A list of struct journal_replay is allocated when register cache device
and will be freed when journal replay complete. It will cause memory
leaks if some error occurred before journal replay.

Signed-off-by: Guoju Fang <[email protected]>
---
 drivers/md/bcache/super.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
index a697a3a..e4289291 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -1782,6 +1782,7 @@ static void run_cache_set(struct cache_set *c)
        struct cache *ca;
        struct closure cl;
        unsigned int i;
+       LIST_HEAD(journal);
 
        closure_init_stack(&cl);
 
@@ -1790,7 +1791,6 @@ static void run_cache_set(struct cache_set *c)
        set_gc_sectors(c);
 
        if (CACHE_SYNC(&c->sb)) {
-               LIST_HEAD(journal);
                struct bkey *k;
                struct jset *j;
 
@@ -1820,25 +1820,25 @@ static void run_cache_set(struct cache_set *c)
 
                err = "bad btree root";
                if (__bch_btree_ptr_invalid(c, k))
-                       goto err;
+                       goto free_journal;
 
                err = "error reading btree root";
                c->root = bch_btree_node_get(c, NULL, k,
                                             j->btree_level,
                                             true, NULL);
                if (IS_ERR_OR_NULL(c->root))
-                       goto err;
+                       goto free_journal;
 
                list_del_init(&c->root->list);
                rw_unlock(true, c->root);
 
                err = uuid_read(c, j, &cl);
                if (err)
-                       goto err;
+                       goto free_journal;
 
                err = "error in recovery";
                if (bch_btree_check(c))
-                       goto err;
+                       goto free_journal;
 
                bch_journal_mark(c, &journal);
                bch_initial_gc_finish(c);
@@ -1854,7 +1854,7 @@ static void run_cache_set(struct cache_set *c)
                err = "error starting allocator thread";
                for_each_cache(ca, c, i)
                        if (bch_cache_allocator_start(ca))
-                               goto err;
+                               goto free_journal;
 
                /*
                 * First place it's safe to allocate: btree_check() and
@@ -1938,6 +1938,14 @@ static void run_cache_set(struct cache_set *c)
 
        set_bit(CACHE_SET_RUNNING, &c->flags);
        return;
+
+free_journal:
+       while (!list_empty(&journal)) {
+               struct journal_replay *jr = list_first_entry(&journal,
+                           struct journal_replay, list);
+               list_del(&jr->list);
+               kfree(jr);
+       }
 err:
        closure_sync(&cl);
        /* XXX: test this, it's broken */
-- 
1.8.3.1

Reply via email to