aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:46 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-12-23 15:21:46 -0500
commit515d86117724abe39d7d57d7ccc7cc5c44480529 (patch)
treedce297acebc94355217219893a5c6a81ca281ff7 /fs/nfs
parent9e33bed55239bdcee1746c31a11177d239bac1b5 (diff)
NFSv4: Clean up the support for returning multiple delegations
Add a flag to mark delegations as requiring return, then run a garbage collector. In the future, this will allow for more flexible delegation management, where delegations may be marked for return if it turns out that they are not being referenced. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/delegation.c97
-rw-r--r--fs/nfs/delegation.h8
-rw-r--r--fs/nfs/super.c2
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 */
261static void nfs_client_return_marked_delegations(struct nfs_client *clp)
262{
263 struct nfs_delegation *delegation;
264 struct inode *inode;
265
266restart:
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 */
299void nfs_return_all_delegations(struct super_block *sb) 327void 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;
307restart:
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
345static 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
329static int nfs_do_expire_all_delegations(void *ptr) 356static 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);
336restart: 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();
356out: 367out:
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 */
380void nfs_handle_cb_pathdown(struct nfs_client *clp) 391void 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;
387restart: 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
405struct recall_threadargs { 398struct 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
28enum {
29 NFS_DELEGATION_NEED_RECLAIM = 0,
30 NFS_DELEGATION_RETURN,
31};
32
29int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 33int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
30void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res); 34void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
31int nfs_inode_return_delegation(struct inode *inode); 35int nfs_inode_return_delegation(struct inode *inode);
@@ -33,7 +37,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *s
33void nfs_inode_return_delegation_noreclaim(struct inode *inode); 37void nfs_inode_return_delegation_noreclaim(struct inode *inode);
34 38
35struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle); 39struct inode *nfs_delegation_find_inode(struct nfs_client *clp, const struct nfs_fh *fhandle);
36void nfs_return_all_delegations(struct super_block *sb); 40void nfs_super_return_all_delegations(struct super_block *sb);
37void nfs_expire_all_delegations(struct nfs_client *clp); 41void nfs_expire_all_delegations(struct nfs_client *clp);
38void nfs_handle_cb_pathdown(struct nfs_client *clp); 42void 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);