* [PATCH 0/8] NLM client improvements for 2.6.26
@ 2008-04-03 22:39 Trond Myklebust
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
0 siblings, 1 reply; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
The following series applies on top of the 'devel' branch of the NFS
client git tree (git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git).
Most of the series is attempting to fix up the ability to interrupt NLM
locking requests, and to eliminate an existing bug whereby a non-fatal
signal to a process may cause it to set a local lock (one that doesn't
exist on the server) that doesn't get cleared.
The series also includes updated versions of the patches that I
suggested to fix the problem that Peter Staubach reported w.r.t.
UNLOCK requests being sent asynchronously when a process exits. The
previous patches had the problem that they also made the GRANTED
callback from the server synchronous, which is undesirable.
Finally, the last patch in the series is really more of a contination
of the generic credentials patches. It uses the generic credential to
ensure that NLM requests are authenticated to the same identity as the
open() call used.
Cheers
Trond
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/8] NLM/lockd: Ensure we don't corrupt fl->fl_flags in nlmclnt_unlock()
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
@ 2008-04-03 22:39 ` Trond Myklebust
[not found] ` <20080403223921.12713.20317.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
2008-04-03 22:39 ` [PATCH 2/8] NLM/lockd: Add a reference counter to struct nlm_rqst Trond Myklebust
` (6 subsequent siblings)
7 siblings, 1 reply; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
Also fix up nlmclnt_lock() so that it doesn't pass modified versions of
fl->fl_flags to nlmclnt_cancel() and other helpers.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 16 ++++++++++------
1 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index b6b74a6..4e1c012 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -493,6 +493,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
}
fl->fl_flags |= FL_ACCESS;
status = do_vfs_lock(fl);
+ fl->fl_flags = fl_flags;
if (status < 0)
goto out;
@@ -530,10 +531,11 @@ again:
goto again;
}
/* Ensure the resulting lock will get added to granted list */
- fl->fl_flags = fl_flags | FL_SLEEP;
+ fl->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);
+ fl->fl_flags = fl_flags;
}
status = nlm_stat_to_errno(resp->status);
out_unblock:
@@ -543,7 +545,6 @@ out_unblock:
nlmclnt_cancel(host, req->a_args.block, fl);
out:
nlm_release_call(req);
- fl->fl_flags = fl_flags;
return status;
}
@@ -598,7 +599,8 @@ 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 = 0;
+ int status;
+ unsigned char fl_flags = fl->fl_flags;
/*
* Note: the server is supposed to either grant us the unlock
@@ -607,11 +609,13 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
*/
fl->fl_flags |= FL_EXISTS;
down_read(&host->h_rwsem);
- if (do_vfs_lock(fl) == -ENOENT) {
- up_read(&host->h_rwsem);
+ status = do_vfs_lock(fl);
+ up_read(&host->h_rwsem);
+ fl->fl_flags = fl_flags;
+ if (status == -ENOENT) {
+ status = 0;
goto out;
}
- up_read(&host->h_rwsem);
if (req->a_flags & RPC_TASK_ASYNC)
return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/8] NLM/lockd: Add a reference counter to struct nlm_rqst
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
2008-04-03 22:39 ` [PATCH 1/8] NLM/lockd: Ensure we don't corrupt fl->fl_flags in nlmclnt_unlock() Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 3/8] NLM/lockd: convert __nlm_async_call to use rpc_run_task() Trond Myklebust
` (5 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
When we replace the existing synchronous RPC calls with asynchronous calls,
the reference count will be needed in order to allow us to examine the
result of the RPC call.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 3 +++
include/linux/lockd/lockd.h | 1 +
2 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 4e1c012..749eb53 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -221,6 +221,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
for(;;) {
call = kzalloc(sizeof(*call), GFP_KERNEL);
if (call != NULL) {
+ atomic_set(&call->a_count, 1);
locks_init_lock(&call->a_args.lock.fl);
locks_init_lock(&call->a_res.lock.fl);
call->a_host = host;
@@ -237,6 +238,8 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host)
void nlm_release_call(struct nlm_rqst *call)
{
+ if (!atomic_dec_and_test(&call->a_count))
+ return;
nlm_release_host(call->a_host);
nlmclnt_release_lockargs(call);
kfree(call);
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index acf39e1..94649a8 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -91,6 +91,7 @@ struct nlm_wait;
*/
#define NLMCLNT_OHSIZE ((__NEW_UTS_LEN) + 10u)
struct nlm_rqst {
+ atomic_t a_count;
unsigned int a_flags; /* initial RPC task flags */
struct nlm_host * a_host; /* host handle */
struct nlm_args a_args; /* arguments */
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 4/8] NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
` (4 preceding siblings ...)
2008-04-03 22:39 ` [PATCH 6/8] NLM/lockd: Fix a race when cancelling a blocking lock Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 5/8] NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call Trond Myklebust
2008-04-03 22:39 ` [PATCH 8/8] NLM/lockd: Ensure client locking calls use correct credentials Trond Myklebust
7 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
The signal masks have been rendered obsolete by the preceding patch.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 42 +-----------------------------------------
1 files changed, 1 insertions(+), 41 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index a34b709..5f13e03 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -155,8 +155,6 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req)
int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
{
struct nlm_rqst *call;
- sigset_t oldset;
- unsigned long flags;
int status;
nlm_get_host(host);
@@ -168,22 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
/* Set up the argument struct */
nlmclnt_setlockargs(call, fl);
- /* Keep the old signal mask */
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- oldset = current->blocked;
-
- /* If we're cleaning up locks because the process is exiting,
- * perform the RPC call asynchronously. */
- if ((IS_SETLK(cmd) || IS_SETLKW(cmd))
- && fl->fl_type == F_UNLCK
- && (current->flags & PF_EXITING)) {
- sigfillset(¤t->blocked); /* Mask all signals */
- recalc_sigpending();
-
- call->a_flags = RPC_TASK_ASYNC;
- }
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
-
if (IS_SETLK(cmd) || IS_SETLKW(cmd)) {
if (fl->fl_type != F_UNLCK) {
call->a_args.block = IS_SETLKW(cmd) ? 1 : 0;
@@ -198,11 +180,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
fl->fl_ops->fl_release_private(fl);
fl->fl_ops = NULL;
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- current->blocked = oldset;
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
-
dprintk("lockd: clnt proc returns %d\n", status);
return status;
}
@@ -722,16 +699,6 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = {
static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl)
{
struct nlm_rqst *req;
- unsigned long flags;
- sigset_t oldset;
- int status;
-
- /* Block all signals while setting up call */
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- oldset = current->blocked;
- sigfillset(¤t->blocked);
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
req = nlm_alloc_call(nlm_get_host(host));
if (!req)
@@ -741,14 +708,7 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
nlmclnt_setlockargs(req, fl);
req->a_args.block = block;
- status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
-
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- current->blocked = oldset;
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
-
- return status;
+ return nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
}
static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 5/8] NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
` (5 preceding siblings ...)
2008-04-03 22:39 ` [PATCH 4/8] NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 8/8] NLM/lockd: Ensure client locking calls use correct credentials Trond Myklebust
7 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
Currently, it returns success as long as the RPC call was sent. We'd like
to know if the CANCEL operation succeeded on the server.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 11 ++++++++++-
1 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 5f13e03..ea1a694 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -699,6 +699,10 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = {
static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl)
{
struct nlm_rqst *req;
+ int status;
+
+ dprintk("lockd: blocking lock attempt was interrupted by a signal.\n"
+ " Attempting to cancel lock.\n");
req = nlm_alloc_call(nlm_get_host(host));
if (!req)
@@ -708,7 +712,12 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
nlmclnt_setlockargs(req, fl);
req->a_args.block = block;
- return nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
+ atomic_inc(&req->a_count);
+ status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
+ if (status == 0 && req->a_res.status == nlm_lck_denied)
+ status = -ENOLCK;
+ nlm_release_call(req);
+ return status;
}
static void nlmclnt_cancel_callback(struct rpc_task *task, void *data)
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/8] NLM/lockd: convert __nlm_async_call to use rpc_run_task()
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
2008-04-03 22:39 ` [PATCH 1/8] NLM/lockd: Ensure we don't corrupt fl->fl_flags in nlmclnt_unlock() Trond Myklebust
2008-04-03 22:39 ` [PATCH 2/8] NLM/lockd: Add a reference counter to struct nlm_rqst Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 7/8] NFS: Remove the buggy lock-if-signalled case from do_setlk() Trond Myklebust
` (4 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
Peter Staubach comments:
> In the course of investigating testing failures in the locking phase of
> the Connectathon testsuite, I discovered a couple of things. One was
> that one of the tests in the locking tests was racy when it didn't seem
> to need to be and two, that the NFS client asynchronously releases locks
> when a process is exiting.
...
> The Single UNIX Specification Version 3 specifies that: "All locks
> associated with a file for a given process shall be removed when a file
> descriptor for that file is closed by that process or the process holding
> that file descriptor terminates.".
>
> This does not specify whether those locks must be released prior to the
> completion of the exit processing for the process or not. However,
> general assumptions seem to be that those locks will be released. This
> leads to more deterministic behavior under normal circumstances.
The following patch converts the NFSv2/v3 locking code to use the same
mechanism as NFSv4 for sending asynchronous RPC calls and then waiting for
them to complete. This ensures that the UNLOCK and CANCEL RPC calls will
complete even if the user interrupts the call, yet satisfies the
above request for synchronous behaviour on process exit.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 64 +++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 54 insertions(+), 10 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 749eb53..a34b709 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -346,10 +346,16 @@ in_grace_period:
/*
* Generic NLM call, async version.
*/
-static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
+static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
{
struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt;
+ struct rpc_task_setup task_setup_data = {
+ .rpc_message = msg,
+ .callback_ops = tk_ops,
+ .callback_data = req,
+ .flags = RPC_TASK_ASYNC,
+ };
dprintk("lockd: call procedure %d on %s (async)\n",
(int)proc, host->h_name);
@@ -359,21 +365,36 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *
if (clnt == NULL)
goto out_err;
msg->rpc_proc = &clnt->cl_procinfo[proc];
+ task_setup_data.rpc_client = clnt;
/* bootstrap and kick off the async RPC call */
- return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req);
+ return rpc_run_task(&task_setup_data);
out_err:
tk_ops->rpc_release(req);
- return -ENOLCK;
+ return ERR_PTR(-ENOLCK);
+}
+
+static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops)
+{
+ struct rpc_task *task;
+
+ task = __nlm_async_call(req, proc, msg, tk_ops);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ rpc_put_task(task);
+ return 0;
}
+/*
+ * NLM asynchronous call.
+ */
int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
{
struct rpc_message msg = {
.rpc_argp = &req->a_args,
.rpc_resp = &req->a_res,
};
- return __nlm_async_call(req, proc, &msg, tk_ops);
+ return nlm_do_async_call(req, proc, &msg, tk_ops);
}
int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
@@ -381,7 +402,32 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t
struct rpc_message msg = {
.rpc_argp = &req->a_res,
};
- return __nlm_async_call(req, proc, &msg, tk_ops);
+ return nlm_do_async_call(req, proc, &msg, tk_ops);
+}
+
+/*
+ * NLM client asynchronous call.
+ *
+ * Note that although the calls are asynchronous, and are therefore
+ * guaranteed to complete, we still always attempt to wait for
+ * completion in order to be able to correctly track the lock
+ * state.
+ */
+static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
+{
+ struct rpc_message msg = {
+ .rpc_argp = &req->a_args,
+ .rpc_resp = &req->a_res,
+ };
+ struct rpc_task *task;
+ int err;
+
+ task = __nlm_async_call(req, proc, &msg, tk_ops);
+ if (IS_ERR(task))
+ return PTR_ERR(task);
+ err = rpc_wait_for_completion_task(task);
+ rpc_put_task(task);
+ return err;
}
/*
@@ -620,10 +666,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
goto out;
}
- if (req->a_flags & RPC_TASK_ASYNC)
- return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
-
- status = nlmclnt_call(req, NLMPROC_UNLOCK);
+ atomic_inc(&req->a_count);
+ status = nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
if (status < 0)
goto out;
@@ -697,7 +741,7 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
nlmclnt_setlockargs(req, fl);
req->a_args.block = block;
- status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
+ status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
spin_lock_irqsave(¤t->sighand->siglock, flags);
current->blocked = oldset;
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 6/8] NLM/lockd: Fix a race when cancelling a blocking lock
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
` (3 preceding siblings ...)
2008-04-03 22:39 ` [PATCH 7/8] NFS: Remove the buggy lock-if-signalled case from do_setlk() Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 4/8] NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel Trond Myklebust
` (2 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
We shouldn't remove the lock from the list of blocked locks until the
CANCEL call has completed since we may be racing with a GRANTED callback.
Also ensure that we send an UNLOCK if the CANCEL request failed. Normally
that should only happen if the process gets hit with a fatal signal.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 43 ++++++++++++++++++++++++++++++++++---------
1 files changed, 34 insertions(+), 9 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index ea1a694..37d1aa2 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -510,6 +510,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
struct nlm_res *resp = &req->a_res;
struct nlm_wait *block = NULL;
unsigned char fl_flags = fl->fl_flags;
+ unsigned char fl_type;
int status = -ENOLCK;
if (nsm_monitor(host) < 0) {
@@ -525,13 +526,16 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
block = nlmclnt_prepare_block(host, fl);
again:
+ /*
+ * Initialise resp->status to a valid non-zero value,
+ * since 0 == nlm_lck_granted
+ */
+ resp->status = nlm_lck_blocked;
for(;;) {
/* Reboot protection */
fl->fl_u.nfs_fl.state = host->h_state;
status = nlmclnt_call(req, NLMPROC_LOCK);
if (status < 0)
- goto out_unblock;
- if (!req->a_args.block)
break;
/* Did a reclaimer thread notify us of a server reboot? */
if (resp->status == nlm_lck_denied_grace_period)
@@ -540,15 +544,22 @@ again:
break;
/* Wait on an NLM blocking lock */
status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
- /* if we were interrupted. Send a CANCEL request to the server
- * and exit
- */
if (status < 0)
- goto out_unblock;
+ break;
if (resp->status != nlm_lck_blocked)
break;
}
+ /* if we were interrupted while blocking, then cancel the lock request
+ * and exit
+ */
+ if (resp->status == nlm_lck_blocked) {
+ if (!req->a_args.block)
+ goto out_unlock;
+ if (nlmclnt_cancel(host, req->a_args.block, fl) == 0)
+ goto out_unblock;
+ }
+
if (resp->status == nlm_granted) {
down_read(&host->h_rwsem);
/* Check whether or not the server has rebooted */
@@ -562,16 +573,30 @@ again:
printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
up_read(&host->h_rwsem);
fl->fl_flags = fl_flags;
+ status = 0;
}
+ if (status < 0)
+ goto out_unlock;
status = nlm_stat_to_errno(resp->status);
out_unblock:
nlmclnt_finish_block(block);
- /* Cancel the blocked request if it is still pending */
- if (resp->status == nlm_lck_blocked)
- nlmclnt_cancel(host, req->a_args.block, fl);
out:
nlm_release_call(req);
return status;
+out_unlock:
+ /* Fatal error: ensure that we remove the lock altogether */
+ dprintk("lockd: lock attempt ended in fatal error.\n"
+ " Attempting to unlock.\n");
+ nlmclnt_finish_block(block);
+ fl_type = fl->fl_type;
+ fl->fl_type = F_UNLCK;
+ down_read(&host->h_rwsem);
+ do_vfs_lock(fl);
+ up_read(&host->h_rwsem);
+ fl->fl_type = fl_type;
+ fl->fl_flags = fl_flags;
+ nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
+ return status;
}
/*
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 7/8] NFS: Remove the buggy lock-if-signalled case from do_setlk()
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
` (2 preceding siblings ...)
2008-04-03 22:39 ` [PATCH 3/8] NLM/lockd: convert __nlm_async_call to use rpc_run_task() Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 6/8] NLM/lockd: Fix a race when cancelling a blocking lock Trond Myklebust
` (3 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
Both NLM and NFSv4 should be able to clean up adequately in the case where
the user interrupts the RPC call...
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/nfs/file.c | 12 ++----------
1 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 10e8b80..742cb74 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -566,17 +566,9 @@ static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
lock_kernel();
/* Use local locking if mounted with "-onolock" */
- if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)) {
+ if (!(NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM))
status = NFS_PROTO(inode)->lock(filp, cmd, fl);
- /* If we were signalled we still need to ensure that
- * we clean up any state on the server. We therefore
- * record the lock call as having succeeded in order to
- * ensure that locks_remove_posix() cleans it out when
- * the process exits.
- */
- if (status == -EINTR || status == -ERESTARTSYS)
- do_vfs_lock(filp, fl);
- } else
+ else
status = do_vfs_lock(filp, fl);
unlock_kernel();
if (status < 0)
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 8/8] NLM/lockd: Ensure client locking calls use correct credentials
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
` (6 preceding siblings ...)
2008-04-03 22:39 ` [PATCH 5/8] NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call Trond Myklebust
@ 2008-04-03 22:39 ` Trond Myklebust
[not found] ` <20080403223922.12713.37190.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
7 siblings, 1 reply; 12+ messages in thread
From: Trond Myklebust @ 2008-04-03 22:39 UTC (permalink / raw)
To: linux-nfs
Now that we've added the 'generic' credentials (that are independent of the
rpc_client) to the nfs_open_context, we can use those in the NLM client to
ensure that the lock/unlock requests are authenticated to whoever
originally opened the file.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
---
fs/lockd/clntproc.c | 23 ++++++++++++++---------
1 files changed, 14 insertions(+), 9 deletions(-)
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 37d1aa2..40b16f2 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -247,7 +247,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue)
* Generic NLM call
*/
static int
-nlmclnt_call(struct nlm_rqst *req, u32 proc)
+nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc)
{
struct nlm_host *host = req->a_host;
struct rpc_clnt *clnt;
@@ -256,6 +256,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
struct rpc_message msg = {
.rpc_argp = argp,
.rpc_resp = resp,
+ .rpc_cred = cred,
};
int status;
@@ -390,11 +391,12 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t
* completion in order to be able to correctly track the lock
* state.
*/
-static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
+static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
{
struct rpc_message msg = {
.rpc_argp = &req->a_args,
.rpc_resp = &req->a_res,
+ .rpc_cred = cred,
};
struct rpc_task *task;
int err;
@@ -415,7 +417,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
{
int status;
- status = nlmclnt_call(req, NLMPROC_TEST);
+ status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST);
if (status < 0)
goto out;
@@ -506,6 +508,7 @@ static int do_vfs_lock(struct file_lock *fl)
static int
nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
{
+ struct rpc_cred *cred = nfs_file_cred(fl->fl_file);
struct nlm_host *host = req->a_host;
struct nlm_res *resp = &req->a_res;
struct nlm_wait *block = NULL;
@@ -534,7 +537,7 @@ again:
for(;;) {
/* Reboot protection */
fl->fl_u.nfs_fl.state = host->h_state;
- status = nlmclnt_call(req, NLMPROC_LOCK);
+ status = nlmclnt_call(cred, req, NLMPROC_LOCK);
if (status < 0)
break;
/* Did a reclaimer thread notify us of a server reboot? */
@@ -595,7 +598,7 @@ out_unlock:
up_read(&host->h_rwsem);
fl->fl_type = fl_type;
fl->fl_flags = fl_flags;
- nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
+ nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
return status;
}
@@ -619,8 +622,8 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
nlmclnt_setlockargs(req, fl);
req->a_args.reclaim = 1;
- if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0
- && req->a_res.status == nlm_granted)
+ status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK);
+ if (status >= 0 && req->a_res.status == nlm_granted)
return 0;
printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
@@ -669,7 +672,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
}
atomic_inc(&req->a_count);
- status = nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
+ status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
+ NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
if (status < 0)
goto out;
@@ -738,7 +742,8 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
req->a_args.block = block;
atomic_inc(&req->a_count);
- status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
+ status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
+ NLMPROC_CANCEL, &nlmclnt_cancel_ops);
if (status == 0 && req->a_res.status == nlm_lck_denied)
status = -ENOLCK;
nlm_release_call(req);
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 8/8] NLM/lockd: Ensure client locking calls use correct credentials
[not found] ` <20080403223922.12713.37190.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
@ 2008-04-04 8:19 ` Benny Halevy
0 siblings, 0 replies; 12+ messages in thread
From: Benny Halevy @ 2008-04-04 8:19 UTC (permalink / raw)
To: Trond Myklebust; +Cc: linux-nfs
On Apr. 04, 2008, 1:39 +0300, Trond Myklebust <Trond.Myklebust@netapp.com> wrote:
> Now that we've added the 'generic' credentials (that are independent of the
> rpc_client) to the nfs_open_context, we can use those in the NLM client to
> ensure that the lock/unlock requests are authenticated to whoever
> originally opened the file.
>
> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
> ---
>
> fs/lockd/clntproc.c | 23 ++++++++++++++---------
> 1 files changed, 14 insertions(+), 9 deletions(-)
>
> diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
> index 37d1aa2..40b16f2 100644
> --- a/fs/lockd/clntproc.c
> +++ b/fs/lockd/clntproc.c
> @@ -247,7 +247,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue)
> * Generic NLM call
> */
> static int
> -nlmclnt_call(struct nlm_rqst *req, u32 proc)
> +nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc)
very minor nit: The order of arguments seems odd to me.
I'd add cred either second or last as nlm_rqst seems to be the primary argument
for this fucntion.
> {
> struct nlm_host *host = req->a_host;
> struct rpc_clnt *clnt;
> @@ -256,6 +256,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc)
> struct rpc_message msg = {
> .rpc_argp = argp,
> .rpc_resp = resp,
> + .rpc_cred = cred,
> };
> int status;
>
> @@ -390,11 +391,12 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t
> * completion in order to be able to correctly track the lock
> * state.
> */
> -static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
> +static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops)
> {
ditto.
> struct rpc_message msg = {
> .rpc_argp = &req->a_args,
> .rpc_resp = &req->a_res,
> + .rpc_cred = cred,
> };
> struct rpc_task *task;
> int err;
> @@ -415,7 +417,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
> {
> int status;
>
> - status = nlmclnt_call(req, NLMPROC_TEST);
> + status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST);
> if (status < 0)
> goto out;
>
> @@ -506,6 +508,7 @@ static int do_vfs_lock(struct file_lock *fl)
> static int
> nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
> {
> + struct rpc_cred *cred = nfs_file_cred(fl->fl_file);
> struct nlm_host *host = req->a_host;
> struct nlm_res *resp = &req->a_res;
> struct nlm_wait *block = NULL;
> @@ -534,7 +537,7 @@ again:
> for(;;) {
> /* Reboot protection */
> fl->fl_u.nfs_fl.state = host->h_state;
> - status = nlmclnt_call(req, NLMPROC_LOCK);
> + status = nlmclnt_call(cred, req, NLMPROC_LOCK);
> if (status < 0)
> break;
> /* Did a reclaimer thread notify us of a server reboot? */
> @@ -595,7 +598,7 @@ out_unlock:
> up_read(&host->h_rwsem);
> fl->fl_type = fl_type;
> fl->fl_flags = fl_flags;
> - nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
> + nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
> return status;
> }
>
> @@ -619,8 +622,8 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl)
> nlmclnt_setlockargs(req, fl);
> req->a_args.reclaim = 1;
>
> - if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0
> - && req->a_res.status == nlm_granted)
> + status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK);
> + if (status >= 0 && req->a_res.status == nlm_granted)
> return 0;
>
> printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d "
> @@ -669,7 +672,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
> }
>
> atomic_inc(&req->a_count);
> - status = nlmclnt_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
> + status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
> + NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
> if (status < 0)
> goto out;
>
> @@ -738,7 +742,8 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl
> req->a_args.block = block;
>
> atomic_inc(&req->a_count);
> - status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
> + status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req,
> + NLMPROC_CANCEL, &nlmclnt_cancel_ops);
> if (status == 0 && req->a_res.status == nlm_lck_denied)
> status = -ENOLCK;
> nlm_release_call(req);
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/8] NLM/lockd: Ensure we don't corrupt fl->fl_flags in nlmclnt_unlock()
[not found] ` <20080403223921.12713.20317.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
@ 2008-04-04 14:37 ` Chuck Lever
2008-04-04 19:02 ` Trond Myklebust
0 siblings, 1 reply; 12+ messages in thread
From: Chuck Lever @ 2008-04-04 14:37 UTC (permalink / raw)
To: Trond Myklebust; +Cc: linux-nfs
On Apr 3, 2008, at 6:39 PM, Trond Myklebust wrote:
> Also fix up nlmclnt_lock() so that it doesn't pass modified
> versions of
> fl->fl_flags to nlmclnt_cancel() and other helpers.
>
> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
> ---
>
> fs/lockd/clntproc.c | 16 ++++++++++------
> 1 files changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
> index b6b74a6..4e1c012 100644
> --- a/fs/lockd/clntproc.c
> +++ b/fs/lockd/clntproc.c
> @@ -493,6 +493,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct
> file_lock *fl)
> }
> fl->fl_flags |= FL_ACCESS;
> status = do_vfs_lock(fl);
> + fl->fl_flags = fl_flags;
> if (status < 0)
> goto out;
>
> @@ -530,10 +531,11 @@ again:
> goto again;
> }
> /* Ensure the resulting lock will get added to granted list */
> - fl->fl_flags = fl_flags | FL_SLEEP;
> + fl->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);
> + fl->fl_flags = fl_flags;
> }
> status = nlm_stat_to_errno(resp->status);
> out_unblock:
> @@ -543,7 +545,6 @@ out_unblock:
> nlmclnt_cancel(host, req->a_args.block, fl);
> out:
> nlm_release_call(req);
> - fl->fl_flags = fl_flags;
> return status;
> }
>
> @@ -598,7 +599,8 @@ 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 = 0;
> + int status;
> + unsigned char fl_flags = fl->fl_flags;
>
> /*
> * Note: the server is supposed to either grant us the unlock
> @@ -607,11 +609,13 @@ nlmclnt_unlock(struct nlm_rqst *req, struct
> file_lock *fl)
> */
> fl->fl_flags |= FL_EXISTS;
> down_read(&host->h_rwsem);
> - if (do_vfs_lock(fl) == -ENOENT) {
> - up_read(&host->h_rwsem);
> + status = do_vfs_lock(fl);
> + up_read(&host->h_rwsem);
> + fl->fl_flags = fl_flags;
> + if (status == -ENOENT) {
> + status = 0;
> goto out;
> }
> - up_read(&host->h_rwsem);
It looks like nfs4_proc_unlck() also leaves the FL_EXISTS bit set.
Should this patch also fix nfs4_proc_unlck() ?
> if (req->a_flags & RPC_TASK_ASYNC)
> return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops);
--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 1/8] NLM/lockd: Ensure we don't corrupt fl->fl_flags in nlmclnt_unlock()
2008-04-04 14:37 ` Chuck Lever
@ 2008-04-04 19:02 ` Trond Myklebust
0 siblings, 0 replies; 12+ messages in thread
From: Trond Myklebust @ 2008-04-04 19:02 UTC (permalink / raw)
To: Chuck Lever; +Cc: linux-nfs
On Fri, 2008-04-04 at 10:37 -0400, Chuck Lever wrote:
> It looks like nfs4_proc_unlck() also leaves the FL_EXISTS bit set.
> Should this patch also fix nfs4_proc_unlck() ?
I checked _nfs4_proc_setlk(), but missed the fact that nfs4_proc_unlck()
messes around with the flags too. I'll fix that in a separate patch.
Thanks for the heads-up
Trond
--
Trond Myklebust
Linux NFS client maintainer
NetApp
Trond.Myklebust@netapp.com
www.netapp.com
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2008-04-04 19:02 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-03 22:39 [PATCH 0/8] NLM client improvements for 2.6.26 Trond Myklebust
[not found] ` <20080403223921.12713.71396.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
2008-04-03 22:39 ` [PATCH 1/8] NLM/lockd: Ensure we don't corrupt fl->fl_flags in nlmclnt_unlock() Trond Myklebust
[not found] ` <20080403223921.12713.20317.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
2008-04-04 14:37 ` Chuck Lever
2008-04-04 19:02 ` Trond Myklebust
2008-04-03 22:39 ` [PATCH 2/8] NLM/lockd: Add a reference counter to struct nlm_rqst Trond Myklebust
2008-04-03 22:39 ` [PATCH 3/8] NLM/lockd: convert __nlm_async_call to use rpc_run_task() Trond Myklebust
2008-04-03 22:39 ` [PATCH 7/8] NFS: Remove the buggy lock-if-signalled case from do_setlk() Trond Myklebust
2008-04-03 22:39 ` [PATCH 6/8] NLM/lockd: Fix a race when cancelling a blocking lock Trond Myklebust
2008-04-03 22:39 ` [PATCH 4/8] NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel Trond Myklebust
2008-04-03 22:39 ` [PATCH 5/8] NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call Trond Myklebust
2008-04-03 22:39 ` [PATCH 8/8] NLM/lockd: Ensure client locking calls use correct credentials Trond Myklebust
[not found] ` <20080403223922.12713.37190.stgit-KPEdlmqt5P7XOazzY/2fV4TcuzvYVacciM950cveMlzk1uMJSBkQmQ@public.gmane.org>
2008-04-04 8:19 ` Benny Halevy
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.