diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
| -rw-r--r-- | fs/nfs/nfs4proc.c | 35 |
1 files changed, 24 insertions, 11 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 8bdfe3ff7925..e6ee97f19d81 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -3489,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request | |||
| 3489 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) | 3489 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
| 3490 | { | 3490 | { |
| 3491 | struct nfs4_client *clp = state->owner->so_client; | 3491 | struct nfs4_client *clp = state->owner->so_client; |
| 3492 | unsigned char fl_flags = request->fl_flags; | ||
| 3492 | int status; | 3493 | int status; |
| 3493 | 3494 | ||
| 3494 | /* Is this a delegated open? */ | 3495 | /* Is this a delegated open? */ |
| 3495 | if (NFS_I(state->inode)->delegation_state != 0) { | ||
| 3496 | /* Yes: cache locks! */ | ||
| 3497 | status = do_vfs_lock(request->fl_file, request); | ||
| 3498 | /* ...but avoid races with delegation recall... */ | ||
| 3499 | if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags)) | ||
| 3500 | return status; | ||
| 3501 | } | ||
| 3502 | down_read(&clp->cl_sem); | ||
| 3503 | status = nfs4_set_lock_state(state, request); | 3496 | status = nfs4_set_lock_state(state, request); |
| 3504 | if (status != 0) | 3497 | if (status != 0) |
| 3505 | goto out; | 3498 | goto out; |
| 3499 | request->fl_flags |= FL_ACCESS; | ||
| 3500 | status = do_vfs_lock(request->fl_file, request); | ||
| 3501 | if (status < 0) | ||
| 3502 | goto out; | ||
| 3503 | down_read(&clp->cl_sem); | ||
| 3504 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | ||
| 3505 | struct nfs_inode *nfsi = NFS_I(state->inode); | ||
| 3506 | /* Yes: cache locks! */ | ||
| 3507 | down_read(&nfsi->rwsem); | ||
| 3508 | /* ...but avoid races with delegation recall... */ | ||
| 3509 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | ||
| 3510 | request->fl_flags = fl_flags & ~FL_SLEEP; | ||
| 3511 | status = do_vfs_lock(request->fl_file, request); | ||
| 3512 | up_read(&nfsi->rwsem); | ||
| 3513 | goto out_unlock; | ||
| 3514 | } | ||
| 3515 | up_read(&nfsi->rwsem); | ||
| 3516 | } | ||
| 3506 | status = _nfs4_do_setlk(state, cmd, request, 0); | 3517 | status = _nfs4_do_setlk(state, cmd, request, 0); |
| 3507 | if (status != 0) | 3518 | if (status != 0) |
| 3508 | goto out; | 3519 | goto out_unlock; |
| 3509 | /* Note: we always want to sleep here! */ | 3520 | /* Note: we always want to sleep here! */ |
| 3510 | request->fl_flags |= FL_SLEEP; | 3521 | request->fl_flags = fl_flags | FL_SLEEP; |
| 3511 | if (do_vfs_lock(request->fl_file, request) < 0) | 3522 | if (do_vfs_lock(request->fl_file, request) < 0) |
| 3512 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); | 3523 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); |
| 3513 | out: | 3524 | out_unlock: |
| 3514 | up_read(&clp->cl_sem); | 3525 | up_read(&clp->cl_sem); |
| 3526 | out: | ||
| 3527 | request->fl_flags = fl_flags; | ||
| 3515 | return status; | 3528 | return status; |
| 3516 | } | 3529 | } |
| 3517 | 3530 | ||
