diff options
author | Slava Pestov <sp@daterainc.com> | 2014-06-19 15:05:59 -0700 |
---|---|---|
committer | Jiri Slaby <jslaby@suse.cz> | 2014-10-31 12:14:35 +0100 |
commit | 2c30554fdfb22f41d66d6c5f4114147bc60a5fd9 (patch) | |
tree | 10d1a1d66f6ee67ff2aed5b6e7df18318024bf04 /drivers | |
parent | 64521124425139ca5a5420660d2408b4f1c4770a (diff) |
bcache: fix memory corruption in init error path
commit c9a78332b42cbdcdd386a95192a716b67d1711a4 upstream.
If register_cache_set() failed, we would touch ca->set after
it had already been freed. Also, fix an assertion to catch
this.
Change-Id: I748e5f5b223e2d9b2602075dec2f997cced2394d
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/md/bcache/super.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 547c4c57b052..3a2ccf9b624b 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1300,8 +1300,11 @@ static void cache_set_free(struct closure *cl) bch_journal_free(c); for_each_cache(ca, c, i) - if (ca) + if (ca) { + ca->set = NULL; + c->cache[ca->sb.nr_this_dev] = NULL; kobject_put(&ca->kobj); + } free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c))); free_pages((unsigned long) c->sort, ilog2(bucket_pages(c))); @@ -1722,8 +1725,10 @@ void bch_cache_release(struct kobject *kobj) { struct cache *ca = container_of(kobj, struct cache, kobj); - if (ca->set) + if (ca->set) { + BUG_ON(ca->set->cache[ca->sb.nr_this_dev] != ca); ca->set->cache[ca->sb.nr_this_dev] = NULL; + } bch_cache_allocator_exit(ca); @@ -1794,7 +1799,7 @@ err: } static void 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]; const char *err = "cannot allocate memory"; |