Commit 1ada1606 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Turn c->state_lock into an rwsem

Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 7fffc85b
...@@ -551,8 +551,8 @@ struct bch_fs { ...@@ -551,8 +551,8 @@ struct bch_fs {
struct super_block *vfs_sb; struct super_block *vfs_sb;
char name[40]; char name[40];
/* ro/rw, add/remove devices: */ /* ro/rw, add/remove/resize devices: */
struct mutex state_lock; struct rw_semaphore state_lock;
/* Counts outstanding writes, for clean transition to read-only */ /* Counts outstanding writes, for clean transition to read-only */
struct percpu_ref writes; struct percpu_ref writes;
......
...@@ -800,6 +800,7 @@ int bch2_gc(struct bch_fs *c, struct journal_keys *journal_keys, ...@@ -800,6 +800,7 @@ int bch2_gc(struct bch_fs *c, struct journal_keys *journal_keys,
unsigned i, iter = 0; unsigned i, iter = 0;
int ret; int ret;
lockdep_assert_held(&c->state_lock);
trace_gc_start(c); trace_gc_start(c);
down_write(&c->gc_lock); down_write(&c->gc_lock);
......
...@@ -1967,6 +1967,8 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) ...@@ -1967,6 +1967,8 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
int ret = -ENOMEM; int ret = -ENOMEM;
unsigned i; unsigned i;
lockdep_assert_held(&c->state_lock);
memset(&free, 0, sizeof(free)); memset(&free, 0, sizeof(free));
memset(&free_inc, 0, sizeof(free_inc)); memset(&free_inc, 0, sizeof(free_inc));
memset(&alloc_heap, 0, sizeof(alloc_heap)); memset(&alloc_heap, 0, sizeof(alloc_heap));
...@@ -1993,7 +1995,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) ...@@ -1993,7 +1995,6 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
bch2_copygc_stop(ca); bch2_copygc_stop(ca);
if (resize) { if (resize) {
down_write(&c->gc_lock);
down_write(&ca->bucket_lock); down_write(&ca->bucket_lock);
percpu_down_write(&c->mark_lock); percpu_down_write(&c->mark_lock);
} }
...@@ -2036,10 +2037,8 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) ...@@ -2036,10 +2037,8 @@ int bch2_dev_buckets_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
nbuckets = ca->mi.nbuckets; nbuckets = ca->mi.nbuckets;
if (resize) { if (resize)
up_write(&ca->bucket_lock); up_write(&ca->bucket_lock);
up_write(&c->gc_lock);
}
if (start_copygc && if (start_copygc &&
bch2_copygc_start(c, ca)) bch2_copygc_start(c, ca))
......
...@@ -37,7 +37,7 @@ void bch2_io_error_work(struct work_struct *work) ...@@ -37,7 +37,7 @@ void bch2_io_error_work(struct work_struct *work)
struct bch_fs *c = ca->fs; struct bch_fs *c = ca->fs;
bool dev; bool dev;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
dev = bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_RO, dev = bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_RO,
BCH_FORCE_IF_DEGRADED); BCH_FORCE_IF_DEGRADED);
if (dev if (dev
...@@ -47,7 +47,7 @@ void bch2_io_error_work(struct work_struct *work) ...@@ -47,7 +47,7 @@ void bch2_io_error_work(struct work_struct *work)
bch_err(ca, bch_err(ca,
"too many IO errors, setting %s RO", "too many IO errors, setting %s RO",
dev ? "device" : "filesystem"); dev ? "device" : "filesystem");
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
} }
void bch2_io_error(struct bch_dev *ca) void bch2_io_error(struct bch_dev *ca)
......
...@@ -1342,16 +1342,16 @@ static struct bch_fs *__bch2_open_as_blockdevs(const char *dev_name, char * cons ...@@ -1342,16 +1342,16 @@ static struct bch_fs *__bch2_open_as_blockdevs(const char *dev_name, char * cons
if (IS_ERR(c)) if (IS_ERR(c))
return c; return c;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
if (!test_bit(BCH_FS_STARTED, &c->flags)) { if (!test_bit(BCH_FS_STARTED, &c->flags)) {
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
closure_put(&c->cl); closure_put(&c->cl);
pr_err("err mounting %s: incomplete filesystem", dev_name); pr_err("err mounting %s: incomplete filesystem", dev_name);
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
set_bit(BCH_FS_BDEV_MOUNTED, &c->flags); set_bit(BCH_FS_BDEV_MOUNTED, &c->flags);
return c; return c;
...@@ -1400,7 +1400,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data) ...@@ -1400,7 +1400,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
return ret; return ret;
if (opts.read_only != c->opts.read_only) { if (opts.read_only != c->opts.read_only) {
mutex_lock(&c->state_lock); down_write(&c->state_lock);
if (opts.read_only) { if (opts.read_only) {
bch2_fs_read_only(c); bch2_fs_read_only(c);
...@@ -1410,7 +1410,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data) ...@@ -1410,7 +1410,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
ret = bch2_fs_read_write(c); ret = bch2_fs_read_write(c);
if (ret) { if (ret) {
bch_err(c, "error going rw: %i", ret); bch_err(c, "error going rw: %i", ret);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return -EINVAL; return -EINVAL;
} }
...@@ -1419,7 +1419,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data) ...@@ -1419,7 +1419,7 @@ static int bch2_remount(struct super_block *sb, int *flags, char *data)
c->opts.read_only = opts.read_only; c->opts.read_only = opts.read_only;
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
} }
if (opts.errors >= 0) if (opts.errors >= 0)
......
...@@ -340,9 +340,9 @@ static void bch2_fs_read_only_work(struct work_struct *work) ...@@ -340,9 +340,9 @@ static void bch2_fs_read_only_work(struct work_struct *work)
struct bch_fs *c = struct bch_fs *c =
container_of(work, struct bch_fs, read_only_work); container_of(work, struct bch_fs, read_only_work);
mutex_lock(&c->state_lock); down_write(&c->state_lock);
bch2_fs_read_only(c); bch2_fs_read_only(c);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
} }
static void bch2_fs_read_only_async(struct bch_fs *c) static void bch2_fs_read_only_async(struct bch_fs *c)
...@@ -534,9 +534,9 @@ void bch2_fs_stop(struct bch_fs *c) ...@@ -534,9 +534,9 @@ void bch2_fs_stop(struct bch_fs *c)
cancel_work_sync(&c->journal_seq_blacklist_gc_work); cancel_work_sync(&c->journal_seq_blacklist_gc_work);
mutex_lock(&c->state_lock); down_write(&c->state_lock);
bch2_fs_read_only(c); bch2_fs_read_only(c);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
for_each_member_device(ca, c, i) for_each_member_device(ca, c, i)
if (ca->kobj.state_in_sysfs && if (ca->kobj.state_in_sysfs &&
...@@ -607,7 +607,7 @@ static const char *bch2_fs_online(struct bch_fs *c) ...@@ -607,7 +607,7 @@ static const char *bch2_fs_online(struct bch_fs *c)
bch2_opts_create_sysfs_files(&c->opts_dir)) bch2_opts_create_sysfs_files(&c->opts_dir))
return "error creating sysfs objects"; return "error creating sysfs objects";
mutex_lock(&c->state_lock); down_write(&c->state_lock);
err = "error creating sysfs objects"; err = "error creating sysfs objects";
__for_each_member_device(ca, c, i, NULL) __for_each_member_device(ca, c, i, NULL)
...@@ -617,7 +617,7 @@ static const char *bch2_fs_online(struct bch_fs *c) ...@@ -617,7 +617,7 @@ static const char *bch2_fs_online(struct bch_fs *c)
list_add(&c->list, &bch_fs_list); list_add(&c->list, &bch_fs_list);
err = NULL; err = NULL;
err: err:
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return err; return err;
} }
...@@ -639,7 +639,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts) ...@@ -639,7 +639,7 @@ static struct bch_fs *bch2_fs_alloc(struct bch_sb *sb, struct bch_opts opts)
c->minor = -1; c->minor = -1;
c->disk_sb.fs_sb = true; c->disk_sb.fs_sb = true;
mutex_init(&c->state_lock); init_rwsem(&c->state_lock);
mutex_init(&c->sb_lock); mutex_init(&c->sb_lock);
mutex_init(&c->replicas_gc_lock); mutex_init(&c->replicas_gc_lock);
mutex_init(&c->btree_root_lock); mutex_init(&c->btree_root_lock);
...@@ -832,7 +832,7 @@ int bch2_fs_start(struct bch_fs *c) ...@@ -832,7 +832,7 @@ int bch2_fs_start(struct bch_fs *c)
unsigned i; unsigned i;
int ret = -EINVAL; int ret = -EINVAL;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
BUG_ON(test_bit(BCH_FS_STARTED, &c->flags)); BUG_ON(test_bit(BCH_FS_STARTED, &c->flags));
...@@ -882,7 +882,7 @@ int bch2_fs_start(struct bch_fs *c) ...@@ -882,7 +882,7 @@ int bch2_fs_start(struct bch_fs *c)
print_mount_opts(c); print_mount_opts(c);
ret = 0; ret = 0;
out: out:
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return ret; return ret;
err: err:
switch (ret) { switch (ret) {
...@@ -1376,9 +1376,9 @@ int bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca, ...@@ -1376,9 +1376,9 @@ int bch2_dev_set_state(struct bch_fs *c, struct bch_dev *ca,
{ {
int ret; int ret;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
ret = __bch2_dev_set_state(c, ca, new_state, flags); ret = __bch2_dev_set_state(c, ca, new_state, flags);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return ret; return ret;
} }
...@@ -1391,7 +1391,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags) ...@@ -1391,7 +1391,7 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
unsigned dev_idx = ca->dev_idx, data; unsigned dev_idx = ca->dev_idx, data;
int ret = -EINVAL; int ret = -EINVAL;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
/* /*
* We consume a reference to ca->ref, regardless of whether we succeed * We consume a reference to ca->ref, regardless of whether we succeed
...@@ -1481,13 +1481,13 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags) ...@@ -1481,13 +1481,13 @@ int bch2_dev_remove(struct bch_fs *c, struct bch_dev *ca, int flags)
bch2_write_super(c); bch2_write_super(c);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return 0; return 0;
err: err:
if (ca->mi.state == BCH_MEMBER_STATE_RW && if (ca->mi.state == BCH_MEMBER_STATE_RW &&
!percpu_ref_is_zero(&ca->io_ref)) !percpu_ref_is_zero(&ca->io_ref))
__bch2_dev_read_write(c, ca); __bch2_dev_read_write(c, ca);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return ret; return ret;
} }
...@@ -1563,7 +1563,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path) ...@@ -1563,7 +1563,7 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
dev_usage_clear(ca); dev_usage_clear(ca);
mutex_lock(&c->state_lock); down_write(&c->state_lock);
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
err = "insufficient space in new superblock"; err = "insufficient space in new superblock";
...@@ -1624,12 +1624,12 @@ int bch2_dev_add(struct bch_fs *c, const char *path) ...@@ -1624,12 +1624,12 @@ int bch2_dev_add(struct bch_fs *c, const char *path)
goto err_late; goto err_late;
} }
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return 0; return 0;
err_unlock: err_unlock:
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
err: err:
if (ca) if (ca)
bch2_dev_free(ca); bch2_dev_free(ca);
...@@ -1652,11 +1652,11 @@ int bch2_dev_online(struct bch_fs *c, const char *path) ...@@ -1652,11 +1652,11 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
const char *err; const char *err;
int ret; int ret;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
ret = bch2_read_super(path, &opts, &sb); ret = bch2_read_super(path, &opts, &sb);
if (ret) { if (ret) {
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return ret; return ret;
} }
...@@ -1687,10 +1687,10 @@ int bch2_dev_online(struct bch_fs *c, const char *path) ...@@ -1687,10 +1687,10 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
bch2_write_super(c); bch2_write_super(c);
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return 0; return 0;
err: err:
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
bch2_free_super(&sb); bch2_free_super(&sb);
bch_err(c, "error bringing %s online: %s", path, err); bch_err(c, "error bringing %s online: %s", path, err);
return -EINVAL; return -EINVAL;
...@@ -1698,23 +1698,23 @@ int bch2_dev_online(struct bch_fs *c, const char *path) ...@@ -1698,23 +1698,23 @@ int bch2_dev_online(struct bch_fs *c, const char *path)
int bch2_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags) int bch2_dev_offline(struct bch_fs *c, struct bch_dev *ca, int flags)
{ {
mutex_lock(&c->state_lock); down_write(&c->state_lock);
if (!bch2_dev_is_online(ca)) { if (!bch2_dev_is_online(ca)) {
bch_err(ca, "Already offline"); bch_err(ca, "Already offline");
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return 0; return 0;
} }
if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_FAILED, flags)) { if (!bch2_dev_state_allowed(c, ca, BCH_MEMBER_STATE_FAILED, flags)) {
bch_err(ca, "Cannot offline required disk"); bch_err(ca, "Cannot offline required disk");
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return -EINVAL; return -EINVAL;
} }
__bch2_dev_offline(c, ca); __bch2_dev_offline(c, ca);
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return 0; return 0;
} }
...@@ -1723,7 +1723,7 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) ...@@ -1723,7 +1723,7 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
struct bch_member *mi; struct bch_member *mi;
int ret = 0; int ret = 0;
mutex_lock(&c->state_lock); down_write(&c->state_lock);
if (nbuckets < ca->mi.nbuckets) { if (nbuckets < ca->mi.nbuckets) {
bch_err(ca, "Cannot shrink yet"); bch_err(ca, "Cannot shrink yet");
...@@ -1754,7 +1754,7 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets) ...@@ -1754,7 +1754,7 @@ int bch2_dev_resize(struct bch_fs *c, struct bch_dev *ca, u64 nbuckets)
bch2_recalc_capacity(c); bch2_recalc_capacity(c);
err: err:
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
return ret; return ret;
} }
...@@ -1834,13 +1834,13 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices, ...@@ -1834,13 +1834,13 @@ struct bch_fs *bch2_fs_open(char * const *devices, unsigned nr_devices,
goto err; goto err;
err = "bch2_dev_online() error"; err = "bch2_dev_online() error";
mutex_lock(&c->state_lock); down_write(&c->state_lock);
for (i = 0; i < nr_devices; i++) for (i = 0; i < nr_devices; i++)
if (bch2_dev_attach_bdev(c, &sb[i])) { if (bch2_dev_attach_bdev(c, &sb[i])) {
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
goto err_print; goto err_print;
} }
mutex_unlock(&c->state_lock); up_write(&c->state_lock);
err = "insufficient devices"; err = "insufficient devices";
if (!bch2_fs_may_start(c)) if (!bch2_fs_may_start(c))
......
...@@ -427,7 +427,7 @@ SHOW(bch2_fs) ...@@ -427,7 +427,7 @@ SHOW(bch2_fs)
return 0; return 0;
} }
STORE(__bch2_fs) STORE(bch2_fs)
{ {
struct bch_fs *c = container_of(kobj, struct bch_fs, kobj); struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
...@@ -485,8 +485,11 @@ STORE(__bch2_fs) ...@@ -485,8 +485,11 @@ STORE(__bch2_fs)
if (attr == &sysfs_trigger_btree_coalesce) if (attr == &sysfs_trigger_btree_coalesce)
bch2_coalesce(c); bch2_coalesce(c);
if (attr == &sysfs_trigger_gc) if (attr == &sysfs_trigger_gc) {
down_read(&c->state_lock);
bch2_gc(c, NULL, false, false); bch2_gc(c, NULL, false, false);
up_read(&c->state_lock);
}
if (attr == &sysfs_trigger_alloc_write) { if (attr == &sysfs_trigger_alloc_write) {
bool wrote; bool wrote;
...@@ -501,6 +504,7 @@ STORE(__bch2_fs) ...@@ -501,6 +504,7 @@ STORE(__bch2_fs)
sc.nr_to_scan = strtoul_or_return(buf); sc.nr_to_scan = strtoul_or_return(buf);
c->btree_cache.shrink.scan_objects(&c->btree_cache.shrink, &sc); c->btree_cache.shrink.scan_objects(&c->btree_cache.shrink, &sc);
} }
#ifdef CONFIG_BCACHEFS_TESTS #ifdef CONFIG_BCACHEFS_TESTS
if (attr == &sysfs_perf_test) { if (attr == &sysfs_perf_test) {
char *tmp = kstrdup(buf, GFP_KERNEL), *p = tmp; char *tmp = kstrdup(buf, GFP_KERNEL), *p = tmp;
...@@ -522,17 +526,6 @@ STORE(__bch2_fs) ...@@ -522,17 +526,6 @@ STORE(__bch2_fs)
#endif #endif
return size; return size;
} }
STORE(bch2_fs)
{
struct bch_fs *c = container_of(kobj, struct bch_fs, kobj);
mutex_lock(&c->state_lock);
size = __bch2_fs_store(kobj, attr, buf, size);
mutex_unlock(&c->state_lock);
return size;
}
SYSFS_OPS(bch2_fs); SYSFS_OPS(bch2_fs);
struct attribute *bch2_fs_files[] = { struct attribute *bch2_fs_files[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment