Re: [PATCH] bcache: avoid potential memleak of list of journal_replay(s) in the CACHE_SYNC branch of run_cache_set

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 2019/1/28 6:18 下午, Shenghui Wang wrote:
> In the CACHE_SYNC branch of run_cache_set(), LIST_HEAD(journal) is used
> to collect journal_replay(s) and filled by bch_journal_read().
> 
> If all goes well, bch_journal_replay() will release the list of
> jounal_replay(s) at the end of the branch.
> 
> If something goes wrong, code flow will jump to the label "err:" and leave
> the list unreleased.
> 
> This patch will release the list of journal_replay(s) in the case of
> error detected.
> 
> Signed-off-by: Shenghui Wang <shhuiw@xxxxxxxxxxx>

Hi Shenghui,

Nice catch. In general I am good with this patch. There is some minor
suggestions I add them in line.

> ---
>  drivers/md/bcache/super.c | 30 +++++++++++++++++++++++-------
>  1 file changed, 23 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c
> index 4dee119c3664..f738a1d3b864 100644
> --- a/drivers/md/bcache/super.c
> +++ b/drivers/md/bcache/super.c
> @@ -1791,18 +1791,19 @@ static void run_cache_set(struct cache_set *c)
>  
>  	if (CACHE_SYNC(&c->sb)) {
>  		LIST_HEAD(journal);
> +		struct journal_replay *l;
>  		struct bkey *k;
>  		struct jset *j;
>  
>  		err = "cannot allocate memory for journal";
>  		if (bch_journal_read(c, &journal))
> -			goto err;
> +			goto no_replay;
>  
>  		pr_debug("btree_journal_read() done");
>  
>  		err = "no journal entries found";
>  		if (list_empty(&journal))
> -			goto err;
> +			goto no_replay;
>  

journal list is checked as empty here, after go to no_replay, it will be
re-checked again, this is a little bit redundant.


>  		j = &list_entry(journal.prev, struct journal_replay, list)->j;
>  
> @@ -1820,25 +1821,25 @@ static void run_cache_set(struct cache_set *c)
>  
>  		err = "bad btree root";
>  		if (__bch_btree_ptr_invalid(c, k))
> -			goto err;
> +			goto no_replay;
>  
>  		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 no_replay;
>  
>  		list_del_init(&c->root->list);
>  		rw_unlock(true, c->root);
>  
>  		err = uuid_read(c, j, &cl);
>  		if (err)
> -			goto err;
> +			goto no_replay;
>  
>  		err = "error in recovery";
>  		if (bch_btree_check(c))
> -			goto err;
> +			goto no_replay;
>  
>  		bch_journal_mark(c, &journal);
>  		bch_initial_gc_finish(c);
> @@ -1854,7 +1855,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 no_replay;
>  
>  		/*
>  		 * First place it's safe to allocate: btree_check() and
> @@ -1870,6 +1871,21 @@ static void run_cache_set(struct cache_set *c)
>  			__uuid_write(c);
>  
>  		bch_journal_replay(c, &journal);
> +
> +no_replay:
> +		/*
> +		 * Only for the err cases as bch_joural_replay can release
> +		 * the list of journal_replay(s) and skip "goto err".
> +		 */
> +		if (!list_empty(&journal)) {
> +			while (!list_empty(&journal)) {
> +				l = list_first_entry(&journal,
> +						struct journal_replay, list);
> +				list_del(&l->list);
> +				kfree(l);
> +			}

How about use do { remove l from l->list } while (!list_empty(&journal))
? Then we can avoid one extra condition check for whether journal list
is empty.

And, if you move this block of code to the location after label 'err:'
(don't forget to move LIST_HEAD(journal) to a proper location), the
modification can be minimized.


> +			goto err;
> +		}
>  	} else {
>  		pr_notice("invalidating existing data");
>  
> 

Thanks.

-- 

Coly Li



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux ARM Kernel]     [Linux Filesystem Development]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux