diff options
Diffstat (limited to 'libbcachefs/super-io.c')
-rw-r--r-- | libbcachefs/super-io.c | 217 |
1 files changed, 91 insertions, 126 deletions
diff --git a/libbcachefs/super-io.c b/libbcachefs/super-io.c index 21720186..8dce7dc1 100644 --- a/libbcachefs/super-io.c +++ b/libbcachefs/super-io.c @@ -330,9 +330,6 @@ const char *bch2_sb_validate(struct bch_sb_handle *disk_sb) if (!is_power_of_2(BCH_SB_BTREE_NODE_SIZE(sb))) return "Btree node size not a power of two"; - if (BCH_SB_BTREE_NODE_SIZE(sb) > BTREE_NODE_SIZE_MAX) - return "Btree node size too large"; - if (BCH_SB_GC_RESERVE(sb) < 5) return "gc reserve percentage too small"; @@ -383,27 +380,6 @@ const char *bch2_sb_validate(struct bch_sb_handle *disk_sb) /* device open: */ -static const char *bch2_blkdev_open(const char *path, fmode_t mode, - void *holder, struct block_device **ret) -{ - struct block_device *bdev; - - *ret = NULL; - bdev = blkdev_get_by_path(path, mode, holder); - if (bdev == ERR_PTR(-EBUSY)) - return "device busy"; - - if (IS_ERR(bdev)) - return "failed to open device"; - - if (mode & FMODE_WRITE) - bdev_get_queue(bdev)->backing_dev_info->capabilities - |= BDI_CAP_STABLE_WRITES; - - *ret = bdev; - return NULL; -} - static void bch2_sb_update(struct bch_fs *c) { struct bch_sb *src = c->disk_sb; @@ -555,44 +531,55 @@ reread: return NULL; } -const char *bch2_read_super(const char *path, - struct bch_opts opts, - struct bch_sb_handle *ret) +int bch2_read_super(const char *path, struct bch_opts *opts, + struct bch_sb_handle *sb) { - u64 offset = opt_get(opts, sb); + u64 offset = opt_get(*opts, sb); struct bch_sb_layout layout; const char *err; - unsigned i; + __le64 *i; + int ret; - memset(ret, 0, sizeof(*ret)); - ret->mode = FMODE_READ; + memset(sb, 0, sizeof(*sb)); + sb->mode = FMODE_READ; - if (!opt_get(opts, noexcl)) - ret->mode |= FMODE_EXCL; + if (!opt_get(*opts, noexcl)) + sb->mode |= FMODE_EXCL; - if (!opt_get(opts, nochanges)) - ret->mode |= FMODE_WRITE; + if (!opt_get(*opts, nochanges)) + sb->mode |= FMODE_WRITE; - err = bch2_blkdev_open(path, ret->mode, ret, &ret->bdev); - if (err) - return err; + sb->bdev = blkdev_get_by_path(path, sb->mode, sb); + if (IS_ERR(sb->bdev) && + PTR_ERR(sb->bdev) == -EACCES && + opt_get(*opts, read_only)) { + sb->mode &= ~FMODE_WRITE; + + sb->bdev = blkdev_get_by_path(path, sb->mode, sb); + if (!IS_ERR(sb->bdev)) + opt_set(*opts, nochanges, true); + } + + if (IS_ERR(sb->bdev)) + return PTR_ERR(sb->bdev); err = "cannot allocate memory"; - if (__bch2_super_realloc(ret, 0)) + ret = __bch2_super_realloc(sb, 0); + if (ret) goto err; + ret = -EFAULT; err = "dynamic fault"; if (bch2_fs_init_fault("read_super")) goto err; - err = read_one_super(ret, offset); + ret = -EINVAL; + err = read_one_super(sb, offset); if (!err) goto got_super; - if (offset != BCH_SB_SECTOR) { - pr_err("error reading superblock: %s", err); + if (opt_defined(*opts, sb)) goto err; - } pr_err("error reading default superblock: %s", err); @@ -600,53 +587,57 @@ const char *bch2_read_super(const char *path, * Error reading primary superblock - read location of backup * superblocks: */ - bio_reset(ret->bio); - ret->bio->bi_bdev = ret->bdev; - ret->bio->bi_iter.bi_sector = BCH_SB_LAYOUT_SECTOR; - ret->bio->bi_iter.bi_size = sizeof(struct bch_sb_layout); - bio_set_op_attrs(ret->bio, REQ_OP_READ, REQ_SYNC|REQ_META); + bio_reset(sb->bio); + sb->bio->bi_bdev = sb->bdev; + sb->bio->bi_iter.bi_sector = BCH_SB_LAYOUT_SECTOR; + sb->bio->bi_iter.bi_size = sizeof(struct bch_sb_layout); + bio_set_op_attrs(sb->bio, REQ_OP_READ, REQ_SYNC|REQ_META); /* * use sb buffer to read layout, since sb buffer is page aligned but * layout won't be: */ - bch2_bio_map(ret->bio, ret->sb); + bch2_bio_map(sb->bio, sb->sb); err = "IO error"; - if (submit_bio_wait(ret->bio)) + if (submit_bio_wait(sb->bio)) goto err; - memcpy(&layout, ret->sb, sizeof(layout)); + memcpy(&layout, sb->sb, sizeof(layout)); err = validate_sb_layout(&layout); if (err) goto err; - for (i = 0; i < layout.nr_superblocks; i++) { - u64 offset = le64_to_cpu(layout.sb_offset[i]); + for (i = layout.sb_offset; + i < layout.sb_offset + layout.nr_superblocks; i++) { + offset = le64_to_cpu(*i); - if (offset == BCH_SB_SECTOR) + if (offset == opt_get(*opts, sb)) continue; - err = read_one_super(ret, offset); + err = read_one_super(sb, offset); if (!err) goto got_super; } + + ret = -EINVAL; goto err; -got_super: - pr_debug("read sb version %llu, flags %llu, seq %llu, journal size %u", - le64_to_cpu(ret->sb->version), - le64_to_cpu(ret->sb->flags[0]), - le64_to_cpu(ret->sb->seq), - le32_to_cpu(ret->sb->u64s)); +got_super: err = "Superblock block size smaller than device block size"; - if (le16_to_cpu(ret->sb->block_size) << 9 < - bdev_logical_block_size(ret->bdev)) + ret = -EINVAL; + if (le16_to_cpu(sb->sb->block_size) << 9 < + bdev_logical_block_size(sb->bdev)) goto err; - return NULL; + if (sb->mode & FMODE_WRITE) + bdev_get_queue(sb->bdev)->backing_dev_info->capabilities + |= BDI_CAP_STABLE_WRITES; + + return 0; err: - bch2_free_super(ret); - return err; + bch2_free_super(sb); + pr_err("error reading superblock: %s", err); + return ret; } /* write superblock: */ @@ -1108,13 +1099,20 @@ err: return ret; } -static inline int __bch2_check_mark_super(struct bch_fs *c, - struct bch_replicas_cpu_entry search, - unsigned max_dev) +int bch2_check_mark_super(struct bch_fs *c, + enum bch_data_type data_type, + struct bch_devs_list devs) { + struct bch_replicas_cpu_entry search; struct bch_replicas_cpu *r, *gc_r; + unsigned max_dev; bool marked; + if (!devs.nr) + return 0; + + devlist_to_replicas(devs, data_type, &search, &max_dev); + rcu_read_lock(); r = rcu_dereference(c->replicas); gc_r = rcu_dereference(c->replicas_gc); @@ -1126,32 +1124,6 @@ static inline int __bch2_check_mark_super(struct bch_fs *c, : bch2_check_mark_super_slowpath(c, search, max_dev); } -int bch2_check_mark_super(struct bch_fs *c, struct bkey_s_c_extent e, - enum bch_data_type data_type) -{ - struct bch_replicas_cpu_entry search; - unsigned max_dev; - - if (!bkey_to_replicas(e, data_type, &search, &max_dev)) - return 0; - - return __bch2_check_mark_super(c, search, max_dev); -} - -int bch2_check_mark_super_devlist(struct bch_fs *c, - struct bch_devs_list *devs, - enum bch_data_type data_type) -{ - struct bch_replicas_cpu_entry search; - unsigned max_dev; - - if (!devs->nr) - return 0; - - devlist_to_replicas(*devs, data_type, &search, &max_dev); - return __bch2_check_mark_super(c, search, max_dev); -} - int bch2_replicas_gc_end(struct bch_fs *c, int err) { struct bch_replicas_cpu *new_r, *old_r; @@ -1435,12 +1407,19 @@ int bch2_sb_replicas_to_text(struct bch_sb_field_replicas *r, char *buf, size_t /* Query replicas: */ -static bool __bch2_sb_has_replicas(struct bch_fs *c, - struct bch_replicas_cpu_entry search, - unsigned max_dev) +bool bch2_sb_has_replicas(struct bch_fs *c, + enum bch_data_type data_type, + struct bch_devs_list devs) { + struct bch_replicas_cpu_entry search; + unsigned max_dev; bool ret; + if (!devs.nr) + return true; + + devlist_to_replicas(devs, data_type, &search, &max_dev); + rcu_read_lock(); ret = replicas_has_entry(rcu_dereference(c->replicas), search, max_dev); @@ -1449,31 +1428,6 @@ static bool __bch2_sb_has_replicas(struct bch_fs *c, return ret; } -bool bch2_sb_has_replicas(struct bch_fs *c, struct bkey_s_c_extent e, - enum bch_data_type data_type) -{ - struct bch_replicas_cpu_entry search; - unsigned max_dev; - - if (!bkey_to_replicas(e, data_type, &search, &max_dev)) - return true; - - return __bch2_sb_has_replicas(c, search, max_dev); -} - -bool bch2_sb_has_replicas_devlist(struct bch_fs *c, struct bch_devs_list *devs, - enum bch_data_type data_type) -{ - struct bch_replicas_cpu_entry search; - unsigned max_dev; - - if (!devs->nr) - return true; - - devlist_to_replicas(*devs, data_type, &search, &max_dev); - return __bch2_sb_has_replicas(c, search, max_dev); -} - struct replicas_status __bch2_replicas_status(struct bch_fs *c, struct bch_devs_mask online_devs) { @@ -1579,12 +1533,23 @@ unsigned bch2_dev_has_data(struct bch_fs *c, struct bch_dev *ca) goto out; for_each_cpu_replicas_entry(r, e) - if (replicas_test_dev(e, ca->dev_idx)) { + if (replicas_test_dev(e, ca->dev_idx)) ret |= 1 << e->data_type; - break; - } out: rcu_read_unlock(); return ret; } + +/* Quotas: */ + +static const char *bch2_sb_validate_quota(struct bch_sb *sb, + struct bch_sb_field *f) +{ + struct bch_sb_field_quota *q = field_to_type(f, quota); + + if (vstruct_bytes(&q->field) != sizeof(*q)) + return "invalid field quota: wrong size"; + + return NULL; +} |