patch-2.1.58 linux/net/sunrpc/sched.c
Next file: linux/net/sunrpc/svc.c
Previous file: linux/net/sunrpc/pmap_clnt.c
Back to the patch index
Back to the overall index
- Lines: 204
- Date:
Sun Oct 12 10:17:46 1997
- Orig file:
v2.1.57/linux/net/sunrpc/sched.c
- Orig date:
Tue Sep 23 16:48:50 1997
diff -u --recursive --new-file v2.1.57/linux/net/sunrpc/sched.c linux/net/sunrpc/sched.c
@@ -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;
@@ -575,19 +576,36 @@
current->pid);
}
+/*
+ * Create a new task for the specified client. We have to
+ * clean up after an allocation failure, as the client may
+ * have specified "oneshot".
+ */
struct rpc_task *
rpc_new_task(struct rpc_clnt *clnt, rpc_action callback, int flags)
{
struct rpc_task *task;
- if (!(task = (struct rpc_task *) rpc_allocate(flags, sizeof(*task))))
- return NULL;
+ task = (struct rpc_task *) rpc_allocate(flags, sizeof(*task));
+ if (!task)
+ goto cleanup;
rpc_init_task(task, clnt, callback, flags);
dprintk("RPC: %4d allocated task\n", task->tk_pid);
task->tk_flags |= RPC_TASK_DYNAMIC;
+out:
return task;
+
+cleanup:
+ /* Check whether to release the client */
+ if (clnt) {
+ printk("rpc_new_task: failed, users=%d, oneshot=%d\n",
+ clnt->cl_users, clnt->cl_oneshot);
+ clnt->cl_users++; /* pretend we were used ... */
+ rpc_release_client(clnt);
+ }
+ goto out;
}
void
@@ -662,6 +680,9 @@
rpc_release_task(child);
}
+/*
+ * Note: rpc_new_task releases the client after a failure.
+ */
struct rpc_task *
rpc_new_child(struct rpc_clnt *clnt, struct rpc_task *parent)
{
@@ -715,11 +736,15 @@
unsigned long oldflags;
int rounds = 0;
+ MOD_INC_USE_COUNT;
lock_kernel();
+ /*
+ * Let our maker know we're running ...
+ */
rpciod_pid = current->pid;
+ wake_up(&rpciod_idle);
- MOD_INC_USE_COUNT;
- /* exit_files(current); */
+ exit_files(current);
exit_mm(current);
current->blocked |= ~_S(SIGKILL);
current->session = 1;
@@ -727,25 +752,28 @@
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;
}
__rpc_schedule();
- if (++rounds >= 64) /* safeguard */
+ if (++rounds >= 64) { /* safeguard */
schedule();
+ rounds = 0;
+ }
save_flags(oldflags); cli();
if (!schedq.task) {
dprintk("RPC: rpciod back to sleep\n");
interruptible_sleep_on(&rpciod_idle);
dprintk("RPC: switch to rpciod\n");
+ rounds = 0;
}
restore_flags(oldflags);
}
@@ -780,26 +808,84 @@
}
}
-void
+/*
+ * Start up the rpciod process if it's not already running.
+ */
+int
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);
+ int error = 0;
+
+ MOD_INC_USE_COUNT;
+ down(&rpciod_sema);
+ dprintk("rpciod_up: pid %d, users %d\n", rpciod_pid, rpciod_users);
+ rpciod_users++;
+ if (rpciod_pid)
+ goto out;
+ /*
+ * If there's no pid, we should be the first user.
+ */
+ if (rpciod_users > 1)
+ printk("rpciod_up: no pid, %d users??\n", rpciod_users);
+ /*
+ * Create the rpciod thread and wait for it to start.
+ */
+ error = kernel_thread(rpciod, &rpciod_killer, 0);
+ if (error < 0) {
+ printk("rpciod_up: create thread failed, error=%d\n", error);
+ goto out;
+ }
+ sleep_on(&rpciod_idle);
+ error = 0;
+out:
+ up(&rpciod_sema);
+ MOD_DEC_USE_COUNT;
+ return error;
}
void
rpciod_down(void)
{
- dprintk("rpciod_down pid %d sema %d\n", rpciod_pid, rpciod_sema);
- if (--rpciod_sema > 0)
- return;
+ unsigned long oldflags;
+
+ MOD_INC_USE_COUNT;
+ 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);
+ /*
+ * Usually rpciod will exit very quickly, so we
+ * wait briefly before checking the process id.
+ */
+ oldflags = current->signal;
+ current->signal = 0;
+ current->state = TASK_INTERRUPTIBLE;
+ current->timeout = jiffies + 1;
+ schedule();
+ current->timeout = 0;
+ /*
+ * Display a message if we're going to wait longer.
+ */
while (rpciod_pid) {
- if (signalled())
- return;
+ printk("rpciod_down: waiting for pid %d to exit\n", rpciod_pid);
+ if (signalled()) {
+ printk("rpciod_down: caught signal\n");
+ break;
+ }
interruptible_sleep_on(&rpciod_killer);
}
+ current->signal = oldflags;
+out:
+ up(&rpciod_sema);
+ MOD_DEC_USE_COUNT;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov