diff options
-rw-r--r-- | fs/nfs/delegation.c | 97 | ||||
-rw-r--r-- | fs/nfs/delegation.h | 8 | ||||
-rw-r--r-- | fs/nfs/super.c | 2 |
3 files changed, 52 insertions, 55 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index ebc06f2da31a..bc9d4f9a788d 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
@@ -256,6 +256,34 @@ static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegat | |||
256 | } | 256 | } |
257 | 257 | ||
258 | /* | 258 | /* |
259 | * Return all delegations that have been marked for return | ||
260 | */ | ||
261 | static void nfs_client_return_marked_delegations(struct nfs_client *clp) | ||
262 | { | ||
263 | struct nfs_delegation *delegation; | ||
264 | struct inode *inode; | ||
265 | |||
266 | restart: | ||
267 | rcu_read_lock(); | ||
268 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | ||
269 | if (!test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags)) | ||
270 | continue; | ||
271 | inode = nfs_delegation_grab_inode(delegation); | ||
272 | if (inode == NULL) | ||
273 | continue; | ||
274 | spin_lock(&clp->cl_lock); | ||
275 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
276 | spin_unlock(&clp->cl_lock); | ||
277 | rcu_read_unlock(); | ||
278 | if (delegation != NULL) | ||
279 | __nfs_inode_return_delegation(inode, delegation); | ||
280 | iput(inode); | ||
281 | goto restart; | ||
282 | } | ||
283 | rcu_read_unlock(); | ||
284 | } | ||
285 | |||
286 | /* | ||
259 | * This function returns the delegation without reclaiming opens | 287 | * This function returns the delegation without reclaiming opens |
260 | * or protecting against delegation reclaims. | 288 | * or protecting against delegation reclaims. |
261 | * It is therefore really only safe to be called from | 289 | * It is therefore really only safe to be called from |
@@ -296,63 +324,46 @@ int nfs_inode_return_delegation(struct inode *inode) | |||
296 | /* | 324 | /* |
297 | * Return all delegations associated to a super block | 325 | * Return all delegations associated to a super block |
298 | */ | 326 | */ |
299 | void nfs_return_all_delegations(struct super_block *sb) | 327 | void nfs_super_return_all_delegations(struct super_block *sb) |
300 | { | 328 | { |
301 | struct nfs_client *clp = NFS_SB(sb)->nfs_client; | 329 | struct nfs_client *clp = NFS_SB(sb)->nfs_client; |
302 | struct nfs_delegation *delegation; | 330 | struct nfs_delegation *delegation; |
303 | struct inode *inode; | ||
304 | 331 | ||
305 | if (clp == NULL) | 332 | if (clp == NULL) |
306 | return; | 333 | return; |
307 | restart: | ||
308 | rcu_read_lock(); | 334 | rcu_read_lock(); |
309 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | 335 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { |
310 | inode = NULL; | ||
311 | spin_lock(&delegation->lock); | 336 | spin_lock(&delegation->lock); |
312 | if (delegation->inode != NULL && delegation->inode->i_sb == sb) | 337 | if (delegation->inode != NULL && delegation->inode->i_sb == sb) |
313 | inode = igrab(delegation->inode); | 338 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); |
314 | spin_unlock(&delegation->lock); | 339 | spin_unlock(&delegation->lock); |
315 | if (inode == NULL) | ||
316 | continue; | ||
317 | spin_lock(&clp->cl_lock); | ||
318 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
319 | spin_unlock(&clp->cl_lock); | ||
320 | rcu_read_unlock(); | ||
321 | if (delegation != NULL) | ||
322 | __nfs_inode_return_delegation(inode, delegation); | ||
323 | iput(inode); | ||
324 | goto restart; | ||
325 | } | 340 | } |
326 | rcu_read_unlock(); | 341 | rcu_read_unlock(); |
342 | nfs_client_return_marked_delegations(clp); | ||
343 | } | ||
344 | |||
345 | static void nfs_client_return_all_delegations(struct nfs_client *clp) | ||
346 | { | ||
347 | struct nfs_delegation *delegation; | ||
348 | |||
349 | rcu_read_lock(); | ||
350 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) | ||
351 | set_bit(NFS_DELEGATION_RETURN, &delegation->flags); | ||
352 | rcu_read_unlock(); | ||
353 | nfs_client_return_marked_delegations(clp); | ||
327 | } | 354 | } |
328 | 355 | ||
329 | static int nfs_do_expire_all_delegations(void *ptr) | 356 | static int nfs_do_expire_all_delegations(void *ptr) |
330 | { | 357 | { |
331 | struct nfs_client *clp = ptr; | 358 | struct nfs_client *clp = ptr; |
332 | struct nfs_delegation *delegation; | ||
333 | struct inode *inode; | ||
334 | 359 | ||
335 | allow_signal(SIGKILL); | 360 | allow_signal(SIGKILL); |
336 | restart: | 361 | |
337 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) | 362 | if (test_bit(NFS4CLNT_STATE_RECOVER, &clp->cl_state) != 0) |
338 | goto out; | 363 | goto out; |
339 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) | 364 | if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) |
340 | goto out; | 365 | goto out; |
341 | rcu_read_lock(); | 366 | nfs_client_return_all_delegations(clp); |
342 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | ||
343 | inode = nfs_delegation_grab_inode(delegation); | ||
344 | if (inode == NULL) | ||
345 | continue; | ||
346 | spin_lock(&clp->cl_lock); | ||
347 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
348 | spin_unlock(&clp->cl_lock); | ||
349 | rcu_read_unlock(); | ||
350 | if (delegation) | ||
351 | __nfs_inode_return_delegation(inode, delegation); | ||
352 | iput(inode); | ||
353 | goto restart; | ||
354 | } | ||
355 | rcu_read_unlock(); | ||
356 | out: | 367 | out: |
357 | nfs_put_client(clp); | 368 | nfs_put_client(clp); |
358 | module_put_and_exit(0); | 369 | module_put_and_exit(0); |
@@ -379,27 +390,9 @@ void nfs_expire_all_delegations(struct nfs_client *clp) | |||
379 | */ | 390 | */ |
380 | void nfs_handle_cb_pathdown(struct nfs_client *clp) | 391 | void nfs_handle_cb_pathdown(struct nfs_client *clp) |
381 | { | 392 | { |
382 | struct nfs_delegation *delegation; | ||
383 | struct inode *inode; | ||
384 | |||
385 | if (clp == NULL) | 393 | if (clp == NULL) |
386 | return; | 394 | return; |
387 | restart: | 395 | nfs_client_return_all_delegations(clp); |
388 | rcu_read_lock(); | ||
389 | list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) { | ||
390 | inode = nfs_delegation_grab_inode(delegation); | ||
391 | if (inode == NULL) | ||
392 | continue; | ||
393 | spin_lock(&clp->cl_lock); | ||
394 | delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL); | ||
395 | spin_unlock(&clp->cl_lock); | ||
396 | rcu_read_unlock(); | ||
397 | if (delegation != NULL) | ||
398 | __nfs_inode_return_delegation(inode, delegation); | ||
399 | iput(inode); | ||
400 | goto restart; | ||
401 | } | ||
402 | rcu_read_unlock(); | ||
403 | } | 396 | } |
404 | 397 | ||
405 | struct recall_threadargs { | 398 | struct recall_threadargs { |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 5e9f40e0a7d8..c772bab12eea 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
@@ -20,12 +20,16 @@ struct nfs_delegation { | |||
20 | int type; | 20 | int type; |
21 | loff_t maxsize; | 21 | loff_t maxsize; |
22 | __u64 change_attr; | 22 | __u64 change_attr; |
23 | #define NFS_DELEGATION_NEED_RECLAIM 0 | ||
24 | unsigned long flags; | 23 | unsigned long flags; |
25 | spinlock_t lock; | 24 | spinlock_t lock; |
26 | struct rcu_head rcu; | 25 | struct rcu_head rcu; |
27 | }; | 26 | }; |
28 | 27 | ||
28 | enum { | ||
29 | NFS_DELEGATION_NEED_RECLAIM = 0, | ||
30 | NFS_DELEGATION_RETURN, | ||
31 | }; | ||
32 | |||
29 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 33 | int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
30 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); | 34 | void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); |
31 | int nfs_inode_return_delegation(struct inode *inode); | 35 | int nfs_inode_return_delegation(struct inode *inode); |
@@ -33,7 +37,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s | |||
33 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); | 37 | void nfs_inode_return_delegation_noreclaim(struct inode *inode); |
34 | 38 | ||
35 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); | 39 | struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); |
36 | void nfs_return_all_delegations(struct super_block *sb); | 40 | void nfs_super_return_all_delegations(struct super_block *sb); |
37 | void nfs_expire_all_delegations(struct nfs_client *clp); | 41 | void nfs_expire_all_delegations(struct nfs_client *clp); |
38 | void nfs_handle_cb_pathdown(struct nfs_client *clp); | 42 | void nfs_handle_cb_pathdown(struct nfs_client *clp); |
39 | 43 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index d8e062fe76b1..bd4c3dd550df 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -2433,7 +2433,7 @@ static void nfs4_kill_super(struct super_block *sb) | |||
2433 | { | 2433 | { |
2434 | struct nfs_server *server = NFS_SB(sb); | 2434 | struct nfs_server *server = NFS_SB(sb); |
2435 | 2435 | ||
2436 | nfs_return_all_delegations(sb); | 2436 | nfs_super_return_all_delegations(sb); |
2437 | kill_anon_super(sb); | 2437 | kill_anon_super(sb); |
2438 | 2438 | ||
2439 | nfs4_renewd_prepare_shutdown(server); | 2439 | nfs4_renewd_prepare_shutdown(server); |