diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-05 13:19:25 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-05 13:19:25 -0400 |
| commit | 72dbac37e3a0acf8e8f07fc65e34e83de83e0b28 (patch) | |
| tree | 4f70bea9d6e8098c13a8cc89806a1e569737ad13 | |
| parent | 4e0641a7ad98fca5646a6be17605bc80f6c4ebde (diff) | |
| parent | 01c3b861cd77b28565a2d18c7caa3ce7f938e35c (diff) | |
Merge branch 'locks'
| -rw-r--r-- | fs/lockd/clntproc.c | 26 | ||||
| -rw-r--r-- | fs/locks.c | 23 | ||||
| -rw-r--r-- | fs/nfs/nfs4proc.c | 74 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 |
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 | ||
| 457 | static void do_vfs_lock(struct file_lock *fl) | 457 | static 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); |
| 510 | again: | 513 | again: |
| @@ -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); |
| 553 | out: | 557 | out: |
| 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 | */ |
| 729 | static int flock_lock_file(struct file *filp, struct file_lock *request) | 733 | static 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 | ||
| 776 | find_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 | */ |
| 1000 | int posix_lock_file(struct file *filp, struct file_lock *fl) | 1019 | int 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; | 3289 | out: |
| 3295 | out_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 | |||
| 3494 | 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) |
| 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__); |
| 3518 | out: | 3524 | out_unlock: |
| 3519 | up_read(&clp->cl_sem); | 3525 | up_read(&clp->cl_sem); |
| 3526 | out: | ||
| 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 */ |
