Commit 9b299728 authored by Eric Wheeler's avatar Eric Wheeler Committed by Jens Axboe

bcache: cleaned up error handling around register_cache()

Fix null pointer dereference by changing register_cache() to return an int
instead of being void.  This allows it to return -ENOMEM or -ENODEV and
enables upper layers to handle the OOM case without NULL pointer issues.

See this thread:
  http://thread.gmane.org/gmane.linux.kernel.bcache.devel/3521

Fixes this error:
  gargamel:/sys/block/md5/bcache# echo /dev/sdh2 > /sys/fs/bcache/register

  bcache: register_cache() error opening sdh2: cannot allocate memory
  BUG: unable to handle kernel NULL pointer dereference at 00000000000009b8
  IP: [<ffffffffc05a7e8d>] cache_set_flush+0x102/0x15c [bcache]
  PGD 120dff067 PUD 1119a3067 PMD 0
  Oops: 0000 [#1] SMP
  Modules linked in: veth ip6table_filter ip6_tables
  (...)
  CPU: 4 PID: 3371 Comm: kworker/4:3 Not tainted 4.4.2-amd64-i915-volpreempt-20160213bc1 #3
  Hardware name: System manufacturer System Product Name/P8H67-M PRO, BIOS 3904 04/27/2013
  Workqueue: events cache_set_flush [bcache]
  task: ffff88020d5dc280 ti: ffff88020b6f8000 task.ti: ffff88020b6f8000
  RIP: 0010:[<ffffffffc05a7e8d>]  [<ffffffffc05a7e8d>] cache_set_flush+0x102/0x15c [bcache]
Signed-off-by: default avatarEric Wheeler <bcache@linux.ewheeler.net>
Tested-by: default avatarMarc MERLIN <marc@merlins.org>
Cc: <stable@vger.kernel.org>
parent 07cc6ef8
...@@ -1835,11 +1835,12 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca) ...@@ -1835,11 +1835,12 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
return 0; return 0;
} }
static void register_cache(struct cache_sb *sb, struct page *sb_page, static int register_cache(struct cache_sb *sb, struct page *sb_page,
struct block_device *bdev, struct cache *ca) struct block_device *bdev, struct cache *ca)
{ {
char name[BDEVNAME_SIZE]; char name[BDEVNAME_SIZE];
const char *err = "cannot allocate memory"; const char *err = NULL;
int ret = 0;
memcpy(&ca->sb, sb, sizeof(struct cache_sb)); memcpy(&ca->sb, sb, sizeof(struct cache_sb));
ca->bdev = bdev; ca->bdev = bdev;
...@@ -1854,27 +1855,35 @@ static void register_cache(struct cache_sb *sb, struct page *sb_page, ...@@ -1854,27 +1855,35 @@ static void register_cache(struct cache_sb *sb, struct page *sb_page,
if (blk_queue_discard(bdev_get_queue(ca->bdev))) if (blk_queue_discard(bdev_get_queue(ca->bdev)))
ca->discard = CACHE_DISCARD(&ca->sb); ca->discard = CACHE_DISCARD(&ca->sb);
if (cache_alloc(sb, ca) != 0) ret = cache_alloc(sb, ca);
if (ret != 0)
goto err; goto err;
err = "error creating kobject"; if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) {
if (kobject_add(&ca->kobj, &part_to_dev(bdev->bd_part)->kobj, "bcache")) err = "error calling kobject_add";
goto err; ret = -ENOMEM;
goto out;
}
mutex_lock(&bch_register_lock); mutex_lock(&bch_register_lock);
err = register_cache_set(ca); err = register_cache_set(ca);
mutex_unlock(&bch_register_lock); mutex_unlock(&bch_register_lock);
if (err) if (err) {
goto err; ret = -ENODEV;
goto out;
}
pr_info("registered cache device %s", bdevname(bdev, name)); pr_info("registered cache device %s", bdevname(bdev, name));
out: out:
kobject_put(&ca->kobj); kobject_put(&ca->kobj);
return;
err: err:
if (err)
pr_notice("error opening %s: %s", bdevname(bdev, name), err); pr_notice("error opening %s: %s", bdevname(bdev, name), err);
goto out;
return ret;
} }
/* Global interfaces/init */ /* Global interfaces/init */
...@@ -1972,7 +1981,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, ...@@ -1972,7 +1981,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
if (!ca) if (!ca)
goto err_close; goto err_close;
register_cache(sb, sb_page, bdev, ca); if (register_cache(sb, sb_page, bdev, ca) != 0)
goto err_close;
} }
out: out:
if (sb_page) if (sb_page)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment