diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-12-23 15:21:46 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-12-23 15:21:46 -0500 |
commit | 515d86117724abe39d7d57d7ccc7cc5c44480529 (patch) | |
tree | dce297acebc94355217219893a5c6a81ca281ff7 /fs/nfs/delegation.c | |
parent | 9e33bed55239bdcee1746c31a11177d239bac1b5 (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/delegation.c')
-rw-r--r-- | fs/nfs/delegation.c | 97 |
1 files changed, 45 insertions, 52 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 { |