From: Your Name you@example.com
euleros inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I41P6F CVE: NA DTS: https://code.huawei.com/hulk/hulk/issues/705
--------------------------------
When making bcache devices, we need to wipe the filesystem on the disks and use the first 8KB space to store the bcache superblock info. Therefore it can be used only on new disks. This patch writes 8K size superblock info to a file on the disk through VFS rather than writes to the first 8KB on the disk, thus there's no need to wipe the disks's filesystem. Note that the superblock file should be set immutable to avoid to be changed through VFS. When registering bcache device, we now pass the offset of the superblock file to the kernel, and use the offset to get the superblock info. This patch don't impact the origin methord to make bcache devices. We can also use the origin bcache-tools to make bcache devices.
Signed-off-by: Song Chao chao.song@huawei.com Reviewed-by: Li Ruilin liruilin4@huawei.com --- drivers/md/bcache/super.c | 47 +++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index e2828c762edc..4f1b5463c0ca 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -57,10 +57,33 @@ struct workqueue_struct *bch_journal_wq; /* limitation of bcache devices number on single system */ #define BCACHE_DEVICE_IDX_MAX ((1U << MINORBITS)/BCACHE_MINORS)
+#define WITH_FS_DATA_OFFSET 0 + +int get_sb_offset(char *path, uint64_t *offset) +{ + char *p = path; + + while (*p == ' ') + p++; + while (*p != ' ' && *p != '\0') + p++; + while (*p == ' ') { + *p = '\0'; + p++; + } + + if (strlen(p) == 0) { + *offset = SB_SECTOR; + return 0; + } + + return kstrtoull(p, 10, offset); +} + /* Superblock */
static const char *read_super(struct cache_sb *sb, struct block_device *bdev, - struct cache_sb_disk **res) + struct cache_sb_disk **res, uint64_t sb_offset) { const char *err; struct cache_sb_disk *s; @@ -68,10 +91,10 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, unsigned int i;
page = read_cache_page_gfp(bdev->bd_inode->i_mapping, - SB_OFFSET >> PAGE_SHIFT, GFP_KERNEL); + (sb_offset << SECTOR_SHIFT) >> PAGE_SHIFT, GFP_KERNEL); if (IS_ERR(page)) return "IO error"; - s = page_address(page) + offset_in_page(SB_OFFSET); + s = page_address(page) + offset_in_page(sb_offset << SECTOR_SHIFT);
sb->offset = le64_to_cpu(s->offset); sb->version = le64_to_cpu(s->version); @@ -94,7 +117,7 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, sb->version, sb->flags, sb->seq, sb->keys);
err = "Not a bcache superblock (bad offset)"; - if (sb->offset != SB_SECTOR) + if (sb->offset != sb_offset) goto err;
err = "Not a bcache superblock (bad magic)"; @@ -127,7 +150,11 @@ static const char *read_super(struct cache_sb *sb, struct block_device *bdev, sb->data_offset = le64_to_cpu(s->data_offset);
err = "Bad data offset"; - if (sb->data_offset < BDEV_DATA_START_DEFAULT) + /* if make-bcache with filesystem on the device, + * the data_offset is set to zero. + */ + if ((sb->data_offset < BDEV_DATA_START_DEFAULT) && + sb->data_offset != WITH_FS_DATA_OFFSET) goto err;
break; @@ -212,7 +239,7 @@ static void __write_super(struct cache_sb *sb, struct cache_sb_disk *out, unsigned int i;
bio->bi_opf = REQ_OP_WRITE | REQ_SYNC | REQ_META; - bio->bi_iter.bi_sector = SB_SECTOR; + bio->bi_iter.bi_sector = le64_to_cpu(out->offset); __bio_add_page(bio, virt_to_page(out), SB_SIZE, offset_in_page(out));
@@ -2404,6 +2431,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, struct cache_sb_disk *sb_disk; struct block_device *bdev; ssize_t ret; + uint64_t sb_offset; + int val;
ret = -EBUSY; err = "failed to reference bcache module"; @@ -2426,6 +2455,10 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (!sb) goto out_free_path;
+ val = get_sb_offset(path, &sb_offset); + if (val) + return -EINVAL; + ret = -EINVAL; err = "failed to open device"; bdev = blkdev_get_by_path(strim(path), @@ -2452,7 +2485,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_disk); + err = read_super(sb, bdev, &sb_disk, sb_offset); if (err) goto out_blkdev_put;