patch for 2.1.73 lockd/nfsd/sunrpc

Bill Hawes (whawes@star.net)
Fri, 19 Dec 1997 13:23:08 -0500


This is a multi-part message in MIME format.
--------------107B9E7FE4AC2667FCE72559
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

The attached (somewhat messy) patch cleans up signal handling and moves
some code common to lockd and nfsd.

Summary of Changes:
The identical xx_makesock() routines in lockd and nfsd have been moved
to the sunrpc module, as suggested in the comments in lockd.

In lockd/svc.c sigpending is now cleared before doing an interruptible
wait while the daemon exits. Pending signals were causing a spurious
"failed to exit" message (because no wait was being done.)

In lockd/mon.c a warning message is added for rpc failures.

In nfsd/nfssvc.c the local makesock() code is replaced with the sunrpc
code, and some signal blocking code is reworked slightly.

In sunrpc/clnt.c retries for garbage args are enabled.

In sunrpc/svc.c signal blocking code is replaced by clearing sigpending,
and some additional error tests are added.

In sunrpc/sched.c, a test is added to warn if the rpciod task processes
a sync request (which would block all other RPC tasks.) The sigpending
flag is cleared when killing RPC tasks at shutdown, instead of blocking
signals.

Regards,
Bill
--------------107B9E7FE4AC2667FCE72559
Content-Type: text/plain; charset=us-ascii; name="sunrpc_73-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sunrpc_73-patch"

--- linux-2.1.73/fs/lockd/svc.c.old Mon Dec 1 11:14:13 1997
+++ linux-2.1.73/fs/lockd/svc.c Fri Dec 19 10:24:25 1997
@@ -18,7 +18,6 @@

#include <linux/sched.h>
#include <linux/errno.h>
-#include <linux/nfs.h>
#include <linux/in.h>
#include <linux/uio.h>
#include <linux/version.h>
@@ -33,11 +32,11 @@
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/lockd/lockd.h>
-
+#include <linux/nfs.h>

#define NLMDBG_FACILITY NLMDBG_SVC
#define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE)
-#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+#define ALLOWED_SIGS (sigmask(SIGKILL) | sigmask(SIGSTOP))

extern struct svc_program nlmsvc_program;
struct nlmsvc_binding * nlmsvc_ops = NULL;
@@ -148,23 +147,22 @@
}

dprintk("lockd: request from %08x\n",
- (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
+ (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));

/*
* Look up the NFS client handle. The handle is needed for
* all but the GRANTED callback RPCs.
*/
+ rqstp->rq_client = NULL;
if (nlmsvc_ops) {
nlmsvc_ops->exp_readlock();
rqstp->rq_client =
nlmsvc_ops->exp_getclient(&rqstp->rq_addr);
- } else {
- rqstp->rq_client = NULL;
}

- /* Process request with all signals blocked. */
+ /* Process request with signals blocked. */
spin_lock_irq(&current->sigmask_lock);
- siginitsetinv(&current->blocked, ~BLOCKABLE_SIGS);
+ siginitsetinv(&current->blocked, ALLOWED_SIGS);
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);

@@ -202,22 +200,6 @@
}

/*
- * Make a socket for lockd
- * FIXME: Move this to net/sunrpc/svc.c so that we can share this with nfsd.
- */
-static int
-lockd_makesock(struct svc_serv *serv, int protocol, unsigned short port)
-{
- struct sockaddr_in sin;
-
- dprintk("lockd: creating socket proto = %d\n", protocol);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
- return svc_create_socket(serv, protocol, &sin);
-}
-
-/*
* Bring up the lockd process if it's not already up.
*/
int
@@ -252,8 +234,8 @@
goto out;
}

- if ((error = lockd_makesock(serv, IPPROTO_UDP, 0)) < 0
- || (error = lockd_makesock(serv, IPPROTO_TCP, 0)) < 0) {
+ if ((error = svc_makesock(serv, IPPROTO_UDP, 0)) < 0
+ || (error = svc_makesock(serv, IPPROTO_TCP, 0)) < 0) {
printk("lockd_up: makesock failed, error=%d\n", error);
goto destroy_and_out;
}
@@ -302,13 +284,17 @@
* Wait for the lockd process to exit, but since we're holding
* the lockd semaphore, we can't wait around forever ...
*/
- current->timeout = jiffies + 5 * HZ;
+ current->sigpending = 0;
+ current->timeout = jiffies + HZ;
interruptible_sleep_on(&lockd_exit);
current->timeout = 0;
if (nlmsvc_pid) {
printk("lockd_down: lockd failed to exit, clearing pid\n");
nlmsvc_pid = 0;
}
+ spin_lock_irq(&current->sigmask_lock);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
out:
up(&nlmsvc_sema);
}
--- linux-2.1.73/fs/lockd/mon.c.old Mon Apr 7 14:35:30 1997
+++ linux-2.1.73/fs/lockd/mon.c Fri Dec 19 10:24:25 1997
@@ -33,29 +33,38 @@
nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
{
struct rpc_clnt *clnt;
+ int status;
struct nsm_args args;
struct nsm_res res;
- int status;

dprintk("lockd: nsm_%s(%s)\n", what, host->h_name);
- if (!(clnt = nsm_create()))
- return -EACCES;
+ status = -EACCES;
+ clnt = nsm_create();
+ if (!clnt)
+ goto out;

args.addr = host->h_addr.sin_addr.s_addr;
args.prog = NLM_PROGRAM;
args.vers = 1;
args.proc = NLMPROC_NSM_NOTIFY;

- if ((status = rpc_call(clnt, proc, &args, &res, 0)) < 0)
- return status;
+ status = rpc_call(clnt, proc, &args, &res, 0);
+ if (status < 0) {
+ printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
+ status);
+ goto out;
+ }

+ status = -EACCES;
if (res.status != 0) {
printk(KERN_NOTICE "lockd: cannot %s %s\n", what, host->h_name);
- return -EACCES;
+ goto out;
}

nsm_local_state = res.state;
- return 0;
+ status = 0;
+out:
+ return status;
}

/*
@@ -66,7 +75,8 @@
{
int status;

- if ((status = nsm_mon_unmon(host, "monitor", SM_MON)) >= 0)
+ status = nsm_mon_unmon(host, "monitor", SM_MON);
+ if (status >= 0)
host->h_monitored = 1;
return status;
}
@@ -90,28 +100,32 @@
static struct rpc_clnt *
nsm_create(void)
{
- struct sockaddr_in sin;
struct rpc_xprt *xprt;
- struct rpc_clnt *clnt;
+ struct rpc_clnt *clnt = NULL;
+ struct sockaddr_in sin;

sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port = 0;

- if (!(xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL)))
- return NULL;
+ xprt = xprt_create_proto(IPPROTO_UDP, &sin, NULL);
+ if (!xprt)
+ goto out;

clnt = rpc_create_client(xprt, "localhost",
&nsm_program, SM_VERSION,
RPC_AUTH_NULL);
- if (!clnt) {
- xprt_destroy(xprt);
- } else {
- clnt->cl_softrtry = 1;
- clnt->cl_chatty = 1;
- clnt->cl_oneshot = 1;
- }
+ if (!clnt)
+ goto out_destroy;
+ clnt->cl_softrtry = 1;
+ clnt->cl_chatty = 1;
+ clnt->cl_oneshot = 1;
+out:
return clnt;
+
+out_destroy:
+ xprt_destroy(xprt);
+ goto out;
}

/*
--- linux-2.1.73/fs/nfsd/nfssvc.c.old Fri Dec 5 18:32:36 1997
+++ linux-2.1.73/fs/nfsd/nfssvc.c Fri Dec 19 11:55:36 1997
@@ -36,28 +36,13 @@
#define NFSDDBG_FACILITY NFSDDBG_SVC
#define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE)

-#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+#define ALLOWED_SIGS (sigmask(SIGKILL) | sigmask(SIGSTOP))
+#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGTERM))

extern struct svc_program nfsd_program;
static void nfsd(struct svc_rqst *rqstp);
struct timeval nfssvc_boot = { 0, 0 };

-/*
- * Make a socket for nfsd
- */
-static int
-nfsd_makesock(struct svc_serv *serv, int protocol, unsigned short port)
-{
- struct sockaddr_in sin;
-
- dprintk("nfsd: creating socket proto = %d\n", protocol);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
- return svc_create_socket(serv, protocol, &sin);
-}
-
int
nfsd_svc(unsigned short port, int nrservs)
{
@@ -65,17 +50,19 @@
int error;

dprintk("nfsd: creating service\n");
+ error = -EINVAL;
if (nrservs < 0)
- return -EINVAL;
+ goto out;
if (nrservs > NFSD_MAXSERVS)
nrservs = NFSD_MAXSERVS;

+ error = -ENOMEM;
serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
if (serv == NULL)
- return -ENOMEM;
+ goto out;

- if ((error = nfsd_makesock(serv, IPPROTO_UDP, port)) < 0
- || (error = nfsd_makesock(serv, IPPROTO_TCP, port)) < 0)
+ if ((error = svc_makesock(serv, IPPROTO_UDP, port)) < 0
+ || (error = svc_makesock(serv, IPPROTO_TCP, port)) < 0)
goto failure;

while (nrservs--) {
@@ -86,6 +73,7 @@

failure:
svc_destroy(serv); /* Release server */
+out:
return error;
}

@@ -98,16 +86,15 @@
struct svc_serv *serv = rqstp->rq_server;
int oldumask, err;

- lock_kernel();
/* Lock module and set up kernel thread */
MOD_INC_USE_COUNT;
+ lock_kernel();
exit_mm(current);
current->session = 1;
current->pgrp = 1;
sprintf(current->comm, "nfsd");

oldumask = current->fs->umask; /* Set umask to 0. */
- siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
current->fs->umask = 0;
nfssvc_boot = xtime; /* record boot time */
lockd_up(); /* start lockd */
@@ -116,6 +103,12 @@
* The main request loop
*/
for (;;) {
+ /* Block all but the shutdown signals */
+ spin_lock_irq(&current->sigmask_lock);
+ siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+ recalc_sigpending(current);
+ spin_unlock_irq(&current->sigmask_lock);
+
/*
* Find a socket with data available and call its
* recvfrom routine.
@@ -140,18 +133,13 @@
svc_drop(rqstp);
serv->sv_stats->rpcbadclnt++;
} else {
- /* Process request with all signals blocked. */
+ /* Process request with signals blocked. */
spin_lock_irq(&current->sigmask_lock);
- siginitsetinv(&current->blocked, ~BLOCKABLE_SIGS);
+ siginitsetinv(&current->blocked, ALLOWED_SIGS);
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);

svc_process(serv, rqstp);
-
- spin_lock_irq(&current->sigmask_lock);
- siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
- recalc_sigpending(current);
- spin_unlock_irq(&current->sigmask_lock);
}

/* Unlock export hash tables */
--- linux-2.1.73/net/sunrpc/clnt.c.old Mon Dec 1 11:14:21 1997
+++ linux-2.1.73/net/sunrpc/clnt.c Fri Dec 19 10:41:46 1997
@@ -753,8 +753,10 @@
rpc_exit(task, error);
return NULL;
}
- if (!(p = rpcauth_checkverf(task, p)))
+ if (!(p = rpcauth_checkverf(task, p))) {
+ printk("call_verify: auth check failed\n");
goto garbage; /* bad verifier, retry */
+ }
switch ((n = ntohl(*p++))) {
case RPC_SUCCESS:
return p;
@@ -768,7 +770,8 @@
garbage:
dprintk("RPC: %4d call_verify: server saw garbage\n", task->tk_pid);
task->tk_client->cl_stats->rpcgarbage++;
- if (0 && task->tk_garb_retry--) {
+ if (task->tk_garb_retry--) {
+ printk("RPC: garbage, retrying %4d\n", task->tk_pid);
task->tk_action = call_encode;
return NULL;
}
--- linux-2.1.73/net/sunrpc/svc.c.old Fri Dec 19 00:22:37 1997
+++ linux-2.1.73/net/sunrpc/svc.c Fri Dec 19 10:41:46 1997
@@ -172,7 +172,6 @@
{
struct svc_program *progp;
unsigned long flags;
- sigset_t old_set;
int i, error = 0, dummy;

progp = serv->sv_program;
@@ -180,18 +179,8 @@
dprintk("RPC: svc_register(%s, %s, %d)\n",
progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);

- /* FIXME: What had been going on before was saving and restoring
- current->signal. This as opposed to blocking signals? Do we
- still need them to wake up out of schedule? In any case it
- isn't playing nice and a better way should be found. */
-
- if (!port) {
- spin_lock_irqsave(&current->sigmask_lock, flags);
- old_set = current->blocked;
- sigfillset(&current->blocked);
- recalc_sigpending(current);
- spin_unlock_irqrestore(&current->sigmask_lock, flags);
- }
+ if (!port)
+ current->sigpending = 0;

for (i = 0; i < progp->pg_nvers; i++) {
if (progp->pg_vers[i] == NULL)
@@ -207,7 +196,6 @@

if (!port) {
spin_lock_irqsave(&current->sigmask_lock, flags);
- current->blocked = old_set;
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
}
@@ -235,7 +223,7 @@
bufp = argp->buf;

if (argp->len < 5)
- goto dropit;
+ goto err_short_len;

dir = ntohl(*bufp++);
vers = ntohl(*bufp++);
@@ -244,10 +232,8 @@
svc_putlong(resp, xdr_one); /* REPLY */
svc_putlong(resp, xdr_zero); /* ACCEPT */

- if (dir != 0) { /* direction != CALL */
- serv->sv_stats->rpcbadfmt++;
- goto dropit; /* drop request */
- }
+ if (dir != 0) /* direction != CALL */
+ goto err_bad_dir;
if (vers != 2) /* RPC version number */
goto err_bad_rpc;

@@ -281,7 +267,7 @@

procp = versp->vs_proc + proc;
if (proc >= versp->vs_nproc || !procp->pc_func)
- goto err_unknown;
+ goto err_bad_proc;
rqstp->rq_server = serv;
rqstp->rq_procinfo = procp;

@@ -329,21 +315,36 @@
if (procp->pc_release)
procp->pc_release(rqstp, NULL, rqstp->rq_resp);

- if (procp->pc_encode != NULL)
- return svc_send(rqstp);
+ if (procp->pc_encode == NULL)
+ goto dropit;
+sendit:
+ return svc_send(rqstp);

dropit:
dprintk("svc: svc_process dropit\n");
svc_drop(rqstp);
return 0;

+err_short_len:
+#ifdef RPC_PARANOIA
+ printk("svc: short len %d, dropping request\n", argp->len);
+#endif
+ goto dropit; /* drop request */
+
+err_bad_dir:
+#ifdef RPC_PARANOIA
+ printk("svc: bad direction %d, dropping request\n", dir);
+#endif
+ serv->sv_stats->rpcbadfmt++;
+ goto dropit; /* drop request */
+
err_bad_rpc:
serv->sv_stats->rpcbadfmt++;
resp->buf[-1] = xdr_one; /* REJECT */
svc_putlong(resp, xdr_zero); /* RPC_MISMATCH */
svc_putlong(resp, xdr_two); /* Only RPCv2 supported */
svc_putlong(resp, xdr_two);
- goto error;
+ goto sendit;

err_bad_auth:
dprintk("svc: authentication failed (%ld)\n", ntohl(auth_stat));
@@ -351,7 +352,7 @@
resp->buf[-1] = xdr_one; /* REJECT */
svc_putlong(resp, xdr_one); /* AUTH_ERROR */
svc_putlong(resp, auth_stat); /* status */
- goto error;
+ goto sendit;

err_bad_prog:
#ifdef RPC_PARANOIA
@@ -359,7 +360,7 @@
#endif
serv->sv_stats->rpcbadfmt++;
svc_putlong(resp, rpc_prog_unavail);
- goto error;
+ goto sendit;

err_bad_vers:
#ifdef RPC_PARANOIA
@@ -369,15 +370,15 @@
svc_putlong(resp, rpc_prog_mismatch);
svc_putlong(resp, htonl(progp->pg_lovers));
svc_putlong(resp, htonl(progp->pg_hivers));
- goto error;
+ goto sendit;

-err_unknown:
+err_bad_proc:
#ifdef RPC_PARANOIA
printk("svc: unknown procedure (%d)\n", proc);
#endif
serv->sv_stats->rpcbadfmt++;
svc_putlong(resp, rpc_proc_unavail);
- goto error;
+ goto sendit;

err_garbage:
#ifdef RPC_PARANOIA
@@ -385,7 +386,5 @@
#endif
serv->sv_stats->rpcbadfmt++;
svc_putlong(resp, rpc_garbage_args);
-
-error:
- return svc_send(rqstp);
+ goto sendit;
}
--- linux-2.1.73/net/sunrpc/sched.c.old Wed Dec 3 10:42:35 1997
+++ linux-2.1.73/net/sunrpc/sched.c Fri Dec 19 10:41:46 1997
@@ -388,6 +388,8 @@
/* sync task: sleep here */
dprintk("RPC: %4d sync task going to sleep\n",
task->tk_pid);
+ if (current->pid == rpciod_pid)
+ printk("RPC: rpciod waiting on sync task!\n");
current->timeout = 0;
sleep_on(&task->tk_wait);

@@ -792,29 +794,21 @@
rpciod_killall(void)
{
unsigned long flags;
- sigset_t old_set;
-
- /* FIXME: What had been going on before was saving and restoring
- current->signal. This as opposed to blocking signals? Do we
- still need them to wake up out of schedule? In any case it
- isn't playing nice and a better way should be found. */
-
- spin_lock_irqsave(&current->sigmask_lock, flags);
- old_set = current->blocked;
- sigfillset(&current->blocked);
- recalc_sigpending(current);
- spin_unlock_irqrestore(&current->sigmask_lock, flags);

while (all_tasks) {
+ current->sigpending = 0;
rpc_killall_tasks(NULL);
__rpc_schedule();
- current->timeout = jiffies + HZ / 100;
- need_resched = 1;
- schedule();
+ if (all_tasks) {
+printk("rpciod_killall: waiting for tasks to exit\n");
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ current->timeout = 0;
+ }
}

spin_lock_irqsave(&current->sigmask_lock, flags);
- current->blocked = old_set;
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, flags);
}
--- linux-2.1.73/net/sunrpc/svcsock.c.old Mon Dec 1 23:57:00 1997
+++ linux-2.1.73/net/sunrpc/svcsock.c Fri Dec 19 10:41:46 1997
@@ -886,7 +886,7 @@
/*
* Create socket for RPC service.
*/
-int
+static int
svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin)
{
struct svc_sock *svsk;
@@ -969,3 +969,19 @@
/* svsk->sk_server = NULL; */
}
}
+
+/*
+ * Make a socket for nfsd and lockd
+ */
+int
+svc_makesock(struct svc_serv *serv, int protocol, unsigned short port)
+{
+ struct sockaddr_in sin;
+
+ dprintk("svc: creating socket proto = %d\n", protocol);
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(port);
+ return svc_create_socket(serv, protocol, &sin);
+}
+
--- linux-2.1.73/net/sunrpc/sunrpc_syms.c.old Mon Dec 1 11:14:21 1997
+++ linux-2.1.73/net/sunrpc/sunrpc_syms.c Fri Dec 19 10:41:46 1997
@@ -62,7 +62,6 @@

/* RPC server stuff */
EXPORT_SYMBOL(svc_create);
-EXPORT_SYMBOL(svc_create_socket);
EXPORT_SYMBOL(svc_create_thread);
EXPORT_SYMBOL(svc_exit_thread);
EXPORT_SYMBOL(svc_destroy);
@@ -70,6 +69,7 @@
EXPORT_SYMBOL(svc_process);
EXPORT_SYMBOL(svc_recv);
EXPORT_SYMBOL(svc_wake_up);
+EXPORT_SYMBOL(svc_makesock);

/* RPC statistics */
#ifdef CONFIG_PROC_FS
--- linux-2.1.73/include/linux/sunrpc/svcsock.h.old Fri Dec 19 00:49:44 1997
+++ linux-2.1.73/include/linux/sunrpc/svcsock.h Fri Dec 19 10:41:46 1997
@@ -49,7 +49,7 @@
/*
* Function prototypes.
*/
-int svc_create_socket(struct svc_serv *, int, struct sockaddr_in *);
+int svc_makesock(struct svc_serv *, int, unsigned short);
void svc_delete_socket(struct svc_sock *);
int svc_recv(struct svc_serv *, struct svc_rqst *);
int svc_send(struct svc_rqst *);

--------------107B9E7FE4AC2667FCE72559--