Loading fs/nfs/delegation.c +51 −35 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ static void nfs_do_free_delegation(struct nfs_delegation *delegation) { if (delegation->cred) put_rpccred(delegation->cred); kfree(delegation); } Loading @@ -36,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head) static void nfs_free_delegation(struct nfs_delegation *delegation) { struct rpc_cred *cred; cred = rcu_dereference(delegation->cred); rcu_assign_pointer(delegation->cred, NULL); call_rcu(&delegation->rcu, nfs_free_delegation_callback); if (cred) put_rpccred(cred); } void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) Loading Loading @@ -129,21 +125,35 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s */ 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; 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); clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); NFS_I(inode)->delegation_state = delegation->type; smp_wmb(); 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) Loading @@ -166,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation return inode; } static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid, struct nfs_client *clp) { struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); struct nfs_delegation *delegation = rcu_dereference_protected(nfsi->delegation, lockdep_is_held(&clp->cl_lock)); if (delegation == NULL) goto nomatch; Loading @@ -195,7 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; struct nfs_delegation *delegation, *old_delegation; struct nfs_delegation *freeme = NULL; int status = 0; Loading @@ -213,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct spin_lock_init(&delegation->lock); spin_lock(&clp->cl_lock); if (rcu_dereference(nfsi->delegation) != NULL) { if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, sizeof(delegation->stateid)) == 0 && delegation->type == nfsi->delegation->type) { old_delegation = rcu_dereference_protected(nfsi->delegation, lockdep_is_held(&clp->cl_lock)); if (old_delegation != NULL) { if (memcmp(&delegation->stateid, &old_delegation->stateid, sizeof(old_delegation->stateid)) == 0 && delegation->type == old_delegation->type) { goto out; } /* Loading @@ -226,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct dfprintk(FILE, "%s: server %s handed out " "a duplicate delegation!\n", __func__, clp->cl_hostname); if (delegation->type <= nfsi->delegation->type) { if (delegation->type <= old_delegation->type) { freeme = delegation; delegation = NULL; goto out; } freeme = nfs_detach_delegation_locked(nfsi, NULL); freeme = nfs_detach_delegation_locked(nfsi, NULL, clp); } list_add_rcu(&delegation->super_list, &clp->cl_delegations); nfsi->delegation_state = delegation->type; Loading Loading @@ -301,7 +317,7 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp) if (inode == NULL) continue; spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); spin_unlock(&clp->cl_lock); rcu_read_unlock(); if (delegation != NULL) { Loading Loading @@ -330,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; if (rcu_dereference(nfsi->delegation) != NULL) { if (rcu_access_pointer(nfsi->delegation) != NULL) { spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(nfsi, NULL); delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); spin_unlock(&clp->cl_lock); if (delegation != NULL) nfs_do_return_delegation(inode, delegation, 0); Loading @@ -346,9 +362,9 @@ int nfs_inode_return_delegation(struct inode *inode) struct nfs_delegation *delegation; int err = 0; if (rcu_dereference(nfsi->delegation) != NULL) { if (rcu_access_pointer(nfsi->delegation) != NULL) { spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(nfsi, NULL); delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); spin_unlock(&clp->cl_lock); if (delegation != NULL) { nfs_msync_inode(inode); Loading Loading @@ -526,7 +542,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp) if (inode == NULL) continue; spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); spin_unlock(&clp->cl_lock); rcu_read_unlock(); if (delegation != NULL) Loading Loading
fs/nfs/delegation.c +51 −35 Original line number Diff line number Diff line Loading @@ -24,6 +24,8 @@ static void nfs_do_free_delegation(struct nfs_delegation *delegation) { if (delegation->cred) put_rpccred(delegation->cred); kfree(delegation); } Loading @@ -36,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head) static void nfs_free_delegation(struct nfs_delegation *delegation) { struct rpc_cred *cred; cred = rcu_dereference(delegation->cred); rcu_assign_pointer(delegation->cred, NULL); call_rcu(&delegation->rcu, nfs_free_delegation_callback); if (cred) put_rpccred(cred); } void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) Loading Loading @@ -129,21 +125,35 @@ static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *s */ 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; 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); clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags); NFS_I(inode)->delegation_state = delegation->type; smp_wmb(); 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) Loading @@ -166,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation return inode; } static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid, struct nfs_client *clp) { struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); struct nfs_delegation *delegation = rcu_dereference_protected(nfsi->delegation, lockdep_is_held(&clp->cl_lock)); if (delegation == NULL) goto nomatch; Loading @@ -195,7 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct { struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; struct nfs_delegation *delegation, *old_delegation; struct nfs_delegation *freeme = NULL; int status = 0; Loading @@ -213,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct spin_lock_init(&delegation->lock); spin_lock(&clp->cl_lock); if (rcu_dereference(nfsi->delegation) != NULL) { if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, sizeof(delegation->stateid)) == 0 && delegation->type == nfsi->delegation->type) { old_delegation = rcu_dereference_protected(nfsi->delegation, lockdep_is_held(&clp->cl_lock)); if (old_delegation != NULL) { if (memcmp(&delegation->stateid, &old_delegation->stateid, sizeof(old_delegation->stateid)) == 0 && delegation->type == old_delegation->type) { goto out; } /* Loading @@ -226,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct dfprintk(FILE, "%s: server %s handed out " "a duplicate delegation!\n", __func__, clp->cl_hostname); if (delegation->type <= nfsi->delegation->type) { if (delegation->type <= old_delegation->type) { freeme = delegation; delegation = NULL; goto out; } freeme = nfs_detach_delegation_locked(nfsi, NULL); freeme = nfs_detach_delegation_locked(nfsi, NULL, clp); } list_add_rcu(&delegation->super_list, &clp->cl_delegations); nfsi->delegation_state = delegation->type; Loading Loading @@ -301,7 +317,7 @@ int nfs_client_return_marked_delegations(struct nfs_client *clp) if (inode == NULL) continue; spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); spin_unlock(&clp->cl_lock); rcu_read_unlock(); if (delegation != NULL) { Loading Loading @@ -330,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) struct nfs_inode *nfsi = NFS_I(inode); struct nfs_delegation *delegation; if (rcu_dereference(nfsi->delegation) != NULL) { if (rcu_access_pointer(nfsi->delegation) != NULL) { spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(nfsi, NULL); delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); spin_unlock(&clp->cl_lock); if (delegation != NULL) nfs_do_return_delegation(inode, delegation, 0); Loading @@ -346,9 +362,9 @@ int nfs_inode_return_delegation(struct inode *inode) struct nfs_delegation *delegation; int err = 0; if (rcu_dereference(nfsi->delegation) != NULL) { if (rcu_access_pointer(nfsi->delegation) != NULL) { spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(nfsi, NULL); delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); spin_unlock(&clp->cl_lock); if (delegation != NULL) { nfs_msync_inode(inode); Loading Loading @@ -526,7 +542,7 @@ void nfs_delegation_reap_unclaimed(struct nfs_client *clp) if (inode == NULL) continue; spin_lock(&clp->cl_lock); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); spin_unlock(&clp->cl_lock); rcu_read_unlock(); if (delegation != NULL) Loading