lkml.org 
[lkml]   [2014]   [May]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.10 17/86] md/raid1: r1buf_pool_alloc: free allocate pages when subsequent allocation fails.
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: NeilBrown <neilb@suse.de>

    commit da1aab3dca9aa88ae34ca392470b8943159e25fe upstream.

    When performing a user-request check/repair (MD_RECOVERY_REQUEST is set)
    on a raid1, we allocate multiple bios each with their own set of pages.

    If the page allocations for one bio fails, we currently do *not* free
    the pages allocated for the previous bios, nor do we free the bio itself.

    This patch frees all the already-allocate pages, and makes sure that
    all the bios are freed as well.

    This bug can cause a memory leak which can ultimately OOM a machine.
    It was introduced in 3.10-rc1.

    Fixes: a07876064a0b73ab5ef1ebcf14b1cf0231c07858
    Cc: Kent Overstreet <koverstreet@google.com>
    Reported-by: Russell King - ARM Linux <linux@arm.linux.org.uk>
    Signed-off-by: NeilBrown <neilb@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/md/raid1.c | 17 +++++++++++++----
    1 file changed, 13 insertions(+), 4 deletions(-)

    --- a/drivers/md/raid1.c
    +++ b/drivers/md/raid1.c
    @@ -94,6 +94,7 @@ static void * r1buf_pool_alloc(gfp_t gfp
    struct pool_info *pi = data;
    struct r1bio *r1_bio;
    struct bio *bio;
    + int need_pages;
    int i, j;

    r1_bio = r1bio_pool_alloc(gfp_flags, pi);
    @@ -116,15 +117,15 @@ static void * r1buf_pool_alloc(gfp_t gfp
    * RESYNC_PAGES for each bio.
    */
    if (test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery))
    - j = pi->raid_disks;
    + need_pages = pi->raid_disks;
    else
    - j = 1;
    - while(j--) {
    + need_pages = 1;
    + for (j = 0; j < need_pages; j++) {
    bio = r1_bio->bios[j];
    bio->bi_vcnt = RESYNC_PAGES;

    if (bio_alloc_pages(bio, gfp_flags))
    - goto out_free_bio;
    + goto out_free_pages;
    }
    /* If not user-requests, copy the page pointers to all bios */
    if (!test_bit(MD_RECOVERY_REQUESTED, &pi->mddev->recovery)) {
    @@ -138,6 +139,14 @@ static void * r1buf_pool_alloc(gfp_t gfp

    return r1_bio;

    +out_free_pages:
    + while (--j >= 0) {
    + struct bio_vec *bv;
    +
    + bio_for_each_segment_all(bv, r1_bio->bios[j], i)
    + __free_page(bv->bv_page);
    + }
    +
    out_free_bio:
    while (++j < pi->raid_disks)
    bio_put(r1_bio->bios[j]);



    \
     
     \ /
      Last update: 2014-05-29 07:41    [W:4.019 / U:0.108 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site