2004-12-09 21:22:51

by Mike Waychison

[permalink] [raw]
Subject: [PATCH 0/2] [RFC] Making mount operation soft + intr

While implementing and testing autofsng, I found myself getting frustrated at
NFS mounts that fail and stay hung.

A typical example is to try and mount from a bogus NFS port:

mount -o port=10000 host:/export /mnt

If the default is hard, the kernel will never time out trying to get initial
contact with the server.

If the default is nointr, then there is no way for userspace to kill the mount
process.

Both of these options make sense while the filesystem is mounted, but in the
case where the server will never respond with a live nfs export, can easily
hang processes and leave locked super_block's live in the system (impeding a
reboot).

The solution I am suggesting is to force the initial rpc calls used in setting
up a mount to be soft + intr, regardless of what the real options are. We can
do this by passing RPC_TASK_SOFT to the rpc_calls for NFS3PROC_FSINFO,
NFS3PROC_GETATTR, NFSPROC_GETATTR and NFSPROC_STATFS.

To force 'intr' regardless of whether clnt->cl_intr is set or not, we use a
similar technique to the recently added RPC_TASK_NOINTR flag used for
transaction integrity. We introduce RPC_TASK_FORCEINTR, which overrides
RPC_TASK_NOINTR (the latter is dependent on clnt->cl_intr).

AFAICT, making these ops soft+intr is safe because there is no data to be lost
in the event of a cancelled/timed-out operation.

The first patch following this message adds RPC_TASK_FORCEINTR and makes the
rootfh ops use it and RPC_TASK_SOFT.

The second patch adds a parameter to rpc_clnt_sigmask that takes an optional
set of task flags, of which only RPC_TASK_FORCEINTR is inspected for. This
keeps the mount paths from blocking signals SIGINT and SIGQUIT.

mount(8) still needs to be taught not to block these signals if it doesn't care
whether the mount operation succeeded or not (in the case of it not being a
loop device and mtab isn't being updated).

(I haven't touched the nfsv4 stuff as I haven't yet wrapped my head around that
code.)

Comments?



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs


2004-12-09 21:23:16

by Mike Waychison

[permalink] [raw]
Subject: [PATCH 1/2] Make get rootfh calls soft + intr

This patch add a new rpc task flag, RPC_TASK_FORCEINTR, which makes the task in
question run intr even if nointr is specified. This is used by the get root fh
functions so that mounting becomes interuptible.

As well, this patch also modifies the get root calls to run RPC_TASK_SOFT so
that a bogus mount will eventually time out. This makes bogus mounts like
'mount -o nfsport=10000 host:/export /tmp/foo' eventually timeout instead of
leaving a super_block hung for eternity.

Signed-off-by: Mike Waychison <[email protected]>
Index: linux-2.6.9-quilt/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/nfs3proc.c 2004-11-11 16:51:45.691151928 -0800
+++ linux-2.6.9-quilt/fs/nfs/nfs3proc.c 2004-11-11 16:52:22.279589640 -0800
@@ -79,10 +79,14 @@ nfs3_proc_get_root(struct nfs_server *se

dprintk("%s: call fsinfo\n", __FUNCTION__);
info->fattr->valid = 0;
- status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
+ /*
+ * We force mount setup to be soft,intr regardless of true mount options
+ * so that we don't end up with a hung system on a bad initial mount
+ */
+ status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, RPC_TASK_SOFT | RPC_TASK_FORCEINTR);
dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status);
if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
- status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
+ status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, RPC_TASK_SOFT | RPC_TASK_FORCEINTR);
dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
}
return status;
Index: linux-2.6.9-quilt/fs/nfs/proc.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/proc.c 2004-11-11 16:51:45.696151168 -0800
+++ linux-2.6.9-quilt/fs/nfs/proc.c 2004-11-11 16:52:22.281589336 -0800
@@ -62,12 +62,18 @@ nfs_proc_get_root(struct nfs_server *ser

dprintk("%s: call getattr\n", __FUNCTION__);
fattr->valid = 0;
- status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
+ /*
+ * We force mount setup to be soft,intr regardless of true mount options
+ * so that we don't end up with a hung system on a bad initial mount
+ */
+ status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr,
+ RPC_TASK_SOFT | RPC_TASK_FORCEINTR);
dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
if (status)
return status;
dprintk("%s: call statfs\n", __FUNCTION__);
- status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0);
+ status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo,
+ RPC_TASK_SOFT | RPC_TASK_FORCEINTR);
dprintk("%s: reply statfs %d\n", __FUNCTION__, status);
if (status)
return status;
Index: linux-2.6.9-quilt/include/linux/sunrpc/sched.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/sunrpc/sched.h 2004-11-11 16:51:45.697151016 -0800
+++ linux-2.6.9-quilt/include/linux/sunrpc/sched.h 2004-11-11 16:52:22.282589184 -0800
@@ -114,6 +114,7 @@ typedef void (*rpc_action)(struct rpc_
#define RPC_TASK_KILLED 0x0100 /* task was killed */
#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */
#define RPC_TASK_NOINTR 0x0400 /* uninterruptible task */
+#define RPC_TASK_FORCEINTR 0x0800 /* force intr even if nointr */

#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
#define RPC_IS_SETUID(t) ((t)->tk_flags & RPC_TASK_SETUID)
@@ -124,7 +125,7 @@ typedef void (*rpc_action)(struct rpc_
#define RPC_IS_ACTIVATED(t) ((t)->tk_active)
#define RPC_DO_CALLBACK(t) ((t)->tk_callback != NULL)
#define RPC_IS_SOFT(t) ((t)->tk_flags & RPC_TASK_SOFT)
-#define RPC_TASK_UNINTERRUPTIBLE(t) ((t)->tk_flags & RPC_TASK_NOINTR)
+#define RPC_TASK_UNINTERRUPTIBLE(t) (((t)->tk_flags & (RPC_TASK_NOINTR | RPC_TASK_FORCEINTR)) == RPC_TASK_NOINTR)

#define RPC_TASK_SLEEPING 0
#define RPC_TASK_RUNNING 1



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2004-12-09 21:23:50

by Mike Waychison

[permalink] [raw]
Subject: [PATCH 2/2] Allow FORCEINTR override for signal masking

Add a new flags parameter to rpc_clnt_sigmask. Flags are meant to be task flags.
This allows us to specify RPC_TASK_FORCEINTR when masking signals, which keeps
rpc_clnt_sigmask from blocking SIGINT and SIGQUIT as if clnt->cl_intr had been
set.

Signed-off-by: Mike Waychison <[email protected]>
Index: linux-2.6.9-quilt/fs/nfs/file.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/file.c 2004-10-18 14:54:38.000000000 -0700
+++ linux-2.6.9-quilt/fs/nfs/file.c 2004-12-03 11:02:27.000000000 -0800
@@ -309,7 +309,7 @@ static int do_unlk(struct file *filp, in
sigset_t oldset;
int status;

- rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset);
+ rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset, 0);
/*
* Flush all pending writes before doing anything
* with locks..
Index: linux-2.6.9-quilt/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/nfs3proc.c 2004-11-18 18:00:29.000000000 -0800
+++ linux-2.6.9-quilt/fs/nfs/nfs3proc.c 2004-12-03 11:06:35.000000000 -0800
@@ -28,7 +28,7 @@ nfs3_rpc_wrapper(struct rpc_clnt *clnt,
{
sigset_t oldset;
int res;
- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, flags);
do {
res = rpc_call_sync(clnt, msg, flags);
if (res != -EJUKEBOX)
Index: linux-2.6.9-quilt/fs/nfs/nfs4proc.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/nfs4proc.c 2004-12-03 11:07:16.000000000 -0800
+++ linux-2.6.9-quilt/fs/nfs/nfs4proc.c 2004-12-03 11:07:57.000000000 -0800
@@ -2086,7 +2086,7 @@ int nfs4_wait_clnt_recover(struct rpc_cl

might_sleep();

- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, 0);
interruptible = TASK_UNINTERRUPTIBLE;
if (clnt->cl_intr)
interruptible = TASK_INTERRUPTIBLE;
@@ -2112,7 +2112,7 @@ static int nfs4_delay(struct rpc_clnt *c
*timeout = NFS4_POLL_RETRY_MIN;
if (*timeout > NFS4_POLL_RETRY_MAX)
*timeout = NFS4_POLL_RETRY_MAX;
- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, 0);
if (clnt->cl_intr) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(*timeout);
Index: linux-2.6.9-quilt/fs/nfs/read.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/read.c 2004-11-11 13:01:03.000000000 -0800
+++ linux-2.6.9-quilt/fs/nfs/read.c 2004-12-03 11:05:07.000000000 -0800
@@ -268,7 +268,7 @@ static void nfs_execute_read(struct nfs_
struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
sigset_t oldset;

- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, 0);
lock_kernel();
rpc_execute(&data->task);
unlock_kernel();
Index: linux-2.6.9-quilt/fs/nfs/write.c
===================================================================
--- linux-2.6.9-quilt.orig/fs/nfs/write.c 2004-11-22 12:48:22.000000000 -0800
+++ linux-2.6.9-quilt/fs/nfs/write.c 2004-12-03 11:06:03.000000000 -0800
@@ -603,7 +603,7 @@ static int nfs_wait_on_write_congestion(
struct rpc_clnt *clnt = NFS_CLIENT(mapping->host);
sigset_t oldset;

- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, RPC_TASK_FORCEINTR);
prepare_to_wait(&nfs_write_congestion, &wait, TASK_INTERRUPTIBLE);
if (bdi_write_congested(bdi)) {
if (signalled())
@@ -903,7 +903,7 @@ static void nfs_execute_write(struct nfs
struct rpc_clnt *clnt = NFS_CLIENT(data->inode);
sigset_t oldset;

- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, 0);
lock_kernel();
rpc_execute(&data->task);
unlock_kernel();
Index: linux-2.6.9-quilt/include/linux/nfs_fs.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/nfs_fs.h 2004-11-11 13:01:03.000000000 -0800
+++ linux-2.6.9-quilt/include/linux/nfs_fs.h 2004-12-03 11:04:40.000000000 -0800
@@ -476,7 +476,7 @@ extern void * nfs_root_data(void);
int __retval = 0; \
if (clnt->cl_intr) { \
sigset_t oldmask; \
- rpc_clnt_sigmask(clnt, &oldmask); \
+ rpc_clnt_sigmask(clnt, &oldmask, 0); \
__retval = wait_event_interruptible(wq, condition); \
rpc_clnt_sigunmask(clnt, &oldmask); \
} else \
Index: linux-2.6.9-quilt/include/linux/sunrpc/clnt.h
===================================================================
--- linux-2.6.9-quilt.orig/include/linux/sunrpc/clnt.h 2004-12-03 10:46:18.000000000 -0800
+++ linux-2.6.9-quilt/include/linux/sunrpc/clnt.h 2004-12-03 10:47:01.000000000 -0800
@@ -126,7 +126,7 @@ int rpc_call_async(struct rpc_clnt *cln
int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
int flags);
void rpc_restart_call(struct rpc_task *);
-void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
+void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset, int flags);
void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);

Index: linux-2.6.9-quilt/net/sunrpc/clnt.c
===================================================================
--- linux-2.6.9-quilt.orig/net/sunrpc/clnt.c 2004-11-22 12:36:48.000000000 -0800
+++ linux-2.6.9-quilt/net/sunrpc/clnt.c 2004-12-03 11:15:54.000000000 -0800
@@ -308,13 +308,13 @@ rpc_default_callback(struct rpc_task *ta
* sleeps on RPC calls
*/

-void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)
+void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset, int flags)
{
unsigned long sigallow = sigmask(SIGKILL);
unsigned long irqflags;

/* Turn off various signals */
- if (clnt->cl_intr) {
+ if (clnt->cl_intr || flags & RPC_TASK_FORCEINTR) {
struct k_sigaction *action = current->sighand->action;
if (action[SIGINT-1].sa.sa_handler == SIG_DFL)
sigallow |= sigmask(SIGINT);
@@ -353,7 +353,7 @@ int rpc_call_sync(struct rpc_clnt *clnt,

BUG_ON(flags & RPC_TASK_ASYNC);

- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, flags);

status = -ENOMEM;
task = rpc_new_task(clnt, NULL, flags);
@@ -393,7 +393,7 @@ rpc_call_async(struct rpc_clnt *clnt, st

flags |= RPC_TASK_ASYNC;

- rpc_clnt_sigmask(clnt, &oldset);
+ rpc_clnt_sigmask(clnt, &oldset, flags);

/* Create/initialize a new RPC task */
if (!callback)



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://productguide.itmanagersjournal.com/
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs