Merge branch 'locks'

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