From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-5.6-rc1 commit a702a692cd7559053ea573f4e2c84828f0e62824 category: feature bugzilla: 43003 CVE: NA ---------------------------
Split out an on-disk version struct cache_sb with the proper endianness annotations. This fixes a fair chunk of sparse warnings, but there are some left due to the way the checksum is defined.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 6 ++--- include/uapi/linux/bcache.h | 51 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 78854837f398..8f8a0a69cc0e 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -63,14 +63,14 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, struct page **res) { const char *err; - struct cache_sb *s; + struct cache_sb_disk *s; struct buffer_head *bh = __bread(bdev, 1, SB_SIZE); unsigned int i;
if (!bh) return "IO error";
- s = (struct cache_sb *) bh->b_data; + s = (struct cache_sb_disk *)bh->b_data;
sb->offset = le64_to_cpu(s->offset); sb->version = le64_to_cpu(s->version); @@ -209,7 +209,7 @@ static void write_bdev_super_endio(struct bio *bio)
static void __write_super(struct cache_sb *sb, struct bio *bio) { - struct cache_sb *out = page_address(bio_first_page_all(bio)); + struct cache_sb_disk *out = page_address(bio_first_page_all(bio)); unsigned int i;
bio->bi_iter.bi_sector = SB_SECTOR; diff --git a/include/uapi/linux/bcache.h b/include/uapi/linux/bcache.h index 5d4f58e059fd..1d8b3a9fc080 100644 --- a/include/uapi/linux/bcache.h +++ b/include/uapi/linux/bcache.h @@ -156,6 +156,57 @@ static inline struct bkey *bkey_idx(const struct bkey *k, unsigned int nr_keys)
#define BDEV_DATA_START_DEFAULT 16 /* sectors */
+struct cache_sb_disk { + __le64 csum; + __le64 offset; /* sector where this sb was written */ + __le64 version; + + __u8 magic[16]; + + __u8 uuid[16]; + union { + __u8 set_uuid[16]; + __le64 set_magic; + }; + __u8 label[SB_LABEL_SIZE]; + + __le64 flags; + __le64 seq; + __le64 pad[8]; + + union { + struct { + /* Cache devices */ + __le64 nbuckets; /* device size */ + + __le16 block_size; /* sectors */ + __le16 bucket_size; /* sectors */ + + __le16 nr_in_set; + __le16 nr_this_dev; + }; + struct { + /* Backing devices */ + __le64 data_offset; + + /* + * block_size from the cache device section is still used by + * backing devices, so don't add anything here until we fix + * things to not need it for backing devices anymore + */ + }; + }; + + __le32 last_mount; /* time overflow in y2106 */ + + __le16 first_bucket; + union { + __le16 njournal_buckets; + __le16 keys; + }; + __le64 d[SB_JOURNAL_BUCKETS]; /* journal buckets */ +}; + struct cache_sb { __u64 csum; __u64 offset; /* sector where this sb was written */
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-5.6-rc1 commit 50246693f81fe887f4db78bf7089051d7f1894cc category: feature bugzilla: 43003 CVE: NA ---------------------------
Split the successful and error return path, and use one goto label for each resource to unwind. This also fixes some small errors like leaking the module reference count in the reboot case (which seems entirely harmless) or printing the wrong warning messages for early failures.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 75 +++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 30 deletions(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 8f8a0a69cc0e..eddc4ec3f7a4 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -2368,29 +2368,33 @@ static bool bch_is_open(struct block_device *bdev) static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, const char *buffer, size_t size) { - ssize_t ret = -EINVAL; - const char *err = "cannot allocate memory"; - char *path = NULL; - struct cache_sb *sb = NULL; + const char *err; + char *path; + struct cache_sb *sb; struct block_device *bdev = NULL; - struct page *sb_page = NULL; + struct page *sb_page; + ssize_t ret;
+ ret = -EBUSY; if (!try_module_get(THIS_MODULE)) - return -EBUSY; + goto out;
/* For latest state of bcache_is_reboot */ smp_mb(); if (bcache_is_reboot) - return -EBUSY; + goto out_module_put;
+ ret = -ENOMEM; + err = "cannot allocate memory"; path = kstrndup(buffer, size, GFP_KERNEL); if (!path) - goto err; + goto out_module_put;
sb = kmalloc(sizeof(struct cache_sb), GFP_KERNEL); if (!sb) - goto err; + goto out_free_path;
+ ret = -EINVAL; err = "failed to open device"; bdev = blkdev_get_by_path(strim(path), FMODE_READ|FMODE_WRITE|FMODE_EXCL, @@ -2407,57 +2411,68 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (!IS_ERR(bdev)) bdput(bdev); if (attr == &ksysfs_register_quiet) - goto quiet_out; + goto done; } - goto err; + goto out_free_sb; }
err = "failed to set blocksize"; if (set_blocksize(bdev, 4096)) - goto err_close; + goto out_blkdev_put;
err = read_super(sb, bdev, &sb_page); if (err) - goto err_close; + goto out_blkdev_put;
err = "failed to register device"; if (SB_IS_BDEV(sb)) { struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
if (!dc) - goto err_close; + goto out_put_sb_page;
mutex_lock(&bch_register_lock); ret = register_bdev(sb, sb_page, bdev, dc); mutex_unlock(&bch_register_lock); /* blkdev_put() will be called in cached_dev_free() */ - if (ret < 0) - goto err; + if (ret < 0) { + bdev = NULL; + goto out_put_sb_page; + } } else { struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL);
if (!ca) - goto err_close; + goto out_put_sb_page;
/* blkdev_put() will be called in bch_cache_release() */ - if (register_cache(sb, sb_page, bdev, ca) != 0) - goto err; + if (register_cache(sb, sb_page, bdev, ca) != 0) { + bdev = NULL; + goto out_put_sb_page; + } } -quiet_out: - ret = size; -out: - if (sb_page) - put_page(sb_page); + + put_page(sb_page); +done: kfree(sb); kfree(path); module_put(THIS_MODULE); - return ret; - -err_close: - blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); -err: + return size; + +out_put_sb_page: + put_page(sb_page); +out_blkdev_put: + if (bdev) + blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); +out_free_sb: + kfree(sb); +out_free_path: + kfree(path); +out_module_put: + module_put(THIS_MODULE); +out: pr_info("error %s: %s", path, err); - goto out; + return ret; }
From: Coly Li colyli@suse.de
mainline inclusion from mainline-5.6-rc1 commit 29cda393bcaad160c4bf3676ddd99855adafc72f category: feature bugzilla: 43003 CVE: NA ---------------------------
Patch "bcache: rework error unwinding in register_bcache" from Christoph Hellwig changes the local variables 'path' and 'err' in undefined initial state. If the code in register_bcache() jumps to label 'out:' or 'out_module_put:' by goto, these two variables might be reference with undefined value by the following line,
out_module_put: module_put(THIS_MODULE); out: pr_info("error %s: %s", path, err); return ret;
Therefore this patch initializes these two local variables properly in register_bcache() to avoid such issue.
Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index eddc4ec3f7a4..a5bbaf0c047a 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -2369,18 +2369,20 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, const char *buffer, size_t size) { const char *err; - char *path; + char *path = NULL; struct cache_sb *sb; struct block_device *bdev = NULL; struct page *sb_page; ssize_t ret;
ret = -EBUSY; + err = "failed to reference bcache module"; if (!try_module_get(THIS_MODULE)) goto out;
/* For latest state of bcache_is_reboot */ smp_mb(); + err = "bcache is in reboot"; if (bcache_is_reboot) goto out_module_put;
From: Coly Li colyli@suse.de
mainline inclusion from mainline-5.6-rc1 commit ae3cd299919af6eb670d5af0bc9d7ba14086bd8e category: feature bugzilla: 43003 CVE: NA ---------------------------
The patch "bcache: rework error unwinding in register_bcache" introduces a use-after-free regression in register_bcache(). Here are current code, 2510 out_free_path: 2511 kfree(path); 2512 out_module_put: 2513 module_put(THIS_MODULE); 2514 out: 2515 pr_info("error %s: %s", path, err); 2516 return ret; If some error happens and the above code path is executed, at line 2511 path is released, but referenced at line 2515. Then KASAN reports a use- after-free error message.
This patch changes line 2515 in the following way to fix the problem, 2515 pr_info("error %s: %s", path?path:"", err);
Signed-off-by: Coly Li colyli@suse.de Cc: Christoph Hellwig hch@lst.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index a5bbaf0c047a..d0c19f9dcbdc 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -2470,10 +2470,11 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, kfree(sb); out_free_path: kfree(path); + path = NULL; out_module_put: module_put(THIS_MODULE); out: - pr_info("error %s: %s", path, err); + pr_info("error %s: %s", path?path:"", err); return ret; }
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-5.6-rc1 commit fc8f19cc5dce183cde4fecb9a1da07d81fa6ea8d category: feature bugzilla: 43003 CVE: NA ---------------------------
Avoid an extra reference count roundtrip by transferring the sb_page ownership to the lower level register helpers.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index d0c19f9dcbdc..ce86fa7c70a6 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1371,8 +1371,6 @@ static int register_bdev(struct cache_sb *sb, struct page *sb_page,
bio_init(&dc->sb_bio, dc->sb_bio.bi_inline_vecs, 1); bio_first_bvec_all(&dc->sb_bio)->bv_page = sb_page; - get_page(sb_page); -
if (cached_dev_init(dc, sb->block_size << 9)) goto err; @@ -2268,7 +2266,6 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
bio_init(&ca->sb_bio, ca->sb_bio.bi_inline_vecs, 1); bio_first_bvec_all(&ca->sb_bio)->bv_page = sb_page; - get_page(sb_page);
if (blk_queue_discard(bdev_get_queue(bdev))) ca->discard = CACHE_DISCARD(&ca->sb); @@ -2371,7 +2368,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, const char *err; char *path = NULL; struct cache_sb *sb; - struct block_device *bdev = NULL; + struct block_device *bdev; struct page *sb_page; ssize_t ret;
@@ -2437,10 +2434,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, ret = register_bdev(sb, sb_page, bdev, dc); mutex_unlock(&bch_register_lock); /* blkdev_put() will be called in cached_dev_free() */ - if (ret < 0) { - bdev = NULL; - goto out_put_sb_page; - } + if (ret < 0) + goto out_free_sb; } else { struct cache *ca = kzalloc(sizeof(*ca), GFP_KERNEL);
@@ -2448,13 +2443,10 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, goto out_put_sb_page;
/* blkdev_put() will be called in bch_cache_release() */ - if (register_cache(sb, sb_page, bdev, ca) != 0) { - bdev = NULL; - goto out_put_sb_page; - } + if (register_cache(sb, sb_page, bdev, ca) != 0) + goto out_free_sb; }
- put_page(sb_page); done: kfree(sb); kfree(path); @@ -2464,8 +2456,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, out_put_sb_page: put_page(sb_page); out_blkdev_put: - if (bdev) - blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); + blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); out_free_sb: kfree(sb); out_free_path:
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-5.6-rc1 commit cfa0c56db9c087227988f6af2c7b9888d24a3b16 category: feature bugzilla: 43003 CVE: NA ---------------------------
Returning the properly typed actual data structure insteaf of the containing struct page will save the callers some work going forward.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index ce86fa7c70a6..43ba87c16617 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -60,7 +60,7 @@ struct workqueue_struct *bch_journal_wq; /* Superblock */
static const char *read_super(struct cache_sb *sb, struct block_device *bdev, - struct page **res) + struct cache_sb_disk **res) { const char *err; struct cache_sb_disk *s; @@ -191,7 +191,7 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, err = NULL;
get_page(bh->b_page); - *res = bh->b_page; + *res = s; err: put_bh(bh); return err; @@ -1356,7 +1356,7 @@ static int cached_dev_init(struct cached_dev *dc, unsigned int block_size)
/* Cached device - bcache superblock */
-static int register_bdev(struct cache_sb *sb, struct page *sb_page, +static int register_bdev(struct cache_sb *sb, struct cache_sb_disk *sb_disk, struct block_device *bdev, struct cached_dev *dc) { @@ -1370,7 +1370,7 @@ static int register_bdev(struct cache_sb *sb, struct page *sb_page, dc->bdev->bd_holder = dc;
bio_init(&dc->sb_bio, dc->sb_bio.bi_inline_vecs, 1); - bio_first_bvec_all(&dc->sb_bio)->bv_page = sb_page; + bio_first_bvec_all(&dc->sb_bio)->bv_page = virt_to_page(sb_disk);
if (cached_dev_init(dc, sb->block_size << 9)) goto err; @@ -2253,7 +2253,7 @@ static int cache_alloc(struct cache *ca) return ret; }
-static int register_cache(struct cache_sb *sb, struct page *sb_page, +static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk, struct block_device *bdev, struct cache *ca) { const char *err = NULL; /* must be set for any error case */ @@ -2265,7 +2265,7 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, ca->bdev->bd_holder = ca;
bio_init(&ca->sb_bio, ca->sb_bio.bi_inline_vecs, 1); - bio_first_bvec_all(&ca->sb_bio)->bv_page = sb_page; + bio_first_bvec_all(&ca->sb_bio)->bv_page = virt_to_page(sb_disk);
if (blk_queue_discard(bdev_get_queue(bdev))) ca->discard = CACHE_DISCARD(&ca->sb); @@ -2368,8 +2368,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, const char *err; char *path = NULL; struct cache_sb *sb; + struct cache_sb_disk *sb_disk; struct block_device *bdev; - struct page *sb_page; ssize_t ret;
ret = -EBUSY; @@ -2419,7 +2419,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (set_blocksize(bdev, 4096)) goto out_blkdev_put;
- err = read_super(sb, bdev, &sb_page); + err = read_super(sb, bdev, &sb_disk); if (err) goto out_blkdev_put;
@@ -2431,7 +2431,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, goto out_put_sb_page;
mutex_lock(&bch_register_lock); - ret = register_bdev(sb, sb_page, bdev, dc); + ret = register_bdev(sb, sb_disk, bdev, dc); mutex_unlock(&bch_register_lock); /* blkdev_put() will be called in cached_dev_free() */ if (ret < 0) @@ -2443,7 +2443,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, goto out_put_sb_page;
/* blkdev_put() will be called in bch_cache_release() */ - if (register_cache(sb, sb_page, bdev, ca) != 0) + if (register_cache(sb, sb_disk, bdev, ca) != 0) goto out_free_sb; }
@@ -2454,7 +2454,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, return size;
out_put_sb_page: - put_page(sb_page); + put_page(virt_to_page(sb_disk)); out_blkdev_put: blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); out_free_sb:
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-5.6-rc1 commit 475389ae5c08656f8bb5cc3adc88a531c7c4877f category: feature bugzilla: 43003 CVE: NA ---------------------------
This allows to properly build the superblock bio including the offset in the page using the normal bio helpers. This fixes writing the superblock for page sizes larger than 4k where the sb write bio would need an offset in the bio_vec.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/bcache.h | 2 ++ drivers/md/bcache/super.c | 34 +++++++++++++++------------------- 2 files changed, 17 insertions(+), 19 deletions(-)
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 6795b3692e87..756fc5425d9b 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -301,6 +301,7 @@ struct cached_dev { struct block_device *bdev;
struct cache_sb sb; + struct cache_sb_disk *sb_disk; struct bio sb_bio; struct bio_vec sb_bv[1]; struct closure sb_write; @@ -406,6 +407,7 @@ enum alloc_reserve { struct cache { struct cache_set *set; struct cache_sb sb; + struct cache_sb_disk *sb_disk; struct bio sb_bio; struct bio_vec sb_bv[1];
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 43ba87c16617..ae857154cf6e 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -207,15 +207,15 @@ static void write_bdev_super_endio(struct bio *bio) closure_put(&dc->sb_write); }
-static void __write_super(struct cache_sb *sb, struct bio *bio) +static void __write_super(struct cache_sb *sb, struct cache_sb_disk *out, + struct bio *bio) { - struct cache_sb_disk *out = page_address(bio_first_page_all(bio)); unsigned int i;
+ bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_META; bio->bi_iter.bi_sector = SB_SECTOR; - bio->bi_iter.bi_size = SB_SIZE; - bio_set_op_attrs(bio, REQ_OP_WRITE, REQ_SYNC|REQ_META); - bch_bio_map(bio, NULL); + __bio_add_page(bio, virt_to_page(out), SB_SIZE, + offset_in_page(out));
out->offset = cpu_to_le64(sb->offset); out->version = cpu_to_le64(sb->version); @@ -257,14 +257,14 @@ void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent) down(&dc->sb_write_mutex); closure_init(cl, parent);
- bio_reset(bio); + bio_init(bio, dc->sb_bv, 1); bio_set_dev(bio, dc->bdev); bio->bi_end_io = write_bdev_super_endio; bio->bi_private = dc;
closure_get(cl); /* I/O request sent to backing device */ - __write_super(&dc->sb, bio); + __write_super(&dc->sb, dc->sb_disk, bio);
closure_return_with_destructor(cl, bch_write_bdev_super_unlock); } @@ -306,13 +306,13 @@ void bcache_write_super(struct cache_set *c)
SET_CACHE_SYNC(&ca->sb, CACHE_SYNC(&c->sb));
- bio_reset(bio); + bio_init(bio, ca->sb_bv, 1); bio_set_dev(bio, ca->bdev); bio->bi_end_io = write_super_endio; bio->bi_private = ca;
closure_get(cl); - __write_super(&ca->sb, bio); + __write_super(&ca->sb, ca->sb_disk, bio); }
closure_return_with_destructor(cl, bcache_write_super_unlock); @@ -1278,8 +1278,8 @@ static void cached_dev_free(struct closure *cl)
mutex_unlock(&bch_register_lock);
- if (dc->sb_bio.bi_inline_vecs[0].bv_page) - put_page(bio_first_page_all(&dc->sb_bio)); + if (dc->sb_disk) + put_page(virt_to_page(dc->sb_disk));
if (!IS_ERR_OR_NULL(dc->bdev)) blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); @@ -1368,9 +1368,7 @@ static int register_bdev(struct cache_sb *sb, struct cache_sb_disk *sb_disk, memcpy(&dc->sb, sb, sizeof(struct cache_sb)); dc->bdev = bdev; dc->bdev->bd_holder = dc; - - bio_init(&dc->sb_bio, dc->sb_bio.bi_inline_vecs, 1); - bio_first_bvec_all(&dc->sb_bio)->bv_page = virt_to_page(sb_disk); + dc->sb_disk = sb_disk;
if (cached_dev_init(dc, sb->block_size << 9)) goto err; @@ -2130,8 +2128,8 @@ void bch_cache_release(struct kobject *kobj) for (i = 0; i < RESERVE_NR; i++) free_fifo(&ca->free[i]);
- if (ca->sb_bio.bi_inline_vecs[0].bv_page) - put_page(bio_first_page_all(&ca->sb_bio)); + if (ca->sb_disk) + put_page(virt_to_page(ca->sb_disk));
if (!IS_ERR_OR_NULL(ca->bdev)) blkdev_put(ca->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); @@ -2263,9 +2261,7 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk, memcpy(&ca->sb, sb, sizeof(struct cache_sb)); ca->bdev = bdev; ca->bdev->bd_holder = ca; - - bio_init(&ca->sb_bio, ca->sb_bio.bi_inline_vecs, 1); - bio_first_bvec_all(&ca->sb_bio)->bv_page = virt_to_page(sb_disk); + ca->sb_disk = sb_disk;
if (blk_queue_discard(bdev_get_queue(bdev))) ca->discard = CACHE_DISCARD(&ca->sb);
From: Christoph Hellwig hch@lst.de
mainline inclusion from mainline-5.6-rc1 commit 6321bef028de43724c47cfa7f9dee69ecb783796 category: feature bugzilla: 43003 CVE: NA ---------------------------
Avoid a pointless dependency on buffer heads in bcache by simply open coding reading a single page. Also add a SB_OFFSET define for the byte offset of the superblock instead of using magic numbers.
Signed-off-by: Christoph Hellwig hch@lst.de Signed-off-by: Coly Li colyli@suse.de Signed-off-by: Jens Axboe axboe@kernel.dk Acked-by: Hanjun Guo guohanjun@huawei.com Reviewed-by: Yufen Yu yuyufen@huawei.com Signed-off-by: zhangyi (F) yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/md/bcache/super.c | 16 +++++++--------- include/uapi/linux/bcache.h | 1 + 2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index ae857154cf6e..94045d72952c 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -15,7 +15,6 @@ #include "writeback.h"
#include <linux/blkdev.h> -#include <linux/buffer_head.h> #include <linux/debugfs.h> #include <linux/genhd.h> #include <linux/idr.h> @@ -64,13 +63,14 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, { const char *err; struct cache_sb_disk *s; - struct buffer_head *bh = __bread(bdev, 1, SB_SIZE); + struct page *page; unsigned int i;
- if (!bh) + page = read_cache_page_gfp(bdev->bd_inode->i_mapping, + SB_OFFSET >> PAGE_SHIFT, GFP_KERNEL); + if (IS_ERR(page)) return "IO error"; - - s = (struct cache_sb_disk *)bh->b_data; + s = page_address(page) + offset_in_page(SB_OFFSET);
sb->offset = le64_to_cpu(s->offset); sb->version = le64_to_cpu(s->version); @@ -188,12 +188,10 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, }
sb->last_mount = (u32)ktime_get_real_seconds(); - err = NULL; - - get_page(bh->b_page); *res = s; + return NULL; err: - put_bh(bh); + put_page(page); return err; }
diff --git a/include/uapi/linux/bcache.h b/include/uapi/linux/bcache.h index 1d8b3a9fc080..9a1965c6c3d0 100644 --- a/include/uapi/linux/bcache.h +++ b/include/uapi/linux/bcache.h @@ -148,6 +148,7 @@ static inline struct bkey *bkey_idx(const struct bkey *k, unsigned int nr_keys) #define BCACHE_SB_MAX_VERSION 4
#define SB_SECTOR 8 +#define SB_OFFSET (SB_SECTOR << SECTOR_SHIFT) #define SB_SIZE 4096 #define SB_LABEL_SIZE 32 #define SB_JOURNAL_BUCKETS 256U