diff options
| -rw-r--r-- | fs/nfs/delegation.c | 44 |
1 files changed, 23 insertions, 21 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 8d9ec494a944..ea61d26e7871 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | 24 | ||
| 25 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) | 25 | static void nfs_do_free_delegation(struct nfs_delegation *delegation) |
| 26 | { | 26 | { |
| 27 | if (delegation->cred) | ||
| 28 | put_rpccred(delegation->cred); | ||
| 27 | kfree(delegation); | 29 | kfree(delegation); |
| 28 | } | 30 | } |
| 29 | 31 | ||
| @@ -36,13 +38,7 @@ static void nfs_free_delegation_callback(struct rcu_head *head) | |||
| 36 | 38 | ||
| 37 | static void nfs_free_delegation(struct nfs_delegation *delegation) | 39 | static void nfs_free_delegation(struct nfs_delegation *delegation) |
| 38 | { | 40 | { |
| 39 | struct rpc_cred *cred; | ||
| 40 | |||
| 41 | cred = rcu_dereference(delegation->cred); | ||
| 42 | rcu_assign_pointer(delegation->cred, NULL); | ||
| 43 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); | 41 | call_rcu(&delegation->rcu, nfs_free_delegation_callback); |
| 44 | if (cred) | ||
| 45 | put_rpccred(cred); | ||
| 46 | } | 42 | } |
| 47 | 43 | ||
| 48 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | 44 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) |
| @@ -180,9 +176,13 @@ static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation | |||
| 180 | return inode; | 176 | return inode; |
| 181 | } | 177 | } |
| 182 | 178 | ||
| 183 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid) | 179 | static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, |
| 180 | const nfs4_stateid *stateid, | ||
| 181 | struct nfs_client *clp) | ||
| 184 | { | 182 | { |
| 185 | struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation); | 183 | struct nfs_delegation *delegation = |
| 184 | rcu_dereference_protected(nfsi->delegation, | ||
| 185 | lockdep_is_held(&clp->cl_lock)); | ||
| 186 | 186 | ||
| 187 | if (delegation == NULL) | 187 | if (delegation == NULL) |
| 188 | goto nomatch; | 188 | goto nomatch; |
| @@ -209,7 +209,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 209 | { | 209 | { |
| 210 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; | 210 | struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; |
| 211 | struct nfs_inode *nfsi = NFS_I(inode); | 211 | struct nfs_inode *nfsi = NFS_I(inode); |
| 212 | struct nfs_delegation *delegation; | 212 | struct nfs_delegation *delegation, *old_delegation; |
| 213 | struct nfs_delegation *freeme = NULL; | 213 | struct nfs_delegation *freeme = NULL; |
| 214 | int status = 0; | 214 | int status = 0; |
| 215 | 215 | ||
| @@ -227,10 +227,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 227 | spin_lock_init(&delegation->lock); | 227 | spin_lock_init(&delegation->lock); |
| 228 | 228 | ||
| 229 | spin_lock(&clp->cl_lock); | 229 | spin_lock(&clp->cl_lock); |
| 230 | if (rcu_dereference(nfsi->delegation) != NULL) { | 230 | old_delegation = rcu_dereference_protected(nfsi->delegation, |
| 231 | if (memcmp(&delegation->stateid, &nfsi->delegation->stateid, | 231 | lockdep_is_held(&clp->cl_lock)); |
| 232 | sizeof(delegation->stateid)) == 0 && | 232 | if (old_delegation != NULL) { |
| 233 | delegation->type == nfsi->delegation->type) { | 233 | if (memcmp(&delegation->stateid, &old_delegation->stateid, |
| 234 | sizeof(old_delegation->stateid)) == 0 && | ||
| 235 | delegation->type == old_delegation->type) { | ||
| 234 | goto out; | 236 | goto out; |
| 235 | } | 237 | } |
| 236 | /* | 238 | /* |
| @@ -240,12 +242,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 240 | dfprintk(FILE, "%s: server %s handed out " | 242 | dfprintk(FILE, "%s: server %s handed out " |
| 241 | "a duplicate delegation!\n", | 243 | "a duplicate delegation!\n", |
| 242 | __func__, clp->cl_hostname); | 244 | __func__, clp->cl_hostname); |
| 243 | if (delegation->type <= nfsi->delegation->type) { | 245 | if (delegation->type <= old_delegation->type) { |
| 244 | freeme = delegation; | 246 | freeme = delegation; |
| 245 | delegation = NULL; | 247 | delegation = NULL; |
| 246 | goto out; | 248 | goto out; |
| 247 | } | 249 | } |
| 248 | freeme = nfs_detach_delegation_locked(nfsi, NULL); | 250 | freeme = nfs_detach_delegation_locked(nfsi, NULL, clp); |
| 249 | } | 251 | } |
| 250 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); | 252 | list_add_rcu(&delegation->super_list, &clp->cl_delegations); |
| 251 | nfsi->delegation_state = delegation->type; | 253 | nfsi->delegation_state = delegation->type; |
| @@ -315,7 +317,7 @@ restart: | |||
| 315 | if (inode == NULL) | 317 | if (inode == NULL) |
| 316 | continue; | 318 | continue; |
| 317 | spin_lock(&clp->cl_lock); | 319 | spin_lock(&clp->cl_lock); |
| 318 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 320 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); |
| 319 | spin_unlock(&clp->cl_lock); | 321 | spin_unlock(&clp->cl_lock); |
| 320 | rcu_read_unlock(); | 322 | rcu_read_unlock(); |
| 321 | if (delegation != NULL) { | 323 | if (delegation != NULL) { |
| @@ -344,9 +346,9 @@ void nfs_inode_return_delegation_noreclaim(struct inode *inode) | |||
| 344 | struct nfs_inode *nfsi = NFS_I(inode); | 346 | struct nfs_inode *nfsi = NFS_I(inode); |
| 345 | struct nfs_delegation *delegation; | 347 | struct nfs_delegation *delegation; |
| 346 | 348 | ||
| 347 | if (rcu_dereference(nfsi->delegation) != NULL) { | 349 | if (rcu_access_pointer(nfsi->delegation) != NULL) { |
| 348 | spin_lock(&clp->cl_lock); | 350 | spin_lock(&clp->cl_lock); |
| 349 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 351 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
| 350 | spin_unlock(&clp->cl_lock); | 352 | spin_unlock(&clp->cl_lock); |
| 351 | if (delegation != NULL) | 353 | if (delegation != NULL) |
| 352 | nfs_do_return_delegation(inode, delegation, 0); | 354 | nfs_do_return_delegation(inode, delegation, 0); |
| @@ -360,9 +362,9 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
| 360 | struct nfs_delegation *delegation; | 362 | struct nfs_delegation *delegation; |
| 361 | int err = 0; | 363 | int err = 0; |
| 362 | 364 | ||
| 363 | if (rcu_dereference(nfsi->delegation) != NULL) { | 365 | if (rcu_access_pointer(nfsi->delegation) != NULL) { |
| 364 | spin_lock(&clp->cl_lock); | 366 | spin_lock(&clp->cl_lock); |
| 365 | delegation = nfs_detach_delegation_locked(nfsi, NULL); | 367 | delegation = nfs_detach_delegation_locked(nfsi, NULL, clp); |
| 366 | spin_unlock(&clp->cl_lock); | 368 | spin_unlock(&clp->cl_lock); |
| 367 | if (delegation != NULL) { | 369 | if (delegation != NULL) { |
| 368 | nfs_msync_inode(inode); | 370 | nfs_msync_inode(inode); |
| @@ -540,7 +542,7 @@ restart: | |||
| 540 | if (inode == NULL) | 542 | if (inode == NULL) |
| 541 | continue; | 543 | continue; |
| 542 | spin_lock(&clp->cl_lock); | 544 | spin_lock(&clp->cl_lock); |
| 543 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | 545 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL, clp); |
| 544 | spin_unlock(&clp->cl_lock); | 546 | spin_unlock(&clp->cl_lock); |
| 545 | rcu_read_unlock(); | 547 | rcu_read_unlock(); |
| 546 | if (delegation != NULL) | 548 | if (delegation != NULL) |
