···454454 fl->fl_ops = &nlmclnt_lock_ops;455455}456456457457-static void do_vfs_lock(struct file_lock *fl)457457+static int do_vfs_lock(struct file_lock *fl)458458{459459 int res = 0;460460 switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {···467467 default:468468 BUG();469469 }470470- if (res < 0)471471- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",472472- __FUNCTION__);470470+ return res;473471}474472475473/*···496498 struct nlm_host *host = req->a_host;497499 struct nlm_res *resp = &req->a_res;498500 struct nlm_wait *block = NULL;501501+ unsigned char fl_flags = fl->fl_flags;499502 int status = -ENOLCK;500503501504 if (!host->h_monitored && nsm_monitor(host) < 0) {···504505 host->h_name);505506 goto out;506507 }508508+ fl->fl_flags |= FL_ACCESS;509509+ status = do_vfs_lock(fl);510510+ if (status < 0)511511+ goto out;507512508513 block = nlmclnt_prepare_block(host, fl);509514again:···542539 up_read(&host->h_rwsem);543540 goto again;544541 }545545- fl->fl_flags |= FL_SLEEP;546542 /* Ensure the resulting lock will get added to granted list */547547- do_vfs_lock(fl);543543+ fl->fl_flags = fl_flags | FL_SLEEP;544544+ if (do_vfs_lock(fl) < 0)545545+ printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);548546 up_read(&host->h_rwsem);549547 }550548 status = nlm_stat_to_errno(resp->status);···556552 nlmclnt_cancel(host, req->a_args.block, fl);557553out:558554 nlm_release_call(req);555555+ fl->fl_flags = fl_flags;559556 return status;560557}561558···611606{612607 struct nlm_host *host = req->a_host;613608 struct nlm_res *resp = &req->a_res;614614- int status;609609+ int status = 0;615610616611 /*617612 * Note: the server is supposed to either grant us the unlock618613 * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either619614 * case, we want to unlock.620615 */616616+ fl->fl_flags |= FL_EXISTS;621617 down_read(&host->h_rwsem);622622- do_vfs_lock(fl);618618+ if (do_vfs_lock(fl) == -ENOENT) {619619+ up_read(&host->h_rwsem);620620+ goto out;621621+ }623622 up_read(&host->h_rwsem);624623625624 if (req->a_flags & RPC_TASK_ASYNC)···633624 if (status < 0)634625 goto out;635626636636- status = 0;637627 if (resp->status == NLM_LCK_GRANTED)638628 goto out;639629
+21-2
fs/locks.c
···725725/* Try to create a FLOCK lock on filp. We always insert new FLOCK locks726726 * at the head of the list, but that's secret knowledge known only to727727 * flock_lock_file and posix_lock_file.728728+ *729729+ * Note that if called with an FL_EXISTS argument, the caller may determine730730+ * whether or not a lock was successfully freed by testing the return731731+ * value for -ENOENT.728732 */729733static int flock_lock_file(struct file *filp, struct file_lock *request)730734{···739735 int found = 0;740736741737 lock_kernel();738738+ if (request->fl_flags & FL_ACCESS)739739+ goto find_conflict;742740 for_each_lock(inode, before) {743741 struct file_lock *fl = *before;744742 if (IS_POSIX(fl))···756750 break;757751 }758752759759- if (request->fl_type == F_UNLCK)753753+ if (request->fl_type == F_UNLCK) {754754+ if ((request->fl_flags & FL_EXISTS) && !found)755755+ error = -ENOENT;760756 goto out;757757+ }761758762759 error = -ENOMEM;763760 new_fl = locks_alloc_lock();···773764 if (found)774765 cond_resched();775766767767+find_conflict:776768 for_each_lock(inode, before) {777769 struct file_lock *fl = *before;778770 if (IS_POSIX(fl))···787777 locks_insert_block(fl, request);788778 goto out;789779 }780780+ if (request->fl_flags & FL_ACCESS)781781+ goto out;790782 locks_copy_lock(new_fl, request);791783 locks_insert_lock(&inode->i_flock, new_fl);792784 new_fl = NULL;···960948961949 error = 0;962950 if (!added) {963963- if (request->fl_type == F_UNLCK)951951+ if (request->fl_type == F_UNLCK) {952952+ if (request->fl_flags & FL_EXISTS)953953+ error = -ENOENT;964954 goto out;955955+ }965956966957 if (!new_fl) {967958 error = -ENOLCK;···1011996 * Add a POSIX style lock to a file.1012997 * We merge adjacent & overlapping locks whenever possible.1013998 * POSIX locks are sorted by owner task, then by starting address999999+ *10001000+ * Note that if called with an FL_EXISTS argument, the caller may determine10011001+ * whether or not a lock was successfully freed by testing the return10021002+ * value for -ENOENT.10141003 */10151004int posix_lock_file(struct file *filp, struct file_lock *fl)10161005{
+41-33
fs/nfs/nfs4proc.c
···31443144 default:31453145 BUG();31463146 }31473147- if (res < 0)31483148- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",31493149- __FUNCTION__);31503147 return res;31513148}31523149···32553258 return ERR_PTR(-ENOMEM);32563259 }3257326032583258- /* Unlock _before_ we do the RPC call */32593259- do_vfs_lock(fl->fl_file, fl);32603261 return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data);32613262}32623263···32653270 struct rpc_task *task;32663271 int status = 0;3267327232733273+ status = nfs4_set_lock_state(state, request);32743274+ /* Unlock _before_ we do the RPC call */32753275+ request->fl_flags |= FL_EXISTS;32763276+ if (do_vfs_lock(request->fl_file, request) == -ENOENT)32773277+ goto out;32783278+ if (status != 0)32793279+ goto out;32683280 /* Is this a delegated lock? */32693281 if (test_bit(NFS_DELEGATED_STATE, &state->flags))32703270- goto out_unlock;32713271- /* Is this open_owner holding any locks on the server? */32723272- if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)32733273- goto out_unlock;32743274-32753275- status = nfs4_set_lock_state(state, request);32763276- if (status != 0)32773277- goto out_unlock;32823282+ goto out;32783283 lsp = request->fl_u.nfs4_fl.owner;32793279- status = -ENOMEM;32803284 seqid = nfs_alloc_seqid(&lsp->ls_seqid);32853285+ status = -ENOMEM;32813286 if (seqid == NULL)32823282- goto out_unlock;32873287+ goto out;32833288 task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid);32843289 status = PTR_ERR(task);32853290 if (IS_ERR(task))32863286- goto out_unlock;32913291+ goto out;32873292 status = nfs4_wait_for_completion_rpc_task(task);32883293 rpc_release_task(task);32893289- return status;32903290-out_unlock:32913291- do_vfs_lock(request->fl_file, request);32943294+out:32923295 return status;32933296}32943297···34543461 struct nfs4_exception exception = { };34553462 int err;3456346334573457- /* Cache the lock if possible... */34583458- if (test_bit(NFS_DELEGATED_STATE, &state->flags))34593459- return 0;34603464 do {34653465+ /* Cache the lock if possible... */34663466+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)34673467+ return 0;34613468 err = _nfs4_do_setlk(state, F_SETLK, request, 1);34623469 if (err != -NFS4ERR_DELAY)34633470 break;···34763483 if (err != 0)34773484 return err;34783485 do {34863486+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)34873487+ return 0;34793488 err = _nfs4_do_setlk(state, F_SETLK, request, 0);34803489 if (err != -NFS4ERR_DELAY)34813490 break;···34893494static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)34903495{34913496 struct nfs4_client *clp = state->owner->so_client;34973497+ unsigned char fl_flags = request->fl_flags;34923498 int status;3493349934943500 /* Is this a delegated open? */34953495- if (NFS_I(state->inode)->delegation_state != 0) {34963496- /* Yes: cache locks! */34973497- status = do_vfs_lock(request->fl_file, request);34983498- /* ...but avoid races with delegation recall... */34993499- if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags))35003500- return status;35013501- }35023502- down_read(&clp->cl_sem);35033501 status = nfs4_set_lock_state(state, request);35043502 if (status != 0)35053503 goto out;35043504+ request->fl_flags |= FL_ACCESS;35053505+ status = do_vfs_lock(request->fl_file, request);35063506+ if (status < 0)35073507+ goto out;35083508+ down_read(&clp->cl_sem);35093509+ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {35103510+ struct nfs_inode *nfsi = NFS_I(state->inode);35113511+ /* Yes: cache locks! */35123512+ down_read(&nfsi->rwsem);35133513+ /* ...but avoid races with delegation recall... */35143514+ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {35153515+ request->fl_flags = fl_flags & ~FL_SLEEP;35163516+ status = do_vfs_lock(request->fl_file, request);35173517+ up_read(&nfsi->rwsem);35183518+ goto out_unlock;35193519+ }35203520+ up_read(&nfsi->rwsem);35213521+ }35063522 status = _nfs4_do_setlk(state, cmd, request, 0);35073523 if (status != 0)35083508- goto out;35243524+ goto out_unlock;35093525 /* Note: we always want to sleep here! */35103510- request->fl_flags |= FL_SLEEP;35263526+ request->fl_flags = fl_flags | FL_SLEEP;35113527 if (do_vfs_lock(request->fl_file, request) < 0)35123528 printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);35133513-out:35293529+out_unlock:35143530 up_read(&clp->cl_sem);35313531+out:35323532+ request->fl_flags = fl_flags;35153533 return status;35163534}35173535
+1
include/linux/fs.h
···716716#define FL_POSIX 1717717#define FL_FLOCK 2718718#define FL_ACCESS 8 /* not trying to lock, just looking */719719+#define FL_EXISTS 16 /* when unlocking, test for existence */719720#define FL_LEASE 32 /* lease held on this file */720721#define FL_CLOSE 64 /* unlock on close */721722#define FL_SLEEP 128 /* A blocking lock */