summaryrefslogtreecommitdiff
path: root/libbcache/super-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbcache/super-io.c')
-rw-r--r--libbcache/super-io.c190
1 files changed, 69 insertions, 121 deletions
diff --git a/libbcache/super-io.c b/libbcache/super-io.c
index 3a53b7ea..67c03e19 100644
--- a/libbcache/super-io.c
+++ b/libbcache/super-io.c
@@ -91,7 +91,7 @@ static int bch_sb_realloc(struct bcache_superblock *sb, unsigned u64s)
return __bch_super_realloc(sb, get_order(new_bytes));
}
-static int bch_fs_sb_realloc(struct cache_set *c, unsigned u64s)
+static int bch_fs_sb_realloc(struct bch_fs *c, unsigned u64s)
{
u64 bytes = __vstruct_bytes(struct bch_sb, u64s);
struct bch_sb *sb;
@@ -159,14 +159,14 @@ struct bch_sb_field *bch_sb_field_resize(struct bcache_superblock *sb,
return f;
}
-struct bch_sb_field *bch_fs_sb_field_resize(struct cache_set *c,
+struct bch_sb_field *bch_fs_sb_field_resize(struct bch_fs *c,
enum bch_sb_field_type type,
unsigned u64s)
{
struct bch_sb_field *f = bch_sb_field_get(c->disk_sb, type);
ssize_t old_u64s = f ? le32_to_cpu(f->u64s) : 0;
ssize_t d = -old_u64s + u64s;
- struct cache *ca;
+ struct bch_dev *ca;
unsigned i;
lockdep_assert_held(&c->sb_lock);
@@ -174,7 +174,9 @@ struct bch_sb_field *bch_fs_sb_field_resize(struct cache_set *c,
if (bch_fs_sb_realloc(c, le32_to_cpu(c->disk_sb->u64s) + d))
return NULL;
- for_each_cache(ca, c, i) {
+ /* XXX: we're not checking that offline device have enough space */
+
+ for_each_online_member(ca, c, i) {
struct bcache_superblock *sb = &ca->disk_sb;
if (bch_sb_realloc(sb, le32_to_cpu(sb->sb->u64s) + d)) {
@@ -228,7 +230,7 @@ static int u64_cmp(const void *_l, const void *_r)
}
const char *bch_validate_journal_layout(struct bch_sb *sb,
- struct cache_member_cpu mi)
+ struct bch_member_cpu mi)
{
struct bch_sb_field_journal *journal;
const char *err;
@@ -276,12 +278,37 @@ err:
return err;
}
+static const char *bch_sb_validate_members(struct bch_sb *sb)
+{
+ struct bch_sb_field_members *mi;
+ unsigned i;
+
+ mi = bch_sb_get_members(sb);
+ if (!mi)
+ return "Invalid superblock: member info area missing";
+
+ if ((void *) (mi->members + sb->nr_devices) >
+ vstruct_end(&mi->field))
+ return "Invalid superblock: bad member info";
+
+ for (i = 0; i < sb->nr_devices; i++) {
+ if (bch_is_zero(mi->members[i].uuid.b, sizeof(uuid_le)))
+ continue;
+
+ if (le16_to_cpu(mi->members[i].bucket_size) <
+ BCH_SB_BTREE_NODE_SIZE(sb))
+ return "bucket size smaller than btree node size";
+ }
+
+ return NULL;
+}
+
const char *bch_validate_cache_super(struct bcache_superblock *disk_sb)
{
struct bch_sb *sb = disk_sb->sb;
struct bch_sb_field *f;
struct bch_sb_field_members *sb_mi;
- struct cache_member_cpu mi;
+ struct bch_member_cpu mi;
const char *err;
u16 block_size;
@@ -378,16 +405,12 @@ const char *bch_validate_cache_super(struct bcache_superblock *disk_sb)
return "Invalid superblock: unknown optional field type";
}
- /* Validate member info: */
- sb_mi = bch_sb_get_members(sb);
- if (!sb_mi)
- return "Invalid superblock: member info area missing";
-
- if ((void *) (sb_mi->members + sb->nr_devices) >
- vstruct_end(&sb_mi->field))
- return "Invalid superblock: bad member info";
+ err = bch_sb_validate_members(sb);
+ if (err)
+ return err;
- mi = cache_mi_to_cpu_mi(sb_mi->members + sb->dev_idx);
+ sb_mi = bch_sb_get_members(sb);
+ mi = bch_mi_to_cpu(sb_mi->members + sb->dev_idx);
if (mi.nbuckets > LONG_MAX)
return "Too many buckets";
@@ -413,104 +436,33 @@ const char *bch_validate_cache_super(struct bcache_superblock *disk_sb)
/* device open: */
-static bool bch_is_open_cache(struct block_device *bdev)
-{
- struct cache_set *c;
- struct cache *ca;
- unsigned i;
-
- rcu_read_lock();
- list_for_each_entry(c, &bch_fs_list, list)
- for_each_cache_rcu(ca, c, i)
- if (ca->disk_sb.bdev == bdev) {
- rcu_read_unlock();
- return true;
- }
- rcu_read_unlock();
- return false;
-}
-
-static bool bch_is_open(struct block_device *bdev)
-{
- bool ret;
-
- mutex_lock(&bch_register_lock);
- ret = bch_is_open_cache(bdev) || bch_is_open_backing_dev(bdev);
- mutex_unlock(&bch_register_lock);
-
- return ret;
-}
-
static const char *bch_blkdev_open(const char *path, fmode_t mode,
void *holder, struct block_device **ret)
{
struct block_device *bdev;
- const char *err;
*ret = NULL;
bdev = blkdev_get_by_path(path, mode, holder);
-
- if (bdev == ERR_PTR(-EBUSY)) {
- bdev = lookup_bdev(path);
- if (IS_ERR(bdev))
- return "device busy";
-
- err = bch_is_open(bdev)
- ? "device already registered"
- : "device busy";
-
- bdput(bdev);
- return err;
- }
+ if (bdev == ERR_PTR(-EBUSY))
+ return "device busy";
if (IS_ERR(bdev))
return "failed to open device";
- bdev_get_queue(bdev)->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES;
+ if (mode & FMODE_WRITE)
+ bdev_get_queue(bdev)->backing_dev_info.capabilities
+ |= BDI_CAP_STABLE_WRITES;
*ret = bdev;
return NULL;
}
-/* Update cached mi: */
-int bch_fs_mi_update(struct cache_set *c, struct bch_member *mi,
- unsigned nr_devices)
-{
- struct cache_member_rcu *new, *old;
- struct cache *ca;
- unsigned i;
-
- lockdep_assert_held(&c->sb_lock);
-
- new = kzalloc(sizeof(struct cache_member_rcu) +
- sizeof(struct cache_member_cpu) * nr_devices,
- GFP_KERNEL);
- if (!new)
- return -ENOMEM;
-
- new->nr_devices = nr_devices;
-
- for (i = 0; i < nr_devices; i++)
- new->m[i] = cache_mi_to_cpu_mi(&mi[i]);
-
- rcu_read_lock();
- for_each_cache(ca, c, i)
- ca->mi = new->m[i];
- rcu_read_unlock();
-
- old = rcu_dereference_protected(c->members,
- lockdep_is_held(&c->sb_lock));
-
- rcu_assign_pointer(c->members, new);
- if (old)
- kfree_rcu(old, rcu);
-
- return 0;
-}
-
-static void bch_sb_update(struct cache_set *c)
+static void bch_sb_update(struct bch_fs *c)
{
struct bch_sb *src = c->disk_sb;
+ struct bch_sb_field_members *mi = bch_sb_get_members(src);
+ struct bch_dev *ca;
+ unsigned i;
lockdep_assert_held(&c->sb_lock);
@@ -527,6 +479,9 @@ static void bch_sb_update(struct cache_set *c)
c->sb.time_base_lo = le64_to_cpu(src->time_base_lo);
c->sb.time_base_hi = le32_to_cpu(src->time_base_hi);
c->sb.time_precision = le32_to_cpu(src->time_precision);
+
+ for_each_member_device(ca, c, i)
+ ca->mi = bch_mi_to_cpu(mi->members + i);
}
/* doesn't copy member info */
@@ -563,10 +518,8 @@ static void __copy_super(struct bch_sb *dst, struct bch_sb *src)
}
}
-int bch_sb_to_cache_set(struct cache_set *c, struct bch_sb *src)
+int bch_sb_to_fs(struct bch_fs *c, struct bch_sb *src)
{
- struct bch_sb_field_members *members =
- bch_sb_get_members(src);
struct bch_sb_field_journal *journal_buckets =
bch_sb_get_journal(src);
unsigned journal_u64s = journal_buckets
@@ -578,16 +531,13 @@ int bch_sb_to_cache_set(struct cache_set *c, struct bch_sb *src)
if (bch_fs_sb_realloc(c, le32_to_cpu(src->u64s) - journal_u64s))
return -ENOMEM;
- if (bch_fs_mi_update(c, members->members, src->nr_devices))
- return -ENOMEM;
-
__copy_super(c->disk_sb, src);
bch_sb_update(c);
return 0;
}
-int bch_sb_from_cache_set(struct cache_set *c, struct cache *ca)
+int bch_sb_from_fs(struct bch_fs *c, struct bch_dev *ca)
{
struct bch_sb *src = c->disk_sb, *dst = ca->disk_sb.sb;
struct bch_sb_field_journal *journal_buckets =
@@ -754,7 +704,7 @@ err:
static void write_super_endio(struct bio *bio)
{
- struct cache *ca = bio->bi_private;
+ struct bch_dev *ca = bio->bi_private;
/* XXX: return errors directly */
@@ -762,11 +712,11 @@ static void write_super_endio(struct bio *bio)
bch_account_io_completion(ca);
- closure_put(&ca->set->sb_write);
- percpu_ref_put(&ca->ref);
+ closure_put(&ca->fs->sb_write);
+ percpu_ref_put(&ca->io_ref);
}
-static bool write_one_super(struct cache_set *c, struct cache *ca, unsigned idx)
+static bool write_one_super(struct bch_fs *c, struct bch_dev *ca, unsigned idx)
{
struct bch_sb *sb = ca->disk_sb.sb;
struct bio *bio = ca->disk_sb.bio;
@@ -774,6 +724,9 @@ static bool write_one_super(struct cache_set *c, struct cache *ca, unsigned idx)
if (idx >= sb->layout.nr_superblocks)
return false;
+ if (!percpu_ref_tryget(&ca->io_ref))
+ return false;
+
sb->offset = sb->layout.sb_offset[idx];
SET_BCH_SB_CSUM_TYPE(sb, c->opts.metadata_checksum);
@@ -791,49 +744,44 @@ static bool write_one_super(struct cache_set *c, struct cache *ca, unsigned idx)
bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_SYNC|REQ_META);
bch_bio_map(bio, sb);
- percpu_ref_get(&ca->ref);
closure_bio_submit_punt(bio, &c->sb_write, c);
-
return true;
}
-void bch_write_super(struct cache_set *c)
+void bch_write_super(struct bch_fs *c)
{
- struct bch_sb_field_members *members =
- bch_sb_get_members(c->disk_sb);
struct closure *cl = &c->sb_write;
- struct cache *ca;
+ struct bch_dev *ca;
unsigned i, super_idx = 0;
bool wrote;
lockdep_assert_held(&c->sb_lock);
- if (c->opts.nochanges)
- return;
-
closure_init_stack(cl);
le64_add_cpu(&c->disk_sb->seq, 1);
- for_each_cache(ca, c, i)
- bch_sb_from_cache_set(c, ca);
+ for_each_online_member(ca, c, i)
+ bch_sb_from_fs(c, ca);
+
+ if (c->opts.nochanges)
+ goto out;
do {
wrote = false;
- for_each_cache(ca, c, i)
+ for_each_online_member(ca, c, i)
if (write_one_super(c, ca, super_idx))
wrote = true;
closure_sync(cl);
super_idx++;
} while (wrote);
-
+out:
/* Make new options visible after they're persistent: */
- bch_fs_mi_update(c, members->members, c->sb.nr_devices);
bch_sb_update(c);
}
-void bch_check_mark_super_slowpath(struct cache_set *c, const struct bkey_i *k,
+void bch_check_mark_super_slowpath(struct bch_fs *c, const struct bkey_i *k,
bool meta)
{
struct bch_member *mi;