Loading fs/lockd/clntproc.c +17 −9 Original line number Diff line number Diff line Loading @@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho fl->fl_ops = &nlmclnt_lock_ops; } static void do_vfs_lock(struct file_lock *fl) static int do_vfs_lock(struct file_lock *fl) { int res = 0; switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { Loading @@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl) default: BUG(); } if (res < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); return res; } /* Loading Loading @@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) struct nlm_host *host = req->a_host; struct nlm_res *resp = &req->a_res; struct nlm_wait *block = NULL; unsigned char fl_flags = fl->fl_flags; int status = -ENOLCK; if (!host->h_monitored && nsm_monitor(host) < 0) { Loading @@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) host->h_name); goto out; } fl->fl_flags |= FL_ACCESS; status = do_vfs_lock(fl); if (status < 0) goto out; block = nlmclnt_prepare_block(host, fl); again: Loading Loading @@ -539,9 +542,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) up_read(&host->h_rwsem); goto again; } fl->fl_flags |= FL_SLEEP; /* Ensure the resulting lock will get added to granted list */ do_vfs_lock(fl); fl->fl_flags = fl_flags | FL_SLEEP; if (do_vfs_lock(fl) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); up_read(&host->h_rwsem); } status = nlm_stat_to_errno(resp->status); Loading @@ -552,6 +556,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) nlmclnt_cancel(host, req->a_args.block, fl); out: nlm_release_call(req); fl->fl_flags = fl_flags; return status; } Loading Loading @@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_host *host = req->a_host; struct nlm_res *resp = &req->a_res; int status; int status = 0; /* * Note: the server is supposed to either grant us the unlock * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either * case, we want to unlock. */ fl->fl_flags |= FL_EXISTS; down_read(&host->h_rwsem); do_vfs_lock(fl); if (do_vfs_lock(fl) == -ENOENT) { up_read(&host->h_rwsem); goto out; } up_read(&host->h_rwsem); if (req->a_flags & RPC_TASK_ASYNC) Loading @@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) if (status < 0) goto out; status = 0; if (resp->status == NLM_LCK_GRANTED) goto out; Loading fs/locks.c +21 −2 Original line number Diff line number Diff line Loading @@ -725,6 +725,10 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks * at the head of the list, but that's secret knowledge known only to * flock_lock_file and posix_lock_file. * * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return * value for -ENOENT. */ static int flock_lock_file(struct file *filp, struct file_lock *request) { Loading @@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) int found = 0; lock_kernel(); if (request->fl_flags & FL_ACCESS) goto find_conflict; for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) Loading @@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) break; } if (request->fl_type == F_UNLCK) if (request->fl_type == F_UNLCK) { if ((request->fl_flags & FL_EXISTS) && !found) error = -ENOENT; goto out; } error = -ENOMEM; new_fl = locks_alloc_lock(); Loading @@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) if (found) cond_resched(); find_conflict: for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) Loading @@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) locks_insert_block(fl, request); goto out; } if (request->fl_flags & FL_ACCESS) goto out; locks_copy_lock(new_fl, request); locks_insert_lock(&inode->i_flock, new_fl); new_fl = NULL; Loading Loading @@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request error = 0; if (!added) { if (request->fl_type == F_UNLCK) if (request->fl_type == F_UNLCK) { if (request->fl_flags & FL_EXISTS) error = -ENOENT; goto out; } if (!new_fl) { error = -ENOLCK; Loading Loading @@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request * Add a POSIX style lock to a file. * We merge adjacent & overlapping locks whenever possible. * POSIX locks are sorted by owner task, then by starting address * * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return * value for -ENOENT. */ int posix_lock_file(struct file *filp, struct file_lock *fl) { Loading fs/nfs/nfs4proc.c +41 −33 Original line number Diff line number Diff line Loading @@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) default: BUG(); } if (res < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); return res; } Loading Loading @@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, return ERR_PTR(-ENOMEM); } /* Unlock _before_ we do the RPC call */ do_vfs_lock(fl->fl_file, fl); return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); } Loading @@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * struct rpc_task *task; int status = 0; /* Is this a delegated lock? */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) goto out_unlock; /* Is this open_owner holding any locks on the server? */ if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) goto out_unlock; status = nfs4_set_lock_state(state, request); /* Unlock _before_ we do the RPC call */ request->fl_flags |= FL_EXISTS; if (do_vfs_lock(request->fl_file, request) == -ENOENT) goto out; if (status != 0) goto out_unlock; goto out; /* Is this a delegated lock? */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) goto out; lsp = request->fl_u.nfs4_fl.owner; status = -ENOMEM; seqid = nfs_alloc_seqid(&lsp->ls_seqid); status = -ENOMEM; if (seqid == NULL) goto out_unlock; goto out; task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); status = PTR_ERR(task); if (IS_ERR(task)) goto out_unlock; goto out; status = nfs4_wait_for_completion_rpc_task(task); rpc_release_task(task); return status; out_unlock: do_vfs_lock(request->fl_file, request); out: return status; } Loading Loading @@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request struct nfs4_exception exception = { }; int err; do { /* Cache the lock if possible... */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) return 0; do { err = _nfs4_do_setlk(state, F_SETLK, request, 1); if (err != -NFS4ERR_DELAY) break; Loading @@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request if (err != 0) return err; do { if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) return 0; err = _nfs4_do_setlk(state, F_SETLK, request, 0); if (err != -NFS4ERR_DELAY) break; Loading @@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) { struct nfs4_client *clp = state->owner->so_client; unsigned char fl_flags = request->fl_flags; int status; /* Is this a delegated open? */ if (NFS_I(state->inode)->delegation_state != 0) { /* Yes: cache locks! */ status = do_vfs_lock(request->fl_file, request); /* ...but avoid races with delegation recall... */ if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags)) return status; } down_read(&clp->cl_sem); status = nfs4_set_lock_state(state, request); if (status != 0) goto out; request->fl_flags |= FL_ACCESS; status = do_vfs_lock(request->fl_file, request); if (status < 0) goto out; down_read(&clp->cl_sem); if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { struct nfs_inode *nfsi = NFS_I(state->inode); /* Yes: cache locks! */ down_read(&nfsi->rwsem); /* ...but avoid races with delegation recall... */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { request->fl_flags = fl_flags & ~FL_SLEEP; status = do_vfs_lock(request->fl_file, request); up_read(&nfsi->rwsem); goto out_unlock; } up_read(&nfsi->rwsem); } status = _nfs4_do_setlk(state, cmd, request, 0); if (status != 0) goto out; goto out_unlock; /* Note: we always want to sleep here! */ request->fl_flags |= FL_SLEEP; request->fl_flags = fl_flags | FL_SLEEP; if (do_vfs_lock(request->fl_file, request) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); out: out_unlock: up_read(&clp->cl_sem); out: request->fl_flags = fl_flags; return status; } Loading include/linux/fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -716,6 +716,7 @@ extern spinlock_t files_lock; #define FL_POSIX 1 #define FL_FLOCK 2 #define FL_ACCESS 8 /* not trying to lock, just looking */ #define FL_EXISTS 16 /* when unlocking, test for existence */ #define FL_LEASE 32 /* lease held on this file */ #define FL_CLOSE 64 /* unlock on close */ #define FL_SLEEP 128 /* A blocking lock */ Loading Loading
fs/lockd/clntproc.c +17 −9 Original line number Diff line number Diff line Loading @@ -454,7 +454,7 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho fl->fl_ops = &nlmclnt_lock_ops; } static void do_vfs_lock(struct file_lock *fl) static int do_vfs_lock(struct file_lock *fl) { int res = 0; switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) { Loading @@ -467,9 +467,7 @@ static void do_vfs_lock(struct file_lock *fl) default: BUG(); } if (res < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); return res; } /* Loading Loading @@ -498,6 +496,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) struct nlm_host *host = req->a_host; struct nlm_res *resp = &req->a_res; struct nlm_wait *block = NULL; unsigned char fl_flags = fl->fl_flags; int status = -ENOLCK; if (!host->h_monitored && nsm_monitor(host) < 0) { Loading @@ -505,6 +504,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) host->h_name); goto out; } fl->fl_flags |= FL_ACCESS; status = do_vfs_lock(fl); if (status < 0) goto out; block = nlmclnt_prepare_block(host, fl); again: Loading Loading @@ -539,9 +542,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) up_read(&host->h_rwsem); goto again; } fl->fl_flags |= FL_SLEEP; /* Ensure the resulting lock will get added to granted list */ do_vfs_lock(fl); fl->fl_flags = fl_flags | FL_SLEEP; if (do_vfs_lock(fl) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); up_read(&host->h_rwsem); } status = nlm_stat_to_errno(resp->status); Loading @@ -552,6 +556,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) nlmclnt_cancel(host, req->a_args.block, fl); out: nlm_release_call(req); fl->fl_flags = fl_flags; return status; } Loading Loading @@ -606,15 +611,19 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) { struct nlm_host *host = req->a_host; struct nlm_res *resp = &req->a_res; int status; int status = 0; /* * Note: the server is supposed to either grant us the unlock * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either * case, we want to unlock. */ fl->fl_flags |= FL_EXISTS; down_read(&host->h_rwsem); do_vfs_lock(fl); if (do_vfs_lock(fl) == -ENOENT) { up_read(&host->h_rwsem); goto out; } up_read(&host->h_rwsem); if (req->a_flags & RPC_TASK_ASYNC) Loading @@ -624,7 +633,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) if (status < 0) goto out; status = 0; if (resp->status == NLM_LCK_GRANTED) goto out; Loading
fs/locks.c +21 −2 Original line number Diff line number Diff line Loading @@ -725,6 +725,10 @@ static int posix_locks_deadlock(struct file_lock *caller_fl, /* Try to create a FLOCK lock on filp. We always insert new FLOCK locks * at the head of the list, but that's secret knowledge known only to * flock_lock_file and posix_lock_file. * * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return * value for -ENOENT. */ static int flock_lock_file(struct file *filp, struct file_lock *request) { Loading @@ -735,6 +739,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) int found = 0; lock_kernel(); if (request->fl_flags & FL_ACCESS) goto find_conflict; for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) Loading @@ -750,8 +756,11 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) break; } if (request->fl_type == F_UNLCK) if (request->fl_type == F_UNLCK) { if ((request->fl_flags & FL_EXISTS) && !found) error = -ENOENT; goto out; } error = -ENOMEM; new_fl = locks_alloc_lock(); Loading @@ -764,6 +773,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) if (found) cond_resched(); find_conflict: for_each_lock(inode, before) { struct file_lock *fl = *before; if (IS_POSIX(fl)) Loading @@ -777,6 +787,8 @@ static int flock_lock_file(struct file *filp, struct file_lock *request) locks_insert_block(fl, request); goto out; } if (request->fl_flags & FL_ACCESS) goto out; locks_copy_lock(new_fl, request); locks_insert_lock(&inode->i_flock, new_fl); new_fl = NULL; Loading Loading @@ -948,8 +960,11 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request error = 0; if (!added) { if (request->fl_type == F_UNLCK) if (request->fl_type == F_UNLCK) { if (request->fl_flags & FL_EXISTS) error = -ENOENT; goto out; } if (!new_fl) { error = -ENOLCK; Loading Loading @@ -996,6 +1011,10 @@ static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request * Add a POSIX style lock to a file. * We merge adjacent & overlapping locks whenever possible. * POSIX locks are sorted by owner task, then by starting address * * Note that if called with an FL_EXISTS argument, the caller may determine * whether or not a lock was successfully freed by testing the return * value for -ENOENT. */ int posix_lock_file(struct file *filp, struct file_lock *fl) { Loading
fs/nfs/nfs4proc.c +41 −33 Original line number Diff line number Diff line Loading @@ -3144,9 +3144,6 @@ static int do_vfs_lock(struct file *file, struct file_lock *fl) default: BUG(); } if (res < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); return res; } Loading Loading @@ -3258,8 +3255,6 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl, return ERR_PTR(-ENOMEM); } /* Unlock _before_ we do the RPC call */ do_vfs_lock(fl->fl_file, fl); return rpc_run_task(NFS_CLIENT(lsp->ls_state->inode), RPC_TASK_ASYNC, &nfs4_locku_ops, data); } Loading @@ -3270,30 +3265,28 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock * struct rpc_task *task; int status = 0; /* Is this a delegated lock? */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) goto out_unlock; /* Is this open_owner holding any locks on the server? */ if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) goto out_unlock; status = nfs4_set_lock_state(state, request); /* Unlock _before_ we do the RPC call */ request->fl_flags |= FL_EXISTS; if (do_vfs_lock(request->fl_file, request) == -ENOENT) goto out; if (status != 0) goto out_unlock; goto out; /* Is this a delegated lock? */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) goto out; lsp = request->fl_u.nfs4_fl.owner; status = -ENOMEM; seqid = nfs_alloc_seqid(&lsp->ls_seqid); status = -ENOMEM; if (seqid == NULL) goto out_unlock; goto out; task = nfs4_do_unlck(request, request->fl_file->private_data, lsp, seqid); status = PTR_ERR(task); if (IS_ERR(task)) goto out_unlock; goto out; status = nfs4_wait_for_completion_rpc_task(task); rpc_release_task(task); return status; out_unlock: do_vfs_lock(request->fl_file, request); out: return status; } Loading Loading @@ -3461,10 +3454,10 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request struct nfs4_exception exception = { }; int err; do { /* Cache the lock if possible... */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) return 0; do { err = _nfs4_do_setlk(state, F_SETLK, request, 1); if (err != -NFS4ERR_DELAY) break; Loading @@ -3483,6 +3476,8 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request if (err != 0) return err; do { if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) return 0; err = _nfs4_do_setlk(state, F_SETLK, request, 0); if (err != -NFS4ERR_DELAY) break; Loading @@ -3494,29 +3489,42 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) { struct nfs4_client *clp = state->owner->so_client; unsigned char fl_flags = request->fl_flags; int status; /* Is this a delegated open? */ if (NFS_I(state->inode)->delegation_state != 0) { /* Yes: cache locks! */ status = do_vfs_lock(request->fl_file, request); /* ...but avoid races with delegation recall... */ if (status < 0 || test_bit(NFS_DELEGATED_STATE, &state->flags)) return status; } down_read(&clp->cl_sem); status = nfs4_set_lock_state(state, request); if (status != 0) goto out; request->fl_flags |= FL_ACCESS; status = do_vfs_lock(request->fl_file, request); if (status < 0) goto out; down_read(&clp->cl_sem); if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { struct nfs_inode *nfsi = NFS_I(state->inode); /* Yes: cache locks! */ down_read(&nfsi->rwsem); /* ...but avoid races with delegation recall... */ if (test_bit(NFS_DELEGATED_STATE, &state->flags)) { request->fl_flags = fl_flags & ~FL_SLEEP; status = do_vfs_lock(request->fl_file, request); up_read(&nfsi->rwsem); goto out_unlock; } up_read(&nfsi->rwsem); } status = _nfs4_do_setlk(state, cmd, request, 0); if (status != 0) goto out; goto out_unlock; /* Note: we always want to sleep here! */ request->fl_flags |= FL_SLEEP; request->fl_flags = fl_flags | FL_SLEEP; if (do_vfs_lock(request->fl_file, request) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); out: out_unlock: up_read(&clp->cl_sem); out: request->fl_flags = fl_flags; return status; } Loading
include/linux/fs.h +1 −0 Original line number Diff line number Diff line Loading @@ -716,6 +716,7 @@ extern spinlock_t files_lock; #define FL_POSIX 1 #define FL_FLOCK 2 #define FL_ACCESS 8 /* not trying to lock, just looking */ #define FL_EXISTS 16 /* when unlocking, test for existence */ #define FL_LEASE 32 /* lease held on this file */ #define FL_CLOSE 64 /* unlock on close */ #define FL_SLEEP 128 /* A blocking lock */ Loading