Commit 19e03c570e6099ffaf24e5628d4fe1a8acbe820d
1 parent
65de872ed6
Exists in
master
and in
7 other branches
NFSv4: Ensure that file unlock requests don't conflict with state recovery
The unlock path is currently failing to take the nfs_client->cl_sem read lock, and hence the recovery path may see locks disappear from underneath it. Also ensure that it takes the nfs_inode->rwsem read lock so that it there is no conflict with delegation recalls. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Showing 2 changed files with 20 additions and 10 deletions Side-by-side Diff
fs/nfs/nfs4proc.c
... | ... | @@ -3273,6 +3273,8 @@ |
3273 | 3273 | |
3274 | 3274 | static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) |
3275 | 3275 | { |
3276 | + struct nfs_client *clp = state->owner->so_client; | |
3277 | + struct nfs_inode *nfsi = NFS_I(state->inode); | |
3276 | 3278 | struct nfs_seqid *seqid; |
3277 | 3279 | struct nfs4_lock_state *lsp; |
3278 | 3280 | struct rpc_task *task; |
3279 | 3281 | |
... | ... | @@ -3282,8 +3284,15 @@ |
3282 | 3284 | status = nfs4_set_lock_state(state, request); |
3283 | 3285 | /* Unlock _before_ we do the RPC call */ |
3284 | 3286 | request->fl_flags |= FL_EXISTS; |
3285 | - if (do_vfs_lock(request->fl_file, request) == -ENOENT) | |
3287 | + down_read(&clp->cl_sem); | |
3288 | + down_read(&nfsi->rwsem); | |
3289 | + if (do_vfs_lock(request->fl_file, request) == -ENOENT) { | |
3290 | + up_read(&nfsi->rwsem); | |
3291 | + up_read(&clp->cl_sem); | |
3286 | 3292 | goto out; |
3293 | + } | |
3294 | + up_read(&nfsi->rwsem); | |
3295 | + up_read(&clp->cl_sem); | |
3287 | 3296 | if (status != 0) |
3288 | 3297 | goto out; |
3289 | 3298 | /* Is this a delegated lock? */ |
... | ... | @@ -3510,6 +3519,7 @@ |
3510 | 3519 | static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) |
3511 | 3520 | { |
3512 | 3521 | struct nfs_client *clp = state->owner->so_client; |
3522 | + struct nfs_inode *nfsi = NFS_I(state->inode); | |
3513 | 3523 | unsigned char fl_flags = request->fl_flags; |
3514 | 3524 | int status; |
3515 | 3525 | |
3516 | 3526 | |
3517 | 3527 | |
3518 | 3528 | |
... | ... | @@ -3522,18 +3532,13 @@ |
3522 | 3532 | if (status < 0) |
3523 | 3533 | goto out; |
3524 | 3534 | down_read(&clp->cl_sem); |
3535 | + down_read(&nfsi->rwsem); | |
3525 | 3536 | if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { |
3526 | - struct nfs_inode *nfsi = NFS_I(state->inode); | |
3527 | 3537 | /* Yes: cache locks! */ |
3528 | - down_read(&nfsi->rwsem); | |
3529 | 3538 | /* ...but avoid races with delegation recall... */ |
3530 | - if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { | |
3531 | - request->fl_flags = fl_flags & ~FL_SLEEP; | |
3532 | - status = do_vfs_lock(request->fl_file, request); | |
3533 | - up_read(&nfsi->rwsem); | |
3534 | - goto out_unlock; | |
3535 | - } | |
3536 | - up_read(&nfsi->rwsem); | |
3539 | + request->fl_flags = fl_flags & ~FL_SLEEP; | |
3540 | + status = do_vfs_lock(request->fl_file, request); | |
3541 | + goto out_unlock; | |
3537 | 3542 | } |
3538 | 3543 | status = _nfs4_do_setlk(state, cmd, request, 0); |
3539 | 3544 | if (status != 0) |
... | ... | @@ -3543,6 +3548,7 @@ |
3543 | 3548 | if (do_vfs_lock(request->fl_file, request) < 0) |
3544 | 3549 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); |
3545 | 3550 | out_unlock: |
3551 | + up_read(&nfsi->rwsem); | |
3546 | 3552 | up_read(&clp->cl_sem); |
3547 | 3553 | out: |
3548 | 3554 | request->fl_flags = fl_flags; |
fs/nfs/nfs4state.c
... | ... | @@ -849,9 +849,11 @@ |
849 | 849 | static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops) |
850 | 850 | { |
851 | 851 | struct inode *inode = state->inode; |
852 | + struct nfs_inode *nfsi = NFS_I(inode); | |
852 | 853 | struct file_lock *fl; |
853 | 854 | int status = 0; |
854 | 855 | |
856 | + down_write(&nfsi->rwsem); | |
855 | 857 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
856 | 858 | if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK))) |
857 | 859 | continue; |
858 | 860 | |
... | ... | @@ -874,8 +876,10 @@ |
874 | 876 | goto out_err; |
875 | 877 | } |
876 | 878 | } |
879 | + up_write(&nfsi->rwsem); | |
877 | 880 | return 0; |
878 | 881 | out_err: |
882 | + up_write(&nfsi->rwsem); | |
879 | 883 | return status; |
880 | 884 | } |
881 | 885 |