diff options
Diffstat (limited to 'libbcachefs/super.c')
-rw-r--r-- | libbcachefs/super.c | 218 |
1 files changed, 119 insertions, 99 deletions
diff --git a/libbcachefs/super.c b/libbcachefs/super.c index 69290d27..29ffba65 100644 --- a/libbcachefs/super.c +++ b/libbcachefs/super.c @@ -29,6 +29,7 @@ #include "move.h" #include "migrate.h" #include "movinggc.h" +#include "quota.h" #include "super.h" #include "super-io.h" #include "sysfs.h" @@ -214,14 +215,15 @@ static void __bch2_fs_read_only(struct bch_fs *c) */ bch2_journal_flush_all_pins(&c->journal); - if (!bch2_journal_error(&c->journal)) - bch2_btree_verify_flushed(c); - for_each_member_device(ca, c, i) bch2_dev_allocator_stop(ca); bch2_fs_journal_stop(&c->journal); + if (!bch2_journal_error(&c->journal) && + !test_bit(BCH_FS_ERROR, &c->flags)) + bch2_btree_verify_flushed(c); + for_each_member_device(ca, c, i) bch2_dev_allocator_remove(c, ca); } @@ -366,6 +368,7 @@ err: static void bch2_fs_free(struct bch_fs *c) { + bch2_fs_quota_exit(c); bch2_fs_fsio_exit(c); bch2_fs_encryption_exit(c); bch2_fs_btree_cache_exit(c); @@ -380,7 +383,7 @@ static void bch2_fs_free(struct bch_fs *c) bioset_exit(&c->bio_write); bioset_exit(&c->bio_read_split); bioset_exit(&c->bio_read); - bioset_exit(&c->btree_read_bio); + bioset_exit(&c->btree_bio); mempool_exit(&c->btree_interior_update_pool); mempool_exit(&c->btree_reserve_pool); mempool_exit(&c->fill_iter); @@ -492,6 +495,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) bch2_fs_allocator_init(c); bch2_fs_tiering_init(c); + bch2_fs_quota_init(c); INIT_LIST_HEAD(&c->list); @@ -561,8 +565,9 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) mempool_init_kmalloc_pool(&c->btree_interior_update_pool, 1, sizeof(struct btree_update)) || mempool_init_kmalloc_pool(&c->fill_iter, 1, iter_size) || - bioset_init(&c->btree_read_bio, 1, - offsetof(struct btree_read_bio, bio), + bioset_init(&c->btree_bio, 1, + max(offsetof(struct btree_read_bio, bio), + offsetof(struct btree_write_bio, wbio.bio)), BIOSET_NEED_BVECS) || bioset_init(&c->bio_read, 1, offsetof(struct bch_read_bio, bio), BIOSET_NEED_BVECS) || @@ -671,13 +676,10 @@ static const char *__bch2_fs_start(struct bch_fs *c) struct bch_dev *ca; LIST_HEAD(journal); struct jset *j; - struct closure cl; time64_t now; unsigned i; int ret = -EINVAL; - closure_init_stack(&cl); - mutex_lock(&c->state_lock); BUG_ON(c->state != BCH_FS_STARTING); @@ -705,14 +707,14 @@ static const char *__bch2_fs_start(struct bch_fs *c) unsigned level; struct bkey_i *k; - err = "missing btree root"; k = bch2_journal_find_btree_root(c, j, i, &level); - if (!k && i < BTREE_ID_ALLOC) - goto err; - if (!k) continue; + err = "invalid btree root pointer"; + if (IS_ERR(k)) + goto err; + err = "error reading btree root"; if (bch2_btree_root_read(c, i, k, level)) { if (i != BTREE_ID_ALLOC) @@ -722,6 +724,10 @@ static const char *__bch2_fs_start(struct bch_fs *c) } } + for (i = 0; i < BTREE_ID_NR; i++) + if (!c->btree_roots[i].b) + bch2_btree_root_alloc(c, i); + err = "error reading allocation information"; ret = bch2_alloc_read(c, &journal); if (ret) @@ -739,14 +745,6 @@ static const char *__bch2_fs_start(struct bch_fs *c) if (c->opts.noreplay) goto recovery_done; - err = "cannot allocate new btree root"; - for (i = 0; i < BTREE_ID_NR; i++) - if (!c->btree_roots[i].b && - bch2_btree_root_alloc(c, i, &cl)) - goto err; - - closure_sync(&cl); - /* * bch2_journal_start() can't happen sooner, or btree_gc_finish() * will give spurious errors about oldest_gen > bucket_gen - @@ -754,12 +752,9 @@ static const char *__bch2_fs_start(struct bch_fs *c) */ bch2_journal_start(c); - err = "error starting allocator thread"; - for_each_rw_member(ca, c, i) - if (bch2_dev_allocator_start(ca)) { - percpu_ref_put(&ca->io_ref); - goto err; - } + err = "error starting allocator"; + if (bch2_fs_allocator_start(c)) + goto err; bch_verbose(c, "starting journal replay:"); err = "journal replay failed"; @@ -777,6 +772,14 @@ static const char *__bch2_fs_start(struct bch_fs *c) if (ret) goto err; bch_verbose(c, "fsck done"); + + if (c->opts.usrquota || c->opts.grpquota) { + bch_verbose(c, "reading quotas:"); + ret = bch2_fs_quota_read(c); + if (ret) + goto err; + bch_verbose(c, "quotas done"); + } } else { struct bch_inode_unpacked inode; struct bkey_inode_buf packed_inode; @@ -784,6 +787,7 @@ static const char *__bch2_fs_start(struct bch_fs *c) bch_notice(c, "initializing new filesystem"); set_bit(BCH_FS_ALLOC_READ_DONE, &c->flags); + set_bit(BCH_FS_BRAND_NEW_FS, &c->flags); ret = bch2_initial_gc(c, &journal); if (ret) @@ -791,15 +795,15 @@ static const char *__bch2_fs_start(struct bch_fs *c) err = "unable to allocate journal buckets"; for_each_rw_member(ca, c, i) - if (bch2_dev_journal_alloc(ca)) { + if (bch2_dev_journal_alloc(c, ca)) { percpu_ref_put(&ca->io_ref); goto err; } - err = "cannot allocate new btree root"; + clear_bit(BCH_FS_BRAND_NEW_FS, &c->flags); + for (i = 0; i < BTREE_ID_NR; i++) - if (bch2_btree_root_alloc(c, i, &cl)) - goto err; + bch2_btree_root_alloc(c, i); /* * journal_res_get() will crash if called before this has @@ -808,15 +812,9 @@ static const char *__bch2_fs_start(struct bch_fs *c) bch2_journal_start(c); bch2_journal_set_replay_done(&c->journal); - err = "error starting allocator thread"; - for_each_rw_member(ca, c, i) - if (bch2_dev_allocator_start(ca)) { - percpu_ref_put(&ca->io_ref); - goto err; - } - - /* Wait for new btree roots to be written: */ - closure_sync(&cl); + err = "error starting allocator"; + if (bch2_fs_allocator_start(c)) + goto err; bch2_inode_init(c, &inode, 0, 0, S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0, NULL); @@ -830,6 +828,12 @@ static const char *__bch2_fs_start(struct bch_fs *c) NULL, NULL, NULL, 0)) goto err; + if (c->opts.usrquota || c->opts.grpquota) { + ret = bch2_fs_quota_read(c); + if (ret) + goto err; + } + err = "error writing first journal entry"; if (bch2_journal_meta(&c->journal)) goto err; @@ -867,8 +871,6 @@ out: return err; err: fsck_err: - closure_sync(&cl); - switch (ret) { case BCH_FSCK_ERRORS_NOT_FIXED: bch_err(c, "filesystem contains errors: please report this to the developers"); @@ -1107,6 +1109,8 @@ static int __bch2_dev_online(struct bch_fs *c, struct bch_sb_handle *sb) struct bch_dev *ca; int ret; + lockdep_assert_held(&c->state_lock); + if (le64_to_cpu(sb->sb->seq) > le64_to_cpu(c->disk_sb->seq)) bch2_sb_to_fs(c, sb->sb); @@ -1153,7 +1157,9 @@ static int __bch2_dev_online(struct bch_fs *c, struct bch_sb_handle *sb) bdevname(ca->disk_sb.bdev, c->name); bdevname(ca->disk_sb.bdev, ca->name); + mutex_lock(&c->sb_lock); bch2_mark_dev_superblock(c, ca, BCH_BUCKET_MARK_MAY_MAKE_UNAVAILABLE); + mutex_unlock(&c->sb_lock); if (ca->mi.state == BCH_MEMBER_STATE_RW) bch2_dev_allocator_add(c, ca); @@ -1430,17 +1436,18 @@ err: /* Add new device to running filesystem: */ int bch2_dev_add(struct bch_fs *c, const char *path) { + struct bch_opts opts = bch2_opts_empty(); struct bch_sb_handle sb; const char *err; struct bch_dev *ca = NULL; struct bch_sb_field_members *mi, *dev_mi; struct bch_member saved_mi; unsigned dev_idx, nr_devices, u64s; - int ret = -EINVAL; + int ret; - err = bch2_read_super(path, bch2_opts_empty(), &sb); - if (err) - return -EINVAL; + ret = bch2_read_super(path, &opts, &sb); + if (ret) + return ret; err = bch2_sb_validate(&sb); if (err) @@ -1479,14 +1486,14 @@ have_slot: sizeof(struct bch_member) * nr_devices) / sizeof(u64); err = "no space in superblock for member info"; - mi = bch2_fs_sb_resize_members(c, u64s); - if (!mi) - goto err_unlock; - dev_mi = bch2_sb_resize_members(&sb, u64s); if (!dev_mi) goto err_unlock; + mi = bch2_fs_sb_resize_members(c, u64s); + if (!mi) + goto err_unlock; + memcpy(dev_mi, mi, u64s * sizeof(u64)); dev_mi->members[dev_idx] = saved_mi; @@ -1499,30 +1506,30 @@ have_slot: c->disk_sb->nr_devices = nr_devices; c->sb.nr_devices = nr_devices; + bch2_write_super(c); + mutex_unlock(&c->sb_lock); + if (bch2_dev_alloc(c, dev_idx)) { err = "cannot allocate memory"; ret = -ENOMEM; - goto err_unlock; + goto err; } if (__bch2_dev_online(c, &sb)) { err = "bch2_dev_online() error"; ret = -ENOMEM; - goto err_unlock; + goto err; } - bch2_write_super(c); - mutex_unlock(&c->sb_lock); - ca = bch_dev_locked(c, dev_idx); if (ca->mi.state == BCH_MEMBER_STATE_RW) { - err = "journal alloc failed"; - if (bch2_dev_journal_alloc(ca)) - goto err; - err = __bch2_dev_read_write(c, ca); if (err) goto err; + + err = "journal alloc failed"; + if (bch2_dev_journal_alloc(c, ca)) + goto err; } mutex_unlock(&c->state_lock); @@ -1540,16 +1547,20 @@ err: /* Hot add existing device to running filesystem: */ int bch2_dev_online(struct bch_fs *c, const char *path) { + struct bch_opts opts = bch2_opts_empty(); struct bch_sb_handle sb = { NULL }; struct bch_dev *ca; unsigned dev_idx; const char *err; + int ret; mutex_lock(&c->state_lock); - err = bch2_read_super(path, bch2_opts_empty(), &sb); - if (err) - goto err; + ret = bch2_read_super(path, &opts, &sb); + if (ret) { + mutex_unlock(&c->state_lock); + return ret; + } dev_idx = sb.sb->dev_idx; @@ -1557,13 +1568,10 @@ int bch2_dev_online(struct bch_fs *c, const char *path) if (err) goto err; - mutex_lock(&c->sb_lock); if (__bch2_dev_online(c, &sb)) { err = "__bch2_dev_online() error"; - mutex_unlock(&c->sb_lock); goto err; } - mutex_unlock(&c->sb_lock); ca = bch_dev_locked(c, dev_idx); if (ca->mi.state == BCH_MEMBER_STATE_RW) { @@ -1585,6 +1593,12 @@ int bch2_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags) { mutex_lock(&c->state_lock); + if (!bch2_dev_is_online(ca)) { + bch_err(ca, "Already offline"); + mutex_unlock(&c->state_lock); + return 0; + } + if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_FAILED, flags)) { bch_err(ca, "Cannot offline required disk"); mutex_unlock(&c->state_lock); @@ -1617,9 +1631,19 @@ int bch2_dev_evacuate(struct bch_fs *c, struct bch_dev *ca) goto err; } + ret = bch2_journal_flush_device(&c->journal, ca->dev_idx); + if (ret) { + bch_err(ca, "Migrate failed: error %i flushing journal", ret); + goto err; + } + data = bch2_dev_has_data(c, ca); if (data) { - bch_err(ca, "Migrate error: data still present (%x)", data); + char buf[100]; + + bch2_scnprint_flag_list(buf, sizeof(buf), + bch2_data_types, data); + bch_err(ca, "Migrate failed, still has data (%s)", buf); ret = -EINVAL; goto err; } @@ -1670,33 +1694,33 @@ err: /* Filesystem open: */ -const char *bch2_fs_open(char * const *devices, unsigned nr_devices, - struct bch_opts opts, struct bch_fs **ret) +struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices, + struct bch_opts opts) { - const char *err; + struct bch_sb_handle *sb = NULL; struct bch_fs *c = NULL; - struct bch_sb_handle *sb; unsigned i, best_sb = 0; + const char *err; + int ret = -ENOMEM; if (!nr_devices) - return "need at least one device"; + return ERR_PTR(-EINVAL); if (!try_module_get(THIS_MODULE)) - return "module unloading"; + return ERR_PTR(-ENODEV); - err = "cannot allocate memory"; sb = kcalloc(nr_devices, sizeof(*sb), GFP_KERNEL); if (!sb) goto err; for (i = 0; i < nr_devices; i++) { - err = bch2_read_super(devices[i], opts, &sb[i]); - if (err) + ret = bch2_read_super(devices[i], &opts, &sb[i]); + if (ret) goto err; err = bch2_sb_validate(&sb[i]); if (err) - goto err; + goto err_print; } for (i = 1; i < nr_devices; i++) @@ -1707,56 +1731,53 @@ const char *bch2_fs_open(char * const *devices, unsigned nr_devices, for (i = 0; i < nr_devices; i++) { err = bch2_dev_in_fs(sb[best_sb].sb, sb[i].sb); if (err) - goto err; + goto err_print; } - err = "cannot allocate memory"; + ret = -ENOMEM; c = bch2_fs_alloc(sb[best_sb].sb, opts); if (!c) goto err; err = "bch2_dev_online() error"; - mutex_lock(&c->sb_lock); + mutex_lock(&c->state_lock); for (i = 0; i < nr_devices; i++) if (__bch2_dev_online(c, &sb[i])) { - mutex_unlock(&c->sb_lock); - goto err; + mutex_unlock(&c->state_lock); + goto err_print; } - mutex_unlock(&c->sb_lock); + mutex_unlock(&c->state_lock); err = "insufficient devices"; if (!bch2_fs_may_start(c)) - goto err; + goto err_print; if (!c->opts.nostart) { err = __bch2_fs_start(c); if (err) - goto err; + goto err_print; } err = bch2_fs_online(c); if (err) - goto err; - - if (ret) - *ret = c; - else - closure_put(&c->cl); + goto err_print; - err = NULL; -out: kfree(sb); module_put(THIS_MODULE); - if (err) - c = NULL; - return err; + return c; +err_print: + pr_err("bch_fs_open err opening %s: %s", + devices[0], err); + ret = -EINVAL; err: if (c) bch2_fs_stop(c); for (i = 0; i < nr_devices; i++) bch2_free_super(&sb[i]); - goto out; + kfree(sb); + module_put(THIS_MODULE); + return ERR_PTR(ret); } static const char *__bch2_fs_open_incremental(struct bch_sb_handle *sb, @@ -1827,9 +1848,8 @@ const char *bch2_fs_open_incremental(const char *path) struct bch_opts opts = bch2_opts_empty(); const char *err; - err = bch2_read_super(path, opts, &sb); - if (err) - return err; + if (bch2_read_super(path, &opts, &sb)) + return "error reading superblock"; err = __bch2_fs_open_incremental(&sb, opts); bch2_free_super(&sb); |