lkml.org 
[lkml]   [2010]   [Apr]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2.6.34-rc5 04/12] NFSv4: Fix the locking in nfs_inode_reclaim_delegation()
    Date
    From: Trond Myklebust <Trond.Myklebust@netapp.com>

    Ensure that we correctly rcu-dereference the delegation itself, and that we
    protect against removal while we're changing the contents.

    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
    Signed-off-by: David Howells <dhowells@redhat.com>
    Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
    ---
    fs/nfs/delegation.c | 42 ++++++++++++++++++++++++++++--------------
    1 files changed, 28 insertions(+), 14 deletions(-)

    diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
    index 1567124..8d9ec49 100644
    --- a/fs/nfs/delegation.c
    +++ b/fs/nfs/delegation.c
    @@ -129,21 +129,35 @@ again:
    */
    void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
    {
    - struct nfs_delegation *delegation = NFS_I(inode)->delegation;
    - struct rpc_cred *oldcred;
    + struct nfs_delegation *delegation;
    + struct rpc_cred *oldcred = NULL;

    - if (delegation == NULL)
    - return;
    - memcpy(delegation->stateid.data, res->delegation.data,
    - sizeof(delegation->stateid.data));
    - delegation->type = res->delegation_type;
    - delegation->maxsize = res->maxsize;
    - oldcred = delegation->cred;
    - delegation->cred = get_rpccred(cred);
    - clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
    - NFS_I(inode)->delegation_state = delegation->type;
    - smp_wmb();
    - put_rpccred(oldcred);
    + rcu_read_lock();
    + delegation = rcu_dereference(NFS_I(inode)->delegation);
    + if (delegation != NULL) {
    + spin_lock(&delegation->lock);
    + if (delegation->inode != NULL) {
    + memcpy(delegation->stateid.data, res->delegation.data,
    + sizeof(delegation->stateid.data));
    + delegation->type = res->delegation_type;
    + delegation->maxsize = res->maxsize;
    + oldcred = delegation->cred;
    + delegation->cred = get_rpccred(cred);
    + clear_bit(NFS_DELEGATION_NEED_RECLAIM,
    + &delegation->flags);
    + NFS_I(inode)->delegation_state = delegation->type;
    + spin_unlock(&delegation->lock);
    + put_rpccred(oldcred);
    + rcu_read_unlock();
    + } else {
    + /* We appear to have raced with a delegation return. */
    + spin_unlock(&delegation->lock);
    + rcu_read_unlock();
    + nfs_inode_set_delegation(inode, cred, res);
    + }
    + } else {
    + rcu_read_unlock();
    + }
    }

    static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
    --
    1.7.0


    \
     
     \ /
      Last update: 2010-04-23 21:49    [W:0.024 / U:30.328 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site