]> git.dujemihanovic.xyz Git - linux.git/commitdiff
bcachefs: Rework logged op error handling
authorKent Overstreet <kent.overstreet@linux.dev>
Tue, 24 Sep 2024 02:06:58 +0000 (22:06 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sat, 5 Oct 2024 00:25:32 +0000 (20:25 -0400)
Initially it was thought that we just wanted to ignore errors from
logged op replay, but it turns out we do need to catch -EROFS, or we'll
go into an infinite loop.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/io_misc.c
fs/bcachefs/logged_ops.c
fs/bcachefs/logged_ops.h

index 177ed331c00b1d4a05d5eb523e430732b251dd8d..307ed0a45184497576956c2bf15222f72dc126a4 100644 (file)
@@ -224,13 +224,14 @@ void bch2_logged_op_truncate_to_text(struct printbuf *out, struct bch_fs *c, str
 
 static int truncate_set_isize(struct btree_trans *trans,
                              subvol_inum inum,
-                             u64 new_i_size)
+                             u64 new_i_size,
+                             bool warn)
 {
        struct btree_iter iter = { NULL };
        struct bch_inode_unpacked inode_u;
        int ret;
 
-       ret   = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent) ?:
+       ret   = __bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent, warn) ?:
                (inode_u.bi_size = new_i_size, 0) ?:
                bch2_inode_write(trans, &iter, &inode_u);
 
@@ -247,10 +248,11 @@ static int __bch2_resume_logged_op_truncate(struct btree_trans *trans,
        struct bkey_i_logged_op_truncate *op = bkey_i_to_logged_op_truncate(op_k);
        subvol_inum inum = { le32_to_cpu(op->v.subvol), le64_to_cpu(op->v.inum) };
        u64 new_i_size = le64_to_cpu(op->v.new_i_size);
+       bool warn_errors = i_sectors_delta != NULL;
        int ret;
 
        ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
-                       truncate_set_isize(trans, inum, new_i_size));
+                       truncate_set_isize(trans, inum, new_i_size, i_sectors_delta != NULL));
        if (ret)
                goto err;
 
@@ -263,8 +265,8 @@ static int __bch2_resume_logged_op_truncate(struct btree_trans *trans,
        if (bch2_err_matches(ret, BCH_ERR_transaction_restart))
                ret = 0;
 err:
-       bch2_logged_op_finish(trans, op_k);
-       bch_err_fn(c, ret);
+       if (warn_errors)
+               bch_err_fn(c, ret);
        return ret;
 }
 
@@ -288,9 +290,14 @@ int bch2_truncate(struct bch_fs *c, subvol_inum inum, u64 new_i_size, u64 *i_sec
         * resume only proceeding in one of the snapshots
         */
        down_read(&c->snapshot_create_lock);
-       int ret = bch2_trans_run(c,
-               bch2_logged_op_start(trans, &op.k_i) ?:
-               __bch2_resume_logged_op_truncate(trans, &op.k_i, i_sectors_delta));
+       struct btree_trans *trans = bch2_trans_get(c);
+       int ret = bch2_logged_op_start(trans, &op.k_i);
+       if (ret)
+               goto out;
+       ret = __bch2_resume_logged_op_truncate(trans, &op.k_i, i_sectors_delta);
+       ret = bch2_logged_op_finish(trans, &op.k_i) ?: ret;
+out:
+       bch2_trans_put(trans);
        up_read(&c->snapshot_create_lock);
 
        return ret;
@@ -308,7 +315,8 @@ void bch2_logged_op_finsert_to_text(struct printbuf *out, struct bch_fs *c, stru
        prt_printf(out, " src_offset=%llu",     le64_to_cpu(op.v->src_offset));
 }
 
-static int adjust_i_size(struct btree_trans *trans, subvol_inum inum, u64 offset, s64 len)
+static int adjust_i_size(struct btree_trans *trans, subvol_inum inum,
+                        u64 offset, s64 len, bool warn)
 {
        struct btree_iter iter;
        struct bch_inode_unpacked inode_u;
@@ -317,7 +325,7 @@ static int adjust_i_size(struct btree_trans *trans, subvol_inum inum, u64 offset
        offset  <<= 9;
        len     <<= 9;
 
-       ret = bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent);
+       ret = __bch2_inode_peek(trans, &iter, &inode_u, inum, BTREE_ITER_intent, warn);
        if (ret)
                return ret;
 
@@ -357,12 +365,22 @@ static int __bch2_resume_logged_op_finsert(struct btree_trans *trans,
        u64 len = abs(shift);
        u64 pos = le64_to_cpu(op->v.pos);
        bool insert = shift > 0;
+       u32 snapshot;
+       bool warn_errors = i_sectors_delta != NULL;
        int ret = 0;
 
        ret = bch2_inum_opts_get(trans, inum, &opts);
        if (ret)
                return ret;
 
+       /*
+        * check for missing subvolume before fpunch, as in resume we don't want
+        * it to be a fatal error
+        */
+       ret = __bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot, warn_errors);
+       if (ret)
+               return ret;
+
        bch2_trans_iter_init(trans, &iter, BTREE_ID_extents,
                             POS(inum.inum, 0),
                             BTREE_ITER_intent);
@@ -373,7 +391,7 @@ case LOGGED_OP_FINSERT_start:
 
        if (insert) {
                ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
-                               adjust_i_size(trans, inum, src_offset, len) ?:
+                               adjust_i_size(trans, inum, src_offset, len, warn_errors) ?:
                                bch2_logged_op_update(trans, &op->k_i));
                if (ret)
                        goto err;
@@ -396,11 +414,11 @@ case LOGGED_OP_FINSERT_shift_extents:
                struct bkey_i delete, *copy;
                struct bkey_s_c k;
                struct bpos src_pos = POS(inum.inum, src_offset);
-               u32 snapshot;
 
                bch2_trans_begin(trans);
 
-               ret = bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot);
+               ret = __bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot,
+                                                   warn_errors);
                if (ret)
                        goto btree_err;
 
@@ -463,12 +481,12 @@ btree_err:
 
        if (!insert) {
                ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
-                               adjust_i_size(trans, inum, src_offset, shift) ?:
+                               adjust_i_size(trans, inum, src_offset, shift, warn_errors) ?:
                                bch2_logged_op_update(trans, &op->k_i));
        } else {
                /* We need an inode update to update bi_journal_seq for fsync: */
                ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
-                               adjust_i_size(trans, inum, 0, 0) ?:
+                               adjust_i_size(trans, inum, 0, 0, warn_errors) ?:
                                bch2_logged_op_update(trans, &op->k_i));
        }
 
@@ -477,9 +495,9 @@ case LOGGED_OP_FINSERT_finish:
        break;
        }
 err:
-       bch_err_fn(c, ret);
-       bch2_logged_op_finish(trans, op_k);
        bch2_trans_iter_exit(trans, &iter);
+       if (warn_errors)
+               bch_err_fn(c, ret);
        return ret;
 }
 
@@ -508,9 +526,14 @@ int bch2_fcollapse_finsert(struct bch_fs *c, subvol_inum inum,
         * resume only proceeding in one of the snapshots
         */
        down_read(&c->snapshot_create_lock);
-       int ret = bch2_trans_run(c,
-               bch2_logged_op_start(trans, &op.k_i) ?:
-               __bch2_resume_logged_op_finsert(trans, &op.k_i, i_sectors_delta));
+       struct btree_trans *trans = bch2_trans_get(c);
+       int ret = bch2_logged_op_start(trans, &op.k_i);
+       if (ret)
+               goto out;
+       ret = __bch2_resume_logged_op_finsert(trans, &op.k_i, i_sectors_delta);
+       ret = bch2_logged_op_finish(trans, &op.k_i) ?: ret;
+out:
+       bch2_trans_put(trans);
        up_read(&c->snapshot_create_lock);
 
        return ret;
index 6f4a4e1083c9558cfe811617915e90f535f5cd2e..60e00702d1a46e41dc3cc0b5818fd108b8487ca6 100644 (file)
@@ -34,8 +34,6 @@ static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter,
                            struct bkey_s_c k)
 {
        struct bch_fs *c = trans->c;
-       const struct bch_logged_op_fn *fn = logged_op_fn(k.k->type);
-       struct bkey_buf sk;
        u32 restart_count = trans->restart_count;
        struct printbuf buf = PRINTBUF;
        int ret = 0;
@@ -46,13 +44,15 @@ static int resume_logged_op(struct btree_trans *trans, struct btree_iter *iter,
                    (bch2_bkey_val_to_text(&buf, c, k),
                     buf.buf));
 
-       if (!fn)
-               return 0;
-
+       struct bkey_buf sk;
        bch2_bkey_buf_init(&sk);
        bch2_bkey_buf_reassemble(&sk, c, k);
 
-       fn->resume(trans, sk.k);
+       const struct bch_logged_op_fn *fn = logged_op_fn(sk.k->k.type);
+       if (fn)
+               fn->resume(trans, sk.k);
+
+       ret = bch2_logged_op_finish(trans, sk.k);
 
        bch2_bkey_buf_exit(&sk, c);
 fsck_err:
@@ -93,7 +93,7 @@ int bch2_logged_op_start(struct btree_trans *trans, struct bkey_i *k)
                         __bch2_logged_op_start(trans, k));
 }
 
-void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
+int bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
 {
        int ret = commit_do(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
                            bch2_btree_delete(trans, BTREE_ID_logged_ops, k->k.p, 0));
@@ -113,4 +113,6 @@ void bch2_logged_op_finish(struct btree_trans *trans, struct bkey_i *k)
                                    buf.buf, bch2_err_str(ret));
                printbuf_exit(&buf);
        }
+
+       return ret;
 }
index 4d1e786a27a89fcf733d6cd937662274c885fdcc..30ae9ef737dd95a806d4d92cddf6defb361195fe 100644 (file)
@@ -15,6 +15,6 @@ static inline int bch2_logged_op_update(struct btree_trans *trans, struct bkey_i
 
 int bch2_resume_logged_ops(struct bch_fs *);
 int bch2_logged_op_start(struct btree_trans *, struct bkey_i *);
-void bch2_logged_op_finish(struct btree_trans *, struct bkey_i *);
+int bch2_logged_op_finish(struct btree_trans *, struct bkey_i *);
 
 #endif /* _BCACHEFS_LOGGED_OPS_H */