| From 88f0c29df7e3ff3a9f2dbc1e0bfb10dbf0d709ae Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 24 Jan 2020 01:01:28 +0800 |
| Subject: bcache: rework error unwinding in register_bcache |
| |
| From: Christoph Hellwig <hch@lst.de> |
| |
| [ Upstream commit 50246693f81fe887f4db78bf7089051d7f1894cc ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| 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 b86cf72033401..86f7e09d31516 100644 |
| --- a/drivers/md/bcache/super.c |
| +++ b/drivers/md/bcache/super.c |
| @@ -2372,29 +2372,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, |
| @@ -2411,57 +2415,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; |
| } |
| |
| |
| -- |
| 2.20.1 |
| |