patch for 2.1.57 sunrpc

Bill Hawes (whawes@star.net)
Thu, 02 Oct 1997 11:49:16 -0400


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

The attached patch should fix some potential problems in the rpc code.
In net/sunrpc/sched.c I've added a semaphore to avoid some races that
could lead to multiple rpciod processes.

In net/sunrpc/svc.c there were some problems with cleanup after
allocation failures for rpc threads. One problem could lead to an oops
from a NULL svc_serv pointer, and another failure could result in a
memory leak (svc_serv not being released.)

If you're using NFS, please give this patch a test and let me know if
any of the warnings are triggered.

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

--- linux-2.1.57/net/sunrpc/svc.c.old Thu Mar 20 10:03:20 1997
+++ linux-2.1.57/net/sunrpc/svc.c Thu Oct 2 10:19:08 1997
@@ -62,8 +62,12 @@
serv->sv_program->pg_name,
serv->sv_nrthreads);

- if (--(serv->sv_nrthreads) != 0)
- return;
+ if (serv->sv_nrthreads) {
+ if (--(serv->sv_nrthreads) != 0)
+ return;
+ } else
+ printk("svc_destroy: no threads for serv=%p!\n", serv);
+
while ((svsk = serv->sv_allsocks) != NULL)
svc_delete_socket(svsk);

@@ -111,29 +115,30 @@
svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
{
struct svc_rqst *rqstp = 0;
- int error;
+ int error = -ENOMEM;

- if (!(rqstp = kmalloc(sizeof(*rqstp), GFP_KERNEL)))
- return -ENOMEM;
+ rqstp = kmalloc(sizeof(*rqstp), GFP_KERNEL);
+ if (!rqstp)
+ goto out;

memset(rqstp, 0, sizeof(*rqstp));
if (!(rqstp->rq_argp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
|| !(rqstp->rq_resp = (u32 *) kmalloc(serv->sv_xdrsize, GFP_KERNEL))
- || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz)) {
- error = -ENOMEM;
- goto failure;
- }
+ || !svc_init_buffer(&rqstp->rq_defbuf, serv->sv_bufsz))
+ goto out_thread;

serv->sv_nrthreads++;
- if ((error = kernel_thread((int (*)(void *)) func, rqstp, 0)) < 0)
- goto failure;
-
rqstp->rq_server = serv;
- return 0;
+ error = kernel_thread((int (*)(void *)) func, rqstp, 0);
+ if (error < 0)
+ goto out_thread;
+ error = 0;
+out:
+ return error;

-failure:
+out_thread:
svc_exit_thread(rqstp);
- return error;
+ goto out;
}

/*
@@ -152,7 +157,8 @@
kfree(rqstp);

/* Release the server */
- svc_destroy(serv);
+ if (serv)
+ svc_destroy(serv);
}

/*
--- linux-2.1.57/net/sunrpc/sched.c.old Sat Sep 20 08:16:17 1997
+++ linux-2.1.57/net/sunrpc/sched.c Thu Oct 2 11:24:53 1997
@@ -56,7 +56,8 @@
*/
static struct wait_queue * rpciod_idle = NULL;
static struct wait_queue * rpciod_killer = NULL;
-static int rpciod_sema = 0;
+static struct semaphore rpciod_sema = MUTEX;
+static unsigned int rpciod_users = 0;
static pid_t rpciod_pid = 0;
static int rpc_inhibit = 0;

@@ -715,10 +716,10 @@
unsigned long oldflags;
int rounds = 0;

+ MOD_INC_USE_COUNT;
lock_kernel();
rpciod_pid = current->pid;

- MOD_INC_USE_COUNT;
/* exit_files(current); */
exit_mm(current);
current->blocked |= ~_S(SIGKILL);
@@ -727,13 +728,13 @@
sprintf(current->comm, "rpciod");

dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
- while (rpciod_sema) {
+ while (rpciod_users) {
if (signalled()) {
if (current->signal & _S(SIGKILL)) {
rpciod_killall();
} else {
printk("rpciod: ignoring signal (%d users)\n",
- rpciod_sema);
+ rpciod_users);
}
current->signal &= current->blocked;
}
@@ -783,23 +784,41 @@
void
rpciod_up(void)
{
- dprintk("rpciod_up pid %d sema %d\n", rpciod_pid, rpciod_sema);
- if (!(rpciod_sema++) || !rpciod_pid)
- kernel_thread(rpciod, &rpciod_killer, 0);
+ down(&rpciod_sema);
+ dprintk("rpciod_up: pid %d, users %d\n", rpciod_pid, rpciod_users);
+ rpciod_users++;
+ if (rpciod_pid)
+ goto out;
+ if (rpciod_users > 1)
+ printk("rpciod_up: no pid, %d users??\n", rpciod_users);
+
+ kernel_thread(rpciod, &rpciod_killer, 0);
+out:
+ up(&rpciod_sema);
}

void
rpciod_down(void)
{
- dprintk("rpciod_down pid %d sema %d\n", rpciod_pid, rpciod_sema);
- if (--rpciod_sema > 0)
- return;
+ down(&rpciod_sema);
+ dprintk("rpciod_down pid %d sema %d\n", rpciod_pid, rpciod_users);
+ if (rpciod_users) {
+ if (--rpciod_users)
+ goto out;
+ } else
+ printk("rpciod_down: pid=%d, no users??\n", rpciod_pid);
+
+ if (!rpciod_pid) {
+ printk("rpciod_down: Nothing to do!\n");
+ goto out;
+ }

- rpciod_sema = 0;
kill_proc(rpciod_pid, SIGKILL, 1);
while (rpciod_pid) {
if (signalled())
- return;
+ break;
interruptible_sleep_on(&rpciod_killer);
}
+out:
+ up(&rpciod_sema);
}

--------------B7792CFD69DBFF7ADD13A5F5--