]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/inode.c
Update upstream source from tag 'v1.6.3'
[bcachefs-tools-debian] / libbcachefs / inode.c
index b9d6dbf3a54b26bacc211b3d4779fddc68460af6..a3139bb66f77e280d76e88e0bb61c9f732eccc7c 100644 (file)
@@ -7,6 +7,7 @@
 #include "btree_update.h"
 #include "buckets.h"
 #include "compress.h"
+#include "dirent.h"
 #include "error.h"
 #include "extents.h"
 #include "extent_update.h"
@@ -323,7 +324,7 @@ int bch2_inode_unpack(struct bkey_s_c k,
        return bch2_inode_unpack_slowpath(k, unpacked);
 }
 
-static int bch2_inode_peek_nowarn(struct btree_trans *trans,
+int bch2_inode_peek_nowarn(struct btree_trans *trans,
                    struct btree_iter *iter,
                    struct bch_inode_unpacked *inode,
                    subvol_inum inum, unsigned flags)
@@ -383,6 +384,34 @@ int bch2_inode_write_flags(struct btree_trans *trans,
        return bch2_trans_update(trans, iter, &inode_p->inode.k_i, flags);
 }
 
+int __bch2_fsck_write_inode(struct btree_trans *trans,
+                        struct bch_inode_unpacked *inode,
+                        u32 snapshot)
+{
+       struct bkey_inode_buf *inode_p =
+               bch2_trans_kmalloc(trans, sizeof(*inode_p));
+
+       if (IS_ERR(inode_p))
+               return PTR_ERR(inode_p);
+
+       bch2_inode_pack(inode_p, inode);
+       inode_p->inode.k.p.snapshot = snapshot;
+
+       return bch2_btree_insert_nonextent(trans, BTREE_ID_inodes,
+                               &inode_p->inode.k_i,
+                               BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
+}
+
+int bch2_fsck_write_inode(struct btree_trans *trans,
+                           struct bch_inode_unpacked *inode,
+                           u32 snapshot)
+{
+       int ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
+                           __bch2_fsck_write_inode(trans, inode, snapshot));
+       bch_err_fn(trans->c, ret);
+       return ret;
+}
+
 struct bkey_i *bch2_inode_to_v3(struct btree_trans *trans, struct bkey_i *k)
 {
        struct bch_inode_unpacked u;
@@ -505,22 +534,33 @@ fsck_err:
 static void __bch2_inode_unpacked_to_text(struct printbuf *out,
                                          struct bch_inode_unpacked *inode)
 {
-       prt_printf(out, "mode=%o ", inode->bi_mode);
+       printbuf_indent_add(out, 2);
+       prt_printf(out, "mode=%o", inode->bi_mode);
+       prt_newline(out);
 
        prt_str(out, "flags=");
        prt_bitflags(out, bch2_inode_flag_strs, inode->bi_flags & ((1U << 20) - 1));
        prt_printf(out, " (%x)", inode->bi_flags);
+       prt_newline(out);
+
+       prt_printf(out, "journal_seq=%llu", inode->bi_journal_seq);
+       prt_newline(out);
+
+       prt_printf(out, "bi_size=%llu", inode->bi_size);
+       prt_newline(out);
 
-       prt_printf(out, " journal_seq=%llu bi_size=%llu bi_sectors=%llu bi_version=%llu",
-              inode->bi_journal_seq,
-              inode->bi_size,
-              inode->bi_sectors,
-              inode->bi_version);
+       prt_printf(out, "bi_sectors=%llu", inode->bi_sectors);
+       prt_newline(out);
+
+       prt_newline(out);
+       prt_printf(out, "bi_version=%llu", inode->bi_version);
 
 #define x(_name, _bits)                                                \
-       prt_printf(out, " "#_name "=%llu", (u64) inode->_name);
+       prt_printf(out, #_name "=%llu", (u64) inode->_name);    \
+       prt_newline(out);
        BCH_INODE_FIELDS_v3()
 #undef  x
+       printbuf_indent_sub(out, 2);
 }
 
 void bch2_inode_unpacked_to_text(struct printbuf *out, struct bch_inode_unpacked *inode)
@@ -560,64 +600,47 @@ static inline bool bkey_is_deleted_inode(struct bkey_s_c k)
        return bkey_inode_flags(k) & BCH_INODE_unlinked;
 }
 
-int bch2_trans_mark_inode(struct btree_trans *trans,
-                         enum btree_id btree_id, unsigned level,
-                         struct bkey_s_c old,
-                         struct bkey_i *new,
-                         unsigned flags)
+int bch2_trigger_inode(struct btree_trans *trans,
+                      enum btree_id btree_id, unsigned level,
+                      struct bkey_s_c old,
+                      struct bkey_s new,
+                      unsigned flags)
 {
-       int nr = bkey_is_inode(&new->k) - bkey_is_inode(old.k);
-       bool old_deleted = bkey_is_deleted_inode(old);
-       bool new_deleted = bkey_is_deleted_inode(bkey_i_to_s_c(new));
-
-       if (nr) {
-               int ret = bch2_replicas_deltas_realloc(trans, 0);
-               struct replicas_delta_list *d = trans->fs_usage_deltas;
+       s64 nr = bkey_is_inode(new.k) - bkey_is_inode(old.k);
 
-               if (ret)
-                       return ret;
+       if (flags & BTREE_TRIGGER_TRANSACTIONAL) {
+               if (nr) {
+                       int ret = bch2_replicas_deltas_realloc(trans, 0);
+                       if (ret)
+                               return ret;
 
-               d->nr_inodes += nr;
-       }
+                       trans->fs_usage_deltas->nr_inodes += nr;
+               }
 
-       if (old_deleted != new_deleted) {
-               int ret = bch2_btree_bit_mod(trans, BTREE_ID_deleted_inodes, new->k.p, new_deleted);
-               if (ret)
-                       return ret;
+               bool old_deleted = bkey_is_deleted_inode(old);
+               bool new_deleted = bkey_is_deleted_inode(new.s_c);
+               if (old_deleted != new_deleted) {
+                       int ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_deleted_inodes,
+                                                             new.k->p, new_deleted);
+                       if (ret)
+                               return ret;
+               }
        }
 
-       return 0;
-}
-
-int bch2_mark_inode(struct btree_trans *trans,
-                   enum btree_id btree_id, unsigned level,
-                   struct bkey_s_c old, struct bkey_s_c new,
-                   unsigned flags)
-{
-       struct bch_fs *c = trans->c;
-       struct bch_fs_usage *fs_usage;
-       u64 journal_seq = trans->journal_res.seq;
-
-       if (flags & BTREE_TRIGGER_INSERT) {
-               struct bch_inode_v3 *v = (struct bch_inode_v3 *) new.v;
+       if ((flags & BTREE_TRIGGER_ATOMIC) && (flags & BTREE_TRIGGER_INSERT)) {
+               BUG_ON(!trans->journal_res.seq);
 
-               BUG_ON(!journal_seq);
-               BUG_ON(new.k->type != KEY_TYPE_inode_v3);
-
-               v->bi_journal_seq = cpu_to_le64(journal_seq);
+               bkey_s_to_inode_v3(new).v->bi_journal_seq = cpu_to_le64(trans->journal_res.seq);
        }
 
        if (flags & BTREE_TRIGGER_GC) {
-               percpu_down_read(&c->mark_lock);
-               preempt_disable();
+               struct bch_fs *c = trans->c;
 
-               fs_usage = fs_usage_ptr(c, journal_seq, flags & BTREE_TRIGGER_GC);
-               fs_usage->nr_inodes += bkey_is_inode(new.k);
-               fs_usage->nr_inodes -= bkey_is_inode(old.k);
-
-               preempt_enable();
+               percpu_down_read(&c->mark_lock);
+               this_cpu_add(c->usage_gc->b.nr_inodes, nr);
                percpu_up_read(&c->mark_lock);
        }
+
        return 0;
 }
 
@@ -1093,11 +1116,16 @@ static int may_delete_deleted_inode(struct btree_trans *trans,
        if (ret)
                goto out;
 
-       if (fsck_err_on(S_ISDIR(inode.bi_mode), c,
-                       deleted_inode_is_dir,
-                       "directory %llu:%u in deleted_inodes btree",
-                       pos.offset, pos.snapshot))
-               goto delete;
+       if (S_ISDIR(inode.bi_mode)) {
+               ret = bch2_empty_dir_snapshot(trans, pos.offset, 0, pos.snapshot);
+               if (fsck_err_on(bch2_err_matches(ret, ENOTEMPTY),
+                               c, deleted_inode_is_dir,
+                               "non empty directory %llu:%u in deleted_inodes btree",
+                               pos.offset, pos.snapshot))
+                       goto delete;
+               if (ret)
+                       goto out;
+       }
 
        if (fsck_err_on(!(inode.bi_flags & BCH_INODE_unlinked), c,
                        deleted_inode_not_unlinked,
@@ -1143,58 +1171,55 @@ fsck_err:
        bch2_trans_iter_exit(trans, &inode_iter);
        return ret;
 delete:
-       ret = bch2_btree_bit_mod(trans, BTREE_ID_deleted_inodes, pos, false);
+       ret = bch2_btree_bit_mod_buffered(trans, BTREE_ID_deleted_inodes, pos, false);
        goto out;
 }
 
 int bch2_delete_dead_inodes(struct bch_fs *c)
 {
        struct btree_trans *trans = bch2_trans_get(c);
-       struct btree_iter iter;
-       struct bkey_s_c k;
        bool need_another_pass;
        int ret;
 again:
        need_another_pass = false;
 
-       ret = bch2_btree_write_buffer_flush_sync(trans);
-       if (ret)
-               goto err;
-
        /*
         * Weird transaction restart handling here because on successful delete,
         * bch2_inode_rm_snapshot() will return a nested transaction restart,
         * but we can't retry because the btree write buffer won't have been
         * flushed and we'd spin:
         */
-       for_each_btree_key(trans, iter, BTREE_ID_deleted_inodes, POS_MIN,
-                          BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, ret) {
-               ret = commit_do(trans, NULL, NULL,
-                               BCH_TRANS_COMMIT_no_enospc|
-                               BCH_TRANS_COMMIT_lazy_rw,
-                       may_delete_deleted_inode(trans, &iter, k.k->p, &need_another_pass));
-               if (ret < 0)
-                       break;
-
-               if (ret) {
-                       if (!test_bit(BCH_FS_RW, &c->flags)) {
-                               bch2_trans_unlock(trans);
-                               bch2_fs_lazy_rw(c);
-                       }
-
+       ret = for_each_btree_key_commit(trans, iter, BTREE_ID_deleted_inodes, POS_MIN,
+                                       BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
+                                       NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
+               ret = may_delete_deleted_inode(trans, &iter, k.k->p, &need_another_pass);
+               if (ret > 0) {
                        bch_verbose(c, "deleting unlinked inode %llu:%u", k.k->p.offset, k.k->p.snapshot);
 
                        ret = bch2_inode_rm_snapshot(trans, k.k->p.offset, k.k->p.snapshot);
-                       if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart))
-                               break;
+                       /*
+                        * We don't want to loop here: a transaction restart
+                        * error here means we handled a transaction restart and
+                        * we're actually done, but if we loop we'll retry the
+                        * same key because the write buffer hasn't been flushed
+                        * yet
+                        */
+                       if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) {
+                               ret = 0;
+                               continue;
+                       }
                }
-       }
-       bch2_trans_iter_exit(trans, &iter);
 
-       if (!ret && need_another_pass)
+               ret;
+       }));
+
+       if (!ret && need_another_pass) {
+               ret = bch2_btree_write_buffer_flush_sync(trans);
+               if (ret)
+                       goto err;
                goto again;
+       }
 err:
        bch2_trans_put(trans);
-
        return ret;
 }