···454 fl->fl_ops = &nlmclnt_lock_ops;455}456457-static void do_vfs_lock(struct file_lock *fl)458{459 int res = 0;460 switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {···467 default:468 BUG();469 }470- if (res < 0)471- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",472- __FUNCTION__);473}474475/*···496 struct nlm_host *host = req->a_host;497 struct nlm_res *resp = &req->a_res;498 struct nlm_wait *block = NULL;0499 int status = -ENOLCK;500501 if (!host->h_monitored && nsm_monitor(host) < 0) {···504 host->h_name);505 goto out;506 }0000507508 block = nlmclnt_prepare_block(host, fl);509again:···542 up_read(&host->h_rwsem);543 goto again;544 }545- fl->fl_flags |= FL_SLEEP;546 /* Ensure the resulting lock will get added to granted list */547- do_vfs_lock(fl);00548 up_read(&host->h_rwsem);549 }550 status = nlm_stat_to_errno(resp->status);···556 nlmclnt_cancel(host, req->a_args.block, fl);557out:558 nlm_release_call(req);0559 return status;560}561···611{612 struct nlm_host *host = req->a_host;613 struct nlm_res *resp = &req->a_res;614- int status;615616 /*617 * Note: the server is supposed to either grant us the unlock618 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either619 * case, we want to unlock.620 */0621 down_read(&host->h_rwsem);622- do_vfs_lock(fl);000623 up_read(&host->h_rwsem);624625 if (req->a_flags & RPC_TASK_ASYNC)···633 if (status < 0)634 goto out;635636- status = 0;637 if (resp->status == NLM_LCK_GRANTED)638 goto out;639
···454 fl->fl_ops = &nlmclnt_lock_ops;455}456457+static int do_vfs_lock(struct file_lock *fl)458{459 int res = 0;460 switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {···467 default:468 BUG();469 }470+ return res;00471}472473/*···498 struct nlm_host *host = req->a_host;499 struct nlm_res *resp = &req->a_res;500 struct nlm_wait *block = NULL;501+ unsigned char fl_flags = fl->fl_flags;502 int status = -ENOLCK;503504 if (!host->h_monitored && nsm_monitor(host) < 0) {···505 host->h_name);506 goto out;507 }508+ fl->fl_flags |= FL_ACCESS;509+ status = do_vfs_lock(fl);510+ if (status < 0)511+ goto out;512513 block = nlmclnt_prepare_block(host, fl);514again:···539 up_read(&host->h_rwsem);540 goto again;541 }0542 /* Ensure the resulting lock will get added to granted list */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__);546 up_read(&host->h_rwsem);547 }548 status = nlm_stat_to_errno(resp->status);···552 nlmclnt_cancel(host, req->a_args.block, fl);553out:554 nlm_release_call(req);555+ fl->fl_flags = fl_flags;556 return status;557}558···606{607 struct nlm_host *host = req->a_host;608 struct nlm_res *resp = &req->a_res;609+ int status = 0;610611 /*612 * Note: the server is supposed to either grant us the unlock613 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either614 * case, we want to unlock.615 */616+ fl->fl_flags |= FL_EXISTS;617 down_read(&host->h_rwsem);618+ if (do_vfs_lock(fl) == -ENOENT) {619+ up_read(&host->h_rwsem);620+ goto out;621+ }622 up_read(&host->h_rwsem);623624 if (req->a_flags & RPC_TASK_ASYNC)···624 if (status < 0)625 goto out;6260627 if (resp->status == NLM_LCK_GRANTED)628 goto out;629
+21-2
fs/locks.c
···725/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks726 * at the head of the list, but that's secret knowledge known only to727 * flock_lock_file and posix_lock_file.0000728 */729static int flock_lock_file(struct file *filp, struct file_lock *request)730{···739 int found = 0;740741 lock_kernel();00742 for_each_lock(inode, before) {743 struct file_lock *fl = *before;744 if (IS_POSIX(fl))···756 break;757 }758759- if (request->fl_type == F_UNLCK)00760 goto out;0761762 error = -ENOMEM;763 new_fl = locks_alloc_lock();···773 if (found)774 cond_resched();7750776 for_each_lock(inode, before) {777 struct file_lock *fl = *before;778 if (IS_POSIX(fl))···787 locks_insert_block(fl, request);788 goto out;789 }00790 locks_copy_lock(new_fl, request);791 locks_insert_lock(&inode->i_flock, new_fl);792 new_fl = NULL;···960961 error = 0;962 if (!added) {963- if (request->fl_type == F_UNLCK)00964 goto out;0965966 if (!new_fl) {967 error = -ENOLCK;···1011 * Add a POSIX style lock to a file.1012 * We merge adjacent & overlapping locks whenever possible.1013 * POSIX locks are sorted by owner task, then by starting address00001014 */1015int posix_lock_file(struct file *filp, struct file_lock *fl)1016{
···725/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks726 * at the head of the list, but that's secret knowledge known only to727 * flock_lock_file and posix_lock_file.728+ *729+ * Note that if called with an FL_EXISTS argument, the caller may determine730+ * whether or not a lock was successfully freed by testing the return731+ * value for -ENOENT.732 */733static int flock_lock_file(struct file *filp, struct file_lock *request)734{···735 int found = 0;736737 lock_kernel();738+ if (request->fl_flags & FL_ACCESS)739+ goto find_conflict;740 for_each_lock(inode, before) {741 struct file_lock *fl = *before;742 if (IS_POSIX(fl))···750 break;751 }752753+ if (request->fl_type == F_UNLCK) {754+ if ((request->fl_flags & FL_EXISTS) && !found)755+ error = -ENOENT;756 goto out;757+ }758759 error = -ENOMEM;760 new_fl = locks_alloc_lock();···764 if (found)765 cond_resched();766767+find_conflict:768 for_each_lock(inode, before) {769 struct file_lock *fl = *before;770 if (IS_POSIX(fl))···777 locks_insert_block(fl, request);778 goto out;779 }780+ if (request->fl_flags & FL_ACCESS)781+ goto out;782 locks_copy_lock(new_fl, request);783 locks_insert_lock(&inode->i_flock, new_fl);784 new_fl = NULL;···948949 error = 0;950 if (!added) {951+ if (request->fl_type == F_UNLCK) {952+ if (request->fl_flags & FL_EXISTS)953+ error = -ENOENT;954 goto out;955+ }956957 if (!new_fl) {958 error = -ENOLCK;···996 * Add a POSIX style lock to a file.997 * We merge adjacent & overlapping locks whenever possible.998 * POSIX locks are sorted by owner task, then by starting address999+ *1000+ * Note that if called with an FL_EXISTS argument, the caller may determine1001+ * whether or not a lock was successfully freed by testing the return1002+ * value for -ENOENT.1003 */1004int posix_lock_file(struct file *filp, struct file_lock *fl)1005{
+41-33
fs/nfs/nfs4proc.c
···3144 default:3145 BUG();3146 }3147- if (res < 0)3148- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",3149- __FUNCTION__);3150 return res;3151}3152···3255 return ERR_PTR(-ENOMEM);3256 }32573258- /* Unlock _before_ we do the RPC call */3259- do_vfs_lock(fl->fl_file, fl);3260 return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);3261}3262···3265 struct rpc_task *task;3266 int status = 0;326700000003268 /* Is this a delegated lock? */3269 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;3278 lsp = request->fl_u.nfs4_fl.owner;3279- status = -ENOMEM;3280 seqid = nfs_alloc_seqid(&lsp->ls_seqid);03281 if (seqid == NULL)3282- goto out_unlock;3283 task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);3284 status = PTR_ERR(task);3285 if (IS_ERR(task))3286- goto out_unlock;3287 status = nfs4_wait_for_completion_rpc_task(task);3288 rpc_release_task(task);3289- return status;3290-out_unlock:3291- do_vfs_lock(request->fl_file, request);3292 return status;3293}3294···3454 struct nfs4_exception exception = { };3455 int err;34563457- /* Cache the lock if possible... */3458- if (test_bit(NFS_DELEGATED_STATE, &state->flags))3459- return 0;3460 do {0003461 err = _nfs4_do_setlk(state, F_SETLK, request, 1);3462 if (err != -NFS4ERR_DELAY)3463 break;···3476 if (err != 0)3477 return err;3478 do {003479 err = _nfs4_do_setlk(state, F_SETLK, request, 0);3480 if (err != -NFS4ERR_DELAY)3481 break;···3489static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)3490{3491 struct nfs4_client *clp = state->owner->so_client;03492 int status;34933494 /* 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);3504 if (status != 0)3505 goto out;0000000000000000003506 status = _nfs4_do_setlk(state, cmd, request, 0);3507 if (status != 0)3508- goto out;3509 /* Note: we always want to sleep here! */3510- request->fl_flags |= FL_SLEEP;3511 if (do_vfs_lock(request->fl_file, request) < 0)3512 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);3513-out:3514 up_read(&clp->cl_sem);003515 return status;3516}3517
···3144 default:3145 BUG();3146 }0003147 return res;3148}3149···3258 return ERR_PTR(-ENOMEM);3259 }3260003261 return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);3262}3263···3270 struct rpc_task *task;3271 int status = 0;32723273+ 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;3280 /* Is this a delegated lock? */3281 if (test_bit(NFS_DELEGATED_STATE, &state->flags))3282+ goto out;00000003283 lsp = request->fl_u.nfs4_fl.owner;03284 seqid = nfs_alloc_seqid(&lsp->ls_seqid);3285+ status = -ENOMEM;3286 if (seqid == NULL)3287+ goto out;3288 task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);3289 status = PTR_ERR(task);3290 if (IS_ERR(task))3291+ goto out;3292 status = nfs4_wait_for_completion_rpc_task(task);3293 rpc_release_task(task);3294+out:003295 return status;3296}3297···3461 struct nfs4_exception exception = { };3462 int err;34630003464 do {3465+ /* Cache the lock if possible... */3466+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)3467+ return 0;3468 err = _nfs4_do_setlk(state, F_SETLK, request, 1);3469 if (err != -NFS4ERR_DELAY)3470 break;···3483 if (err != 0)3484 return err;3485 do {3486+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)3487+ return 0;3488 err = _nfs4_do_setlk(state, F_SETLK, request, 0);3489 if (err != -NFS4ERR_DELAY)3490 break;···3494static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)3495{3496 struct nfs4_client *clp = state->owner->so_client;3497+ unsigned char fl_flags = request->fl_flags;3498 int status;34993500 /* Is this a delegated open? */000000003501 status = nfs4_set_lock_state(state, request);3502 if (status != 0)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+ }3522 status = _nfs4_do_setlk(state, cmd, request, 0);3523 if (status != 0)3524+ goto out_unlock;3525 /* Note: we always want to sleep here! */3526+ request->fl_flags = fl_flags | FL_SLEEP;3527 if (do_vfs_lock(request->fl_file, request) < 0)3528 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);3529+out_unlock:3530 up_read(&clp->cl_sem);3531+out:3532+ request->fl_flags = fl_flags;3533 return status;3534}3535
+1
include/linux/fs.h
···716#define FL_POSIX 1717#define FL_FLOCK 2718#define FL_ACCESS 8 /* not trying to lock, just looking */0719#define FL_LEASE 32 /* lease held on this file */720#define FL_CLOSE 64 /* unlock on close */721#define FL_SLEEP 128 /* A blocking lock */
···716#define FL_POSIX 1717#define FL_FLOCK 2718#define FL_ACCESS 8 /* not trying to lock, just looking */719+#define FL_EXISTS 16 /* when unlocking, test for existence */720#define FL_LEASE 32 /* lease held on this file */721#define FL_CLOSE 64 /* unlock on close */722#define FL_SLEEP 128 /* A blocking lock */