diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-02-27 23:00:33 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-04-29 13:44:33 -0400 |
commit | 6266af4314c6c69b0cf97b90704c4e5922e8e47c (patch) | |
tree | 25240560bf7c60f13c7f1c35c5890efd29ebfdfd | |
parent | e1e43d9e34b2012dcd8fba0b1e8484dba674383c (diff) |
verify_extent_has_replicas()
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/data_update.c | 22 | ||||
-rw-r--r-- | fs/bcachefs/extents.c | 36 | ||||
-rw-r--r-- | fs/bcachefs/extents.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/io_write.c | 3 |
4 files changed, 56 insertions, 7 deletions
diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c index 9b44f11fb0d9..106db6264314 100644 --- a/fs/bcachefs/data_update.c +++ b/fs/bcachefs/data_update.c @@ -380,6 +380,15 @@ restart_drop_extra_replicas: printbuf_exit(&buf); } + ret = bch2_verify_extent_has_replicas(trans, insert); + if (ret == -1) { + print_update(m, k, bkey_i_to_s_c(&new->k_i), insert, "durability > 2"); + bch2_fs_inconsistent(c, "durability > 2"); + goto err; + } + if (ret) + goto err; + printbuf_reset(&journal_msg); prt_str(&journal_msg, bch2_data_update_type_strs[m->type]); @@ -397,13 +406,14 @@ restart_drop_extra_replicas: BCH_TRANS_COMMIT_no_check_rw| BCH_TRANS_COMMIT_no_enospc| m->data_opts.btree_insert_flags); - if (!ret) { - bch2_btree_iter_set_pos(trans, &iter, next_pos); + if (ret) + goto err; - this_cpu_add(c->counters[BCH_COUNTER_io_move_finish], new->k.size); - if (trace_io_move_finish_enabled()) - trace_io_move_finish2(m, &new->k_i, insert); - } + bch2_btree_iter_set_pos(&iter, next_pos); + + this_cpu_add(c->counters[BCH_COUNTER_io_move_finish], new->k.size); + if (trace_io_move_finish_enabled()) + trace_io_move_finish2(m, &new->k_i, insert); err: if (bch2_err_matches(ret, BCH_ERR_transaction_restart)) ret = 0; diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index b043b4755701..544387bc516c 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -866,6 +866,42 @@ static unsigned bch2_bkey_durability_safe(struct bch_fs *c, struct bkey_s_c k) return durability; } +int bch2_verify_extent_has_replicas(struct btree_trans *trans, struct bkey_i *e) +{ + struct bch_io_opts opts; + struct bch_inode_unpacked inode; + struct btree_iter iter; + struct bkey_s_c k; + int ret; + + bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes, + SPOS(0, e->k.p.inode, e->k.p.snapshot), + BTREE_ITER_CACHED); + k = bch2_btree_iter_peek_slot(&iter); + ret = bkey_err(k); + if (ret) + goto err; + + BUG_ON(!bkey_is_inode(k.k)); + + ret = bch2_inode_unpack(k, &inode); + BUG_ON(ret); + + bch2_inode_opts_get(&opts, trans->c, &inode); + + if (bch2_bkey_durability(trans->c, bkey_i_to_s_c(e)) != opts.data_replicas) { + struct printbuf buf = PRINTBUF; + + bch2_bkey_val_to_text(&buf, trans->c, bkey_i_to_s_c(e)); + pr_err("%s", buf.buf); + printbuf_exit(&buf); + ret = -1; + } +err: + bch2_trans_iter_exit(trans, &iter); + return ret; +} + void bch2_bkey_extent_entry_drop(struct bkey_i *k, union bch_extent_entry *entry) { union bch_extent_entry *end = bkey_val_end(bkey_i_to_s(k)); diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h index c1ec69b914cd..f0f37ef95b40 100644 --- a/fs/bcachefs/extents.h +++ b/fs/bcachefs/extents.h @@ -622,6 +622,8 @@ unsigned bch2_extent_ptr_desired_durability(struct bch_fs *, struct extent_ptr_d unsigned bch2_extent_ptr_durability(struct bch_fs *, struct extent_ptr_decoded *); unsigned bch2_bkey_durability(struct bch_fs *, struct bkey_s_c); +int bch2_verify_extent_has_replicas(struct btree_trans *, struct bkey_i *); + const struct bch_extent_ptr *bch2_bkey_has_device_c(struct bkey_s_c, unsigned); static inline struct bch_extent_ptr *bch2_bkey_has_device(struct bkey_s k, unsigned dev) diff --git a/fs/bcachefs/io_write.c b/fs/bcachefs/io_write.c index 570759337f03..86428ec0f8cc 100644 --- a/fs/bcachefs/io_write.c +++ b/fs/bcachefs/io_write.c @@ -327,7 +327,8 @@ int bch2_extent_update(struct btree_trans *trans, * aren't changing - for fsync to work properly; fsync relies on * inode->bi_journal_seq which is updated by the trigger code: */ - ret = bch2_extent_update_i_size_sectors(trans, iter, + ret = bch2_verify_extent_has_replicas(trans, k) ?: + bch2_extent_update_i_size_sectors(trans, iter, min(k->k.p.offset << 9, new_i_size), i_sectors_delta) ?: bch2_trans_update(trans, iter, k, 0) ?: |