aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/lockd/clntproc.c26
-rw-r--r--fs/locks.c23
-rw-r--r--fs/nfs/nfs4proc.c74
-rw-r--r--include/linux/fs.h1
4 files changed, 80 insertions, 44 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 5980c45998cc..89ba0df14c22 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho
454 fl->fl_ops = &nlmclnt_lock_ops; 454 fl->fl_ops = &nlmclnt_lock_ops;
455} 455}
456 456
457static void do_vfs_lock(struct file_lock *fl) 457static int do_vfs_lock(struct file_lock *fl)
458{ 458{
459 int res = 0; 459 int res = 0;
460 switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { 460 switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
@@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl)
467 default: 467 default:
468 BUG(); 468 BUG();
469 } 469 }
470 if (res < 0) 470 return res;
471 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
472 __FUNCTION__);
473} 471}
474 472
475/* 473/*
@@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
498 struct nlm_host *host = req->a_host; 496 struct nlm_host *host = req->a_host;
499 struct nlm_res *resp = &req->a_res; 497 struct nlm_res *resp = &req->a_res;
500 struct nlm_wait *block = NULL; 498 struct nlm_wait *block = NULL;
499 unsigned char fl_flags = fl->fl_flags;
501 int status = -ENOLCK; 500 int status = -ENOLCK;
502 501
503 if (!host->h_monitored && nsm_monitor(host) < 0) { 502 if (!host->h_monitored && nsm_monitor(host) < 0) {
@@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
505 host->h_name); 504 host->h_name);
506 goto out; 505 goto out;
507 } 506 }
507 fl->fl_flags |= FL_ACCESS;
508 status = do_vfs_lock(fl);
509 if (status < 0)
510 goto out;
508 511
509 block = nlmclnt_prepare_block(host, fl); 512 block = nlmclnt_prepare_block(host, fl);
510again: 513again:
@@ -539,9 +542,10 @@ again:
539 up_read(&host->h_rwsem); 542 up_read(&host->h_rwsem);
540 goto again; 543 goto again;
541 } 544 }
542 fl->fl_flags |= FL_SLEEP;
543 /* Ensure the resulting lock will get added to granted list */ 545 /* Ensure the resulting lock will get added to granted list */
544 do_vfs_lock(fl); 546 fl->fl_flags = fl_flags | FL_SLEEP;
547 if (do_vfs_lock(fl) < 0)
548 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
545 up_read(&host->h_rwsem); 549 up_read(&host->h_rwsem);
546 } 550 }
547 status = nlm_stat_to_errno(resp->status); 551 status = nlm_stat_to_errno(resp->status);
@@ -552,6 +556,7 @@ out_unblock:
552 nlmclnt_cancel(host, req->a_args.block, fl); 556 nlmclnt_cancel(host, req->a_args.block, fl);
553out: 557out:
554 nlm_release_call(req); 558 nlm_release_call(req);
559 fl->fl_flags = fl_flags;
555 return status; 560 return status;
556} 561}
557 562
@@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
606{ 611{
607 struct nlm_host *host = req->a_host; 612 struct nlm_host *host = req->a_host;
608 struct nlm_res *resp = &req->a_res; 613 struct nlm_res *resp = &req->a_res;
609 int status; 614 int status = 0;
610 615
611 /* 616 /*
612 * Note: the server is supposed to either grant us the unlock 617 * Note: the server is supposed to either grant us the unlock
613 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either 618 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either
614 * case, we want to unlock. 619 * case, we want to unlock.
615 */ 620 */
621 fl->fl_flags |= FL_EXISTS;
616 down_read(&host->h_rwsem); 622 down_read(&host->h_rwsem);
617 do_vfs_lock(fl); 623 if (do_vfs_lock(fl) == -ENOENT) {
624 up_read(&host->h_rwsem);
625 goto out;
626 }
618 up_read(&host->h_rwsem); 627 up_read(&host->h_rwsem);
619 628
620 if (req->a_flags & RPC_TASK_ASYNC) 629 if (req->a_flags & RPC_TASK_ASYNC)
@@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
624 if (status < 0) 633 if (status < 0)
625 goto out; 634 goto out;
626 635
627 status = 0;
628 if (resp->status == NLM_LCK_GRANTED) 636 if (resp->status == NLM_LCK_GRANTED)
629 goto out; 637 goto out;
630 638
diff --git a/fs/locks.c b/fs/locks.c
index 1ad29c9b6252..b0b41a64e10b 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -725,6 +725,10 @@ next_task:
725/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks 725/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks
726 * at the head of the list, but that's secret knowledge known only to 726 * at the head of the list, but that's secret knowledge known only to
727 * flock_lock_file and posix_lock_file. 727 * flock_lock_file and posix_lock_file.
728 *
729 * Note that if called with an FL_EXISTS argument, the caller may determine
730 * whether or not a lock was successfully freed by testing the return
731 * value for -ENOENT.
728 */ 732 */
729static int flock_lock_file(struct file *filp, struct file_lock *request) 733static int flock_lock_file(struct file *filp, struct file_lock *request)
730{ 734{
@@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
735 int found = 0; 739 int found = 0;
736 740
737 lock_kernel(); 741 lock_kernel();
742 if (request->fl_flags & FL_ACCESS)
743 goto find_conflict;
738 for_each_lock(inode, before) { 744 for_each_lock(inode, before) {
739 struct file_lock *fl = *before; 745 struct file_lock *fl = *before;
740 if (IS_POSIX(fl)) 746 if (IS_POSIX(fl))
@@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
750 break; 756 break;
751 } 757 }
752 758
753 if (request->fl_type == F_UNLCK) 759 if (request->fl_type == F_UNLCK) {
760 if ((request->fl_flags & FL_EXISTS) && !found)
761 error = -ENOENT;
754 goto out; 762 goto out;
763 }
755 764
756 error = -ENOMEM; 765 error = -ENOMEM;
757 new_fl = locks_alloc_lock(); 766 new_fl = locks_alloc_lock();
@@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
764 if (found) 773 if (found)
765 cond_resched(); 774 cond_resched();
766 775
776find_conflict:
767 for_each_lock(inode, before) { 777 for_each_lock(inode, before) {
768 struct file_lock *fl = *before; 778 struct file_lock *fl = *before;
769 if (IS_POSIX(fl)) 779 if (IS_POSIX(fl))
@@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
777 locks_insert_block(fl, request); 787 locks_insert_block(fl, request);
778 goto out; 788 goto out;
779 } 789 }
790 if (request->fl_flags & FL_ACCESS)
791 goto out;
780 locks_copy_lock(new_fl, request); 792 locks_copy_lock(new_fl, request);
781 locks_insert_lock(&inode->i_flock, new_fl); 793 locks_insert_lock(&inode->i_flock, new_fl);
782 new_fl = NULL; 794 new_fl = NULL;
@@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
948 960
949 error = 0; 961 error = 0;
950 if (!added) { 962 if (!added) {
951 if (request->fl_type == F_UNLCK) 963 if (request->fl_type == F_UNLCK) {
964 if (request->fl_flags & FL_EXISTS)
965 error = -ENOENT;
952 goto out; 966 goto out;
967 }
953 968
954 if (!new_fl) { 969 if (!new_fl) {
955 error = -ENOLCK; 970 error = -ENOLCK;
@@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request
996 * Add a POSIX style lock to a file. 1011 * Add a POSIX style lock to a file.
997 * We merge adjacent & overlapping locks whenever possible. 1012 * We merge adjacent & overlapping locks whenever possible.
998 * POSIX locks are sorted by owner task, then by starting address 1013 * POSIX locks are sorted by owner task, then by starting address
1014 *
1015 * Note that if called with an FL_EXISTS argument, the caller may determine
1016 * whether or not a lock was successfully freed by testing the return
1017 * value for -ENOENT.
999 */ 1018 */
1000int posix_lock_file(struct file *filp, struct file_lock *fl) 1019int posix_lock_file(struct file *filp, struct file_lock *fl)
1001{ 1020{
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index b4916b092194..e6ee97f19d81 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl)
3144 default: 3144 default:
3145 BUG(); 3145 BUG();
3146 } 3146 }
3147 if (res < 0)
3148 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
3149 __FUNCTION__);
3150 return res; 3147 return res;
3151} 3148}
3152 3149
@@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
3258 return ERR_PTR(-ENOMEM); 3255 return ERR_PTR(-ENOMEM);
3259 } 3256 }
3260 3257
3261 /* Unlock _before_ we do the RPC call */
3262 do_vfs_lock(fl->fl_file, fl);
3263 return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); 3258 return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);
3264} 3259}
3265 3260
@@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
3270 struct rpc_task *task; 3265 struct rpc_task *task;
3271 int status = 0; 3266 int status = 0;
3272 3267
3273 /* Is this a delegated lock? */
3274 if (test_bit(NFS_DELEGATED_STATE, &state->flags))
3275 goto out_unlock;
3276 /* Is this open_owner holding any locks on the server? */
3277 if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
3278 goto out_unlock;
3279
3280 status = nfs4_set_lock_state(state, request); 3268 status = nfs4_set_lock_state(state, request);
3269 /* Unlock _before_ we do the RPC call */
3270 request->fl_flags |= FL_EXISTS;
3271 if (do_vfs_lock(request->fl_file, request) == -ENOENT)
3272 goto out;
3281 if (status != 0) 3273 if (status != 0)
3282 goto out_unlock; 3274 goto out;
3275 /* Is this a delegated lock? */
3276 if (test_bit(NFS_DELEGATED_STATE, &state->flags))
3277 goto out;
3283 lsp = request->fl_u.nfs4_fl.owner; 3278 lsp = request->fl_u.nfs4_fl.owner;
3284 status = -ENOMEM;
3285 seqid = nfs_alloc_seqid(&lsp->ls_seqid); 3279 seqid = nfs_alloc_seqid(&lsp->ls_seqid);
3280 status = -ENOMEM;
3286 if (seqid == NULL) 3281 if (seqid == NULL)
3287 goto out_unlock; 3282 goto out;
3288 task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); 3283 task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);
3289 status = PTR_ERR(task); 3284 status = PTR_ERR(task);
3290 if (IS_ERR(task)) 3285 if (IS_ERR(task))
3291 goto out_unlock; 3286 goto out;
3292 status = nfs4_wait_for_completion_rpc_task(task); 3287 status = nfs4_wait_for_completion_rpc_task(task);
3293 rpc_release_task(task); 3288 rpc_release_task(task);
3294 return status; 3289out:
3295out_unlock:
3296 do_vfs_lock(request->fl_file, request);
3297 return status; 3290 return status;
3298} 3291}
3299 3292
@@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
3461 struct nfs4_exception exception = { }; 3454 struct nfs4_exception exception = { };
3462 int err; 3455 int err;
3463 3456
3464 /* Cache the lock if possible... */
3465 if (test_bit(NFS_DELEGATED_STATE, &state->flags))
3466 return 0;
3467 do { 3457 do {
3458 /* Cache the lock if possible... */
3459 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
3460 return 0;
3468 err = _nfs4_do_setlk(state, F_SETLK, request, 1); 3461 err = _nfs4_do_setlk(state, F_SETLK, request, 1);
3469 if (err != -NFS4ERR_DELAY) 3462 if (err != -NFS4ERR_DELAY)
3470 break; 3463 break;
@@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
3483 if (err != 0) 3476 if (err != 0)
3484 return err; 3477 return err;
3485 do { 3478 do {
3479 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
3480 return 0;
3486 err = _nfs4_do_setlk(state, F_SETLK, request, 0); 3481 err = _nfs4_do_setlk(state, F_SETLK, request, 0);
3487 if (err != -NFS4ERR_DELAY) 3482 if (err != -NFS4ERR_DELAY)
3488 break; 3483 break;
@@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
3494static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) 3489static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
3495{ 3490{
3496 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;
3497 int status; 3493 int status;
3498 3494
3499 /* Is this a delegated open? */ 3495 /* Is this a delegated open? */
3500 if (NFS_I(state->inode)->delegation_state != 0) {
3501 /* Yes: cache locks! */
3502 status = do_vfs_lock(request->fl_file, request);
3503 /* ...but avoid races with delegation recall... */
3504 if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))
3505 return status;
3506 }
3507 down_read(&clp->cl_sem);
3508 status = nfs4_set_lock_state(state, request); 3496 status = nfs4_set_lock_state(state, request);
3509 if (status != 0) 3497 if (status != 0)
3510 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 }
3511 status = _nfs4_do_setlk(state, cmd, request, 0); 3517 status = _nfs4_do_setlk(state, cmd, request, 0);
3512 if (status != 0) 3518 if (status != 0)
3513 goto out; 3519 goto out_unlock;
3514 /* Note: we always want to sleep here! */ 3520 /* Note: we always want to sleep here! */
3515 request->fl_flags |= FL_SLEEP; 3521 request->fl_flags = fl_flags | FL_SLEEP;
3516 if (do_vfs_lock(request->fl_file, request) < 0) 3522 if (do_vfs_lock(request->fl_file, request) < 0)
3517 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__);
3518out: 3524out_unlock:
3519 up_read(&clp->cl_sem); 3525 up_read(&clp->cl_sem);
3526out:
3527 request->fl_flags = fl_flags;
3520 return status; 3528 return status;
3521} 3529}
3522 3530
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 134b32068246..43aef9b230fd 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -716,6 +716,7 @@ extern spinlock_t files_lock;
716#define FL_POSIX 1 716#define FL_POSIX 1
717#define FL_FLOCK 2 717#define FL_FLOCK 2
718#define FL_ACCESS 8 /* not trying to lock, just looking */ 718#define FL_ACCESS 8 /* not trying to lock, just looking */
719#define FL_EXISTS 16 /* when unlocking, test for existence */
719#define FL_LEASE 32 /* lease held on this file */ 720#define FL_LEASE 32 /* lease held on this file */
720#define FL_CLOSE 64 /* unlock on close */ 721#define FL_CLOSE 64 /* unlock on close */
721#define FL_SLEEP 128 /* A blocking lock */ 722#define FL_SLEEP 128 /* A blocking lock */