lkml.org 
[lkml]   [2014]   [Mar]   [4]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.10 81/97] quota: Fix race between dqput() and dquot_scan_active()
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

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

    From: Jan Kara <jack@suse.cz>

    commit 1362f4ea20fa63688ba6026e586d9746ff13a846 upstream.

    Currently last dqput() can race with dquot_scan_active() causing it to
    call callback for an already deactivated dquot. The race is as follows:

    CPU1 CPU2
    dqput()
    spin_lock(&dq_list_lock);
    if (atomic_read(&dquot->dq_count) > 1) {
    - not taken
    if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
    spin_unlock(&dq_list_lock);
    ->release_dquot(dquot);
    if (atomic_read(&dquot->dq_count) > 1)
    - not taken
    dquot_scan_active()
    spin_lock(&dq_list_lock);
    if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags))
    - not taken
    atomic_inc(&dquot->dq_count);
    spin_unlock(&dq_list_lock);
    - proceeds to release dquot
    ret = fn(dquot, priv);
    - called for inactive dquot

    Fix the problem by making sure possible ->release_dquot() is finished by
    the time we call the callback and new calls to it will notice reference
    dquot_scan_active() has taken and bail out.

    Signed-off-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/quota/dquot.c | 14 +++++++++++---
    1 file changed, 11 insertions(+), 3 deletions(-)

    --- a/fs/quota/dquot.c
    +++ b/fs/quota/dquot.c
    @@ -581,9 +581,17 @@ int dquot_scan_active(struct super_block
    dqstats_inc(DQST_LOOKUPS);
    dqput(old_dquot);
    old_dquot = dquot;
    - ret = fn(dquot, priv);
    - if (ret < 0)
    - goto out;
    + /*
    + * ->release_dquot() can be racing with us. Our reference
    + * protects us from new calls to it so just wait for any
    + * outstanding call and recheck the DQ_ACTIVE_B after that.
    + */
    + wait_on_dquot(dquot);
    + if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) {
    + ret = fn(dquot, priv);
    + if (ret < 0)
    + goto out;
    + }
    spin_lock(&dq_list_lock);
    /* We are safe to continue now because our dquot could not
    * be moved out of the inuse list while we hold the reference */



    \
     
     \ /
      Last update: 2014-03-04 22:02    [W:4.141 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site