diff options
Diffstat (limited to 'fs/bcachefs')
-rw-r--r-- | fs/bcachefs/bcachefs.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/btree_gc.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/btree_types.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/data_update.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/error.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/io_read.c | 6 | ||||
-rw-r--r-- | fs/bcachefs/io_write.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/journal_sb.c | 45 | ||||
-rw-r--r-- | fs/bcachefs/journal_sb.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/move.c | 6 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 5 | ||||
-rw-r--r-- | fs/bcachefs/super.c | 17 | ||||
-rw-r--r-- | fs/bcachefs/super.h | 2 |
13 files changed, 85 insertions, 11 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h index 16d08dfb5f19..0ede47f62129 100644 --- a/fs/bcachefs/bcachefs.h +++ b/fs/bcachefs/bcachefs.h @@ -523,6 +523,7 @@ struct discard_in_flight { x(journal_read) \ x(fs_journal_alloc) \ x(fs_resize_on_mount) \ + x(sb_journal_sort) \ x(btree_node_read) \ x(btree_node_read_all_replicas) \ x(btree_node_scrub) \ diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 43f294284d57..2b1b6b7ffdf0 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -720,7 +720,7 @@ static int bch2_gc_btree(struct btree_trans *trans, enum btree_id btree, bool initial) { struct bch_fs *c = trans->c; - unsigned target_depth = btree_node_type_has_triggers(__btree_node_type(0, btree)) ? 0 : 1; + unsigned target_depth = BIT_ULL(btree) & btree_leaf_has_triggers_mask ? 0 : 1; int ret = 0; /* We need to make sure every leaf node is readable before going RW */ diff --git a/fs/bcachefs/btree_types.h b/fs/bcachefs/btree_types.h index e893eb938bb3..31ae24dcab75 100644 --- a/fs/bcachefs/btree_types.h +++ b/fs/bcachefs/btree_types.h @@ -840,6 +840,10 @@ static inline bool btree_node_type_has_triggers(enum btree_node_type type) return BIT_ULL(type) & BTREE_NODE_TYPE_HAS_TRIGGERS; } +/* A mask of btree id bits that have triggers for their leaves */ +__maybe_unused +static const u64 btree_leaf_has_triggers_mask = BTREE_NODE_TYPE_HAS_TRIGGERS >> 1; + static const u64 btree_is_extents_mask = 0 #define x(name, nr, flags, ...) |((!!((flags) & BTREE_IS_extents)) << nr) BCH_BTREE_IDS() diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c index 2c997fddefb3..d0f5a765cd4b 100644 --- a/fs/bcachefs/data_update.c +++ b/fs/bcachefs/data_update.c @@ -657,6 +657,8 @@ void bch2_data_update_to_text(struct printbuf *out, struct data_update *m) prt_str_indented(out, "old key:\t"); bch2_bkey_val_to_text(out, m->op.c, bkey_i_to_s_c(m->k.k)); + + bch2_write_op_to_text(out, &m->op); } void bch2_data_update_inflight_to_text(struct printbuf *out, struct data_update *m) diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c index e33f3166c48a..9e69263eb796 100644 --- a/fs/bcachefs/error.c +++ b/fs/bcachefs/error.c @@ -394,7 +394,7 @@ int bch2_fsck_err_opt(struct bch_fs *c, flags |= fsck_flags_extra[err]; if (test_bit(BCH_FS_in_fsck, &c->flags) || - test_bit(BCH_FS_in_recovery, &c->flags)) { + c->opts.fix_errors != FSCK_FIX_exit) { if (!(flags & (FSCK_CAN_FIX|FSCK_CAN_IGNORE))) return bch_err_throw(c, fsck_repair_unimplemented); diff --git a/fs/bcachefs/io_read.c b/fs/bcachefs/io_read.c index e7d53ab1cf55..bae2e181c9ed 100644 --- a/fs/bcachefs/io_read.c +++ b/fs/bcachefs/io_read.c @@ -1076,8 +1076,10 @@ int __bch2_read_extent(struct btree_trans *trans, struct bch_read_bio *orig, } if ((bch2_bkey_extent_flags(k) & BIT_ULL(BCH_EXTENT_FLAG_poisoned)) && - !orig->data_update) - return bch_err_throw(c, extent_poisoned); + !orig->data_update) { + ret = bch_err_throw(c, extent_poisoned); + goto err; + } retry_pick: ret = bch2_bkey_pick_read_device(c, k, failed, &pick, dev); diff --git a/fs/bcachefs/io_write.c b/fs/bcachefs/io_write.c index 1d83dcc9731e..501ab7fc9f69 100644 --- a/fs/bcachefs/io_write.c +++ b/fs/bcachefs/io_write.c @@ -1754,6 +1754,9 @@ void bch2_write_op_to_text(struct printbuf *out, struct bch_write_op *op) prt_printf(out, "nr_replicas:\t%u\n", op->nr_replicas); prt_printf(out, "nr_replicas_required:\t%u\n", op->nr_replicas_required); + prt_printf(out, "devs_have:\t"); + bch2_devs_list_to_text(out, &op->devs_have); + prt_newline(out); prt_printf(out, "ref:\t%u\n", closure_nr_remaining(&op->cl)); prt_printf(out, "ret\t%s\n", bch2_err_str(op->error)); diff --git a/fs/bcachefs/journal_sb.c b/fs/bcachefs/journal_sb.c index 0cb9b93f13e7..dc0ecedb3a8f 100644 --- a/fs/bcachefs/journal_sb.c +++ b/fs/bcachefs/journal_sb.c @@ -30,7 +30,7 @@ static int bch2_sb_journal_validate(struct bch_sb *sb, struct bch_sb_field *f, if (!nr) return 0; - b = kmalloc_array(nr, sizeof(u64), GFP_KERNEL); + b = kvmalloc_array(nr, sizeof(u64), GFP_KERNEL); if (!b) return -BCH_ERR_ENOMEM_sb_journal_validate; @@ -64,7 +64,7 @@ static int bch2_sb_journal_validate(struct bch_sb *sb, struct bch_sb_field *f, ret = 0; err: - kfree(b); + kvfree(b); return ret; } @@ -113,7 +113,7 @@ static int bch2_sb_journal_v2_validate(struct bch_sb *sb, struct bch_sb_field *f if (!nr) return 0; - b = kmalloc_array(nr, sizeof(*b), GFP_KERNEL); + b = kvmalloc_array(nr, sizeof(*b), GFP_KERNEL); if (!b) return -BCH_ERR_ENOMEM_sb_journal_v2_validate; @@ -165,7 +165,7 @@ static int bch2_sb_journal_v2_validate(struct bch_sb *sb, struct bch_sb_field *f ret = 0; err: - kfree(b); + kvfree(b); return ret; } @@ -230,3 +230,40 @@ int bch2_journal_buckets_to_sb(struct bch_fs *c, struct bch_dev *ca, BUG_ON(dst + 1 != nr_compacted); return 0; } + +static inline bool journal_v2_unsorted(struct bch_sb_field_journal_v2 *j) +{ + unsigned nr = bch2_sb_field_journal_v2_nr_entries(j); + for (unsigned i = 0; i + 1 < nr; i++) + if (le64_to_cpu(j->d[i].start) > le64_to_cpu(j->d[i + 1].start)) + return true; + return false; +} + +int bch2_sb_journal_sort(struct bch_fs *c) +{ + BUG_ON(!c->sb.clean); + BUG_ON(test_bit(BCH_FS_rw, &c->flags)); + + guard(mutex)(&c->sb_lock); + bool write_sb = false; + + for_each_online_member(c, ca, BCH_DEV_READ_REF_sb_journal_sort) { + struct bch_sb_field_journal_v2 *j = bch2_sb_field_get(ca->disk_sb.sb, journal_v2); + if (!j) + continue; + + if ((j && journal_v2_unsorted(j)) || + bch2_sb_field_get(ca->disk_sb.sb, journal)) { + struct journal_device *ja = &ca->journal; + + sort(ja->buckets, ja->nr, sizeof(ja->buckets[0]), u64_cmp, NULL); + bch2_journal_buckets_to_sb(c, ca, ja->buckets, ja->nr); + write_sb = true; + } + } + + return write_sb + ? bch2_write_super(c) + : 0; +} diff --git a/fs/bcachefs/journal_sb.h b/fs/bcachefs/journal_sb.h index ba40a7e8d90a..e0fc40652607 100644 --- a/fs/bcachefs/journal_sb.h +++ b/fs/bcachefs/journal_sb.h @@ -22,3 +22,4 @@ extern const struct bch_sb_field_ops bch_sb_field_ops_journal; extern const struct bch_sb_field_ops bch_sb_field_ops_journal_v2; int bch2_journal_buckets_to_sb(struct bch_fs *, struct bch_dev *, u64 *, unsigned); +int bch2_sb_journal_sort(struct bch_fs *); diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c index 4f41f1f6ec6c..101658cbe95a 100644 --- a/fs/bcachefs/move.c +++ b/fs/bcachefs/move.c @@ -121,6 +121,7 @@ struct moving_io { static void move_free(struct moving_io *io) { struct moving_context *ctxt = io->write.ctxt; + struct bch_fs *c = io->write.op.c; if (io->b) atomic_dec(&io->b->count); @@ -132,8 +133,9 @@ static void move_free(struct moving_io *io) if (!io->write.data_opts.scrub) { bch2_data_update_exit(&io->write); } else { - bch2_bio_free_pages_pool(io->write.op.c, &io->write.op.wbio.bio); + bch2_bio_free_pages_pool(c, &io->write.op.wbio.bio); kfree(io->write.bvecs); + bch2_bkey_buf_exit(&io->write.k, c); } kfree(io); } @@ -427,7 +429,9 @@ int bch2_move_extent(struct moving_context *ctxt, data_opts.scrub ? data_opts.read_dev : -1); return 0; err: + bch2_bkey_buf_exit(&io->write.k, c); kfree(io); + if (bch2_err_matches(ret, EROFS) || bch2_err_matches(ret, BCH_ERR_transaction_restart)) return ret; diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 6319144a440c..278d8a38d23e 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -15,6 +15,7 @@ #include "error.h" #include "journal_io.h" #include "journal_reclaim.h" +#include "journal_sb.h" #include "journal_seq_blacklist.h" #include "logged_ops.h" #include "move.h" @@ -644,6 +645,10 @@ int bch2_fs_recovery(struct bch_fs *c) bch_info(c, "recovering from clean shutdown, journal seq %llu", le64_to_cpu(clean->journal_seq)); + + ret = bch2_sb_journal_sort(c); + if (ret) + goto err; } else { bch_info(c, "recovering from unclean shutdown"); } diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index d640ae188722..7bd12e57e41f 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -277,6 +277,17 @@ struct bch_fs *bch2_uuid_to_fs(__uuid_t uuid) return c; } +void bch2_devs_list_to_text(struct printbuf *out, struct bch_devs_list *d) +{ + prt_char(out, '['); + darray_for_each(*d, i) { + if (i != d->data) + prt_char(out, ' '); + prt_printf(out, "%u", *i); + } + prt_char(out, ']'); +} + /* Filesystem RO/RW: */ /* @@ -461,9 +472,11 @@ static bool __bch2_fs_emergency_read_only2(struct bch_fs *c, struct printbuf *ou bch2_fs_read_only_async(c); wake_up(&bch2_read_only_wait); - if (ret) + if (ret) { prt_printf(out, "emergency read only at seq %llu\n", journal_cur_seq(&c->journal)); + bch2_prt_task_backtrace(out, current, 1, out->atomic ? GFP_ATOMIC : GFP_KERNEL); + } return ret; } @@ -1769,7 +1782,7 @@ static int bch2_dev_alloc(struct bch_fs *c, unsigned dev_idx) static int __bch2_dev_attach_bdev(struct bch_dev *ca, struct bch_sb_handle *sb, struct printbuf *err) { - unsigned ret; + int ret; if (bch2_dev_is_online(ca)) { prt_printf(err, "already have device online in slot %u\n", diff --git a/fs/bcachefs/super.h b/fs/bcachefs/super.h index d13dbf2b8227..351dc5911645 100644 --- a/fs/bcachefs/super.h +++ b/fs/bcachefs/super.h @@ -16,6 +16,8 @@ extern const char * const bch2_dev_write_refs[]; struct bch_fs *bch2_dev_to_fs(dev_t); struct bch_fs *bch2_uuid_to_fs(__uuid_t); +void bch2_devs_list_to_text(struct printbuf *, struct bch_devs_list *); + bool bch2_dev_state_allowed(struct bch_fs *, struct bch_dev *, enum bch_member_state, int, struct printbuf *); |