diff options
Diffstat (limited to 'fs/nfs/delegation.c')
| -rw-r--r-- | fs/nfs/delegation.c | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 7f3f60641344..da5433230bb1 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -85,25 +85,30 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_ | |||
| 85 | { | 85 | { |
| 86 | struct inode *inode = state->inode; | 86 | struct inode *inode = state->inode; |
| 87 | struct file_lock *fl; | 87 | struct file_lock *fl; |
| 88 | struct file_lock_context *flctx = inode->i_flctx; | ||
| 89 | struct list_head *list; | ||
| 88 | int status = 0; | 90 | int status = 0; |
| 89 | 91 | ||
| 90 | if (inode->i_flock == NULL) | 92 | if (flctx == NULL) |
| 91 | goto out; | 93 | goto out; |
| 92 | 94 | ||
| 93 | /* Protect inode->i_flock using the i_lock */ | 95 | list = &flctx->flc_posix; |
| 94 | spin_lock(&inode->i_lock); | 96 | spin_lock(&flctx->flc_lock); |
| 95 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { | 97 | restart: |
| 96 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) | 98 | list_for_each_entry(fl, list, fl_list) { |
| 97 | continue; | ||
| 98 | if (nfs_file_open_context(fl->fl_file) != ctx) | 99 | if (nfs_file_open_context(fl->fl_file) != ctx) |
| 99 | continue; | 100 | continue; |
| 100 | spin_unlock(&inode->i_lock); | 101 | spin_unlock(&flctx->flc_lock); |
| 101 | status = nfs4_lock_delegation_recall(fl, state, stateid); | 102 | status = nfs4_lock_delegation_recall(fl, state, stateid); |
| 102 | if (status < 0) | 103 | if (status < 0) |
| 103 | goto out; | 104 | goto out; |
| 104 | spin_lock(&inode->i_lock); | 105 | spin_lock(&flctx->flc_lock); |
| 105 | } | 106 | } |
| 106 | spin_unlock(&inode->i_lock); | 107 | if (list == &flctx->flc_posix) { |
| 108 | list = &flctx->flc_flock; | ||
| 109 | goto restart; | ||
| 110 | } | ||
| 111 | spin_unlock(&flctx->flc_lock); | ||
| 107 | out: | 112 | out: |
| 108 | return status; | 113 | return status; |
| 109 | } | 114 | } |
| @@ -301,6 +306,17 @@ nfs_inode_detach_delegation(struct inode *inode) | |||
| 301 | return nfs_detach_delegation(nfsi, delegation, server); | 306 | return nfs_detach_delegation(nfsi, delegation, server); |
| 302 | } | 307 | } |
| 303 | 308 | ||
| 309 | static void | ||
| 310 | nfs_update_inplace_delegation(struct nfs_delegation *delegation, | ||
| 311 | const struct nfs_delegation *update) | ||
| 312 | { | ||
| 313 | if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) { | ||
| 314 | delegation->stateid.seqid = update->stateid.seqid; | ||
| 315 | smp_wmb(); | ||
| 316 | delegation->type = update->type; | ||
| 317 | } | ||
| 318 | } | ||
| 319 | |||
| 304 | /** | 320 | /** |
| 305 | * nfs_inode_set_delegation - set up a delegation on an inode | 321 | * nfs_inode_set_delegation - set up a delegation on an inode |
| 306 | * @inode: inode to which delegation applies | 322 | * @inode: inode to which delegation applies |
| @@ -334,9 +350,12 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct | |||
| 334 | old_delegation = rcu_dereference_protected(nfsi->delegation, | 350 | old_delegation = rcu_dereference_protected(nfsi->delegation, |
| 335 | lockdep_is_held(&clp->cl_lock)); | 351 | lockdep_is_held(&clp->cl_lock)); |
| 336 | if (old_delegation != NULL) { | 352 | if (old_delegation != NULL) { |
| 337 | if (nfs4_stateid_match(&delegation->stateid, | 353 | /* Is this an update of the existing delegation? */ |
| 338 | &old_delegation->stateid) && | 354 | if (nfs4_stateid_match_other(&old_delegation->stateid, |
| 339 | delegation->type == old_delegation->type) { | 355 | &delegation->stateid)) { |
| 356 | nfs_update_inplace_delegation(old_delegation, | ||
| 357 | delegation); | ||
| 358 | nfsi->delegation_state = old_delegation->type; | ||
| 340 | goto out; | 359 | goto out; |
| 341 | } | 360 | } |
| 342 | /* | 361 | /* |
