lkml.org 
[lkml]   [2012]   [Mar]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[ 005/149] staging: zcache: avoid AB-BA deadlock condition
    3.2-stable review patch.  If anyone has any objections, please let me know.

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

    From: Andrea Righi <andrea@betterlinux.com>

    commit cfbc6a92212e74b07aa76c9e2f20c542e36077fb upstream.

    Commit 9256a47 fixed a deadlock condition, being sure that the buddy
    list spinlock is always taken before the page spinlock.

    However in zbud_free_and_delist() locking order is the opposite
    (page lock -> list lock).

    Possible unsafe locking scenario (reported by lockdep):

    CPU0 CPU1
    ---- ----
    lock(&(&zbpg->lock)->rlock);
    lock(zbud_budlists_spinlock);
    lock(&(&zbpg->lock)->rlock);
    lock(zbud_budlists_spinlock);

    Fix by grabbing the locks in opposite order in zbud_free_and_delist().

    Signed-off-by: Andrea Righi <andrea@betterlinux.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/staging/zcache/zcache-main.c | 4 ++--
    1 file changed, 2 insertions(+), 2 deletions(-)

    --- a/drivers/staging/zcache/zcache-main.c
    +++ b/drivers/staging/zcache/zcache-main.c
    @@ -299,10 +299,12 @@ static void zbud_free_and_delist(struct
    struct zbud_page *zbpg =
    container_of(zh, struct zbud_page, buddy[budnum]);

    + spin_lock(&zbud_budlists_spinlock);
    spin_lock(&zbpg->lock);
    if (list_empty(&zbpg->bud_list)) {
    /* ignore zombie page... see zbud_evict_pages() */
    spin_unlock(&zbpg->lock);
    + spin_unlock(&zbud_budlists_spinlock);
    return;
    }
    size = zbud_free(zh);
    @@ -310,7 +312,6 @@ static void zbud_free_and_delist(struct
    zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0];
    if (zh_other->size == 0) { /* was unbuddied: unlist and free */
    chunks = zbud_size_to_chunks(size) ;
    - spin_lock(&zbud_budlists_spinlock);
    BUG_ON(list_empty(&zbud_unbuddied[chunks].list));
    list_del_init(&zbpg->bud_list);
    zbud_unbuddied[chunks].count--;
    @@ -318,7 +319,6 @@ static void zbud_free_and_delist(struct
    zbud_free_raw_page(zbpg);
    } else { /* was buddied: move remaining buddy to unbuddied list */
    chunks = zbud_size_to_chunks(zh_other->size) ;
    - spin_lock(&zbud_budlists_spinlock);
    list_del_init(&zbpg->bud_list);
    zcache_zbud_buddied_count--;
    list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list);



    \
     
     \ /
      Last update: 2012-03-31 00:39    [W:0.029 / U:30.336 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site