diff options
Diffstat (limited to 'fs/nfs')
-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) |