Commit 86e894899820f2b3094d5557124fc22743ae0fc7

Authored by Trond Myklebust
1 parent 343104308a

NFSv4: Fix up the dereferencing of delegation->inode

Without an extra lock, we cannot just assume that the delegation->inode is
valid when we're traversing the rcu-protected nfs_client lists. Use the
delegation->lock to ensure that it is truly valid.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>

Showing 1 changed file with 31 additions and 8 deletions Side-by-side Diff

... ... @@ -134,6 +134,17 @@
134 134 return res;
135 135 }
136 136  
  137 +static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
  138 +{
  139 + struct inode *inode = NULL;
  140 +
  141 + spin_lock(&delegation->lock);
  142 + if (delegation->inode != NULL)
  143 + inode = igrab(delegation->inode);
  144 + spin_unlock(&delegation->lock);
  145 + return inode;
  146 +}
  147 +
137 148 static struct nfs_delegation *nfs_detach_delegation_locked(struct nfs_inode *nfsi, const nfs4_stateid *stateid)
138 149 {
139 150 struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);
... ... @@ -145,6 +156,7 @@
145 156 sizeof(delegation->stateid.data)) != 0)
146 157 goto nomatch_unlock;
147 158 list_del_rcu(&delegation->super_list);
  159 + delegation->inode = NULL;
148 160 nfsi->delegation_state = 0;
149 161 rcu_assign_pointer(nfsi->delegation, NULL);
150 162 spin_unlock(&delegation->lock);
... ... @@ -298,9 +310,11 @@
298 310 restart:
299 311 rcu_read_lock();
300 312 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
301   - if (delegation->inode->i_sb != sb)
302   - continue;
303   - inode = igrab(delegation->inode);
  313 + inode = NULL;
  314 + spin_lock(&delegation->lock);
  315 + if (delegation->inode != NULL && delegation->inode->i_sb == sb)
  316 + inode = igrab(delegation->inode);
  317 + spin_unlock(&delegation->lock);
304 318 if (inode == NULL)
305 319 continue;
306 320 spin_lock(&clp->cl_lock);
... ... @@ -329,7 +343,7 @@
329 343 goto out;
330 344 rcu_read_lock();
331 345 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
332   - inode = igrab(delegation->inode);
  346 + inode = nfs_delegation_grab_inode(delegation);
333 347 if (inode == NULL)
334 348 continue;
335 349 spin_lock(&clp->cl_lock);
... ... @@ -376,7 +390,7 @@
376 390 restart:
377 391 rcu_read_lock();
378 392 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
379   - inode = igrab(delegation->inode);
  393 + inode = nfs_delegation_grab_inode(delegation);
380 394 if (inode == NULL)
381 395 continue;
382 396 spin_lock(&clp->cl_lock);
383 397  
384 398  
... ... @@ -464,10 +478,14 @@
464 478 struct inode *res = NULL;
465 479 rcu_read_lock();
466 480 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
467   - if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
  481 + spin_lock(&delegation->lock);
  482 + if (delegation->inode != NULL &&
  483 + nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
468 484 res = igrab(delegation->inode);
469   - break;
470 485 }
  486 + spin_unlock(&delegation->lock);
  487 + if (res != NULL)
  488 + break;
471 489 }
472 490 rcu_read_unlock();
473 491 return res;
474 492  
475 493  
476 494  
... ... @@ -491,17 +509,22 @@
491 509 void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
492 510 {
493 511 struct nfs_delegation *delegation;
  512 + struct inode *inode;
494 513 restart:
495 514 rcu_read_lock();
496 515 list_for_each_entry_rcu(delegation, &clp->cl_delegations, super_list) {
497 516 if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
498 517 continue;
  518 + inode = nfs_delegation_grab_inode(delegation);
  519 + if (inode == NULL)
  520 + continue;
499 521 spin_lock(&clp->cl_lock);
500   - delegation = nfs_detach_delegation_locked(NFS_I(delegation->inode), NULL);
  522 + delegation = nfs_detach_delegation_locked(NFS_I(inode), NULL);
501 523 spin_unlock(&clp->cl_lock);
502 524 rcu_read_unlock();
503 525 if (delegation != NULL)
504 526 nfs_free_delegation(delegation);
  527 + iput(inode);
505 528 goto restart;
506 529 }
507 530 rcu_read_unlock();