NFS: todays TCP fixes

Alan Cox (alan@lxorguk.ukuu.org.uk)
Mon, 17 Aug 98 23:37 BST


Ok this seems to cure the tcp hang some people were seeing. Unfortunately
its not a 100% fix. While it cures the error 11 /disconnect cycle and the
infinite hang it replaces them with a pause until the retry timer kicks in.

The tcp layer logic is right, the tcp notifier should be waking the rpc
and the rpc completion should wake the next rpc but something isnt occuring
right there. Maybe there is a bug in the RPC scheduler or the top level
of tcp rpc sending logic. Additional eyes over that would be appreciated

Its also got a certain amount of debugging printks in it

Hitting ^C on a stuck mount syscall not works right.

diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/fs/nfs/dir.c linux/fs/nfs/dir.c
--- linux.vanilla/fs/nfs/dir.c Mon Jul 6 16:35:26 1998
+++ linux/fs/nfs/dir.c Fri Aug 7 18:49:46 1998
@@ -14,6 +14,13 @@
* Following Linus comments on my original hack, this version
* depends only on the dcache stuff and doesn't touch the inode
* layer (iput() and friends).
+ * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
+ * FIFO's need special handling in NFSv2
+ */
+
+/*
+ * Fixes:
+ * Ion Badulescu <ionut@cs.columbia.edu> : FIFO's need special handling in NFSv2
*/

#include <linux/sched.h>
@@ -645,7 +652,10 @@
if (dentry->d_name.len > NFS_MAXNAMLEN)
goto out;

- sattr.mode = mode;
+ if (mode & S_IFIFO)
+ sattr.mode = (mode & ~S_IFMT) | S_IFCHR;
+ else
+ sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;

@@ -655,6 +665,15 @@
nfs_invalidate_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ /*
+ * Retry invalid FIFO creates as the original object
+ * to cover for NFS servers that don't cope.
+ */
+ if (error == -EINVAL && (mode & S_IFIFO)) {
+ sattr.mode = mode;
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ }
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
@@ -684,7 +703,10 @@
if (dentry->d_name.len > NFS_MAXNAMLEN)
return -ENAMETOOLONG;

- sattr.mode = mode;
+ if (mode & S_IFIFO)
+ sattr.mode = (mode & ~S_IFMT) | S_IFCHR;
+ else
+ sattr.mode = mode;
sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
if (S_ISCHR(mode) || S_ISBLK(mode))
sattr.size = rdev; /* get out your barf bag */
@@ -693,6 +715,11 @@
nfs_invalidate_dircache(dir);
error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
dentry->d_name.name, &sattr, &fhandle, &fattr);
+ if (error == -EINVAL && (mode & S_IFIFO)) {
+ sattr.mode = mode;
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
+ dentry->d_name.name, &sattr, &fhandle, &fattr);
+ }
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
if (error)
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/fs/nfs/mount_clnt.c linux/fs/nfs/mount_clnt.c
--- linux.vanilla/fs/nfs/mount_clnt.c Thu Apr 24 03:01:26 1997
+++ linux/fs/nfs/mount_clnt.c Mon Aug 17 13:59:43 1998
@@ -78,6 +78,7 @@
clnt->cl_softrtry = 1;
clnt->cl_chatty = 1;
clnt->cl_oneshot = 1;
+ clnt->cl_intr = 1;
}
return clnt;
}
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/fs/nfs/nfs2xdr.c linux/fs/nfs/nfs2xdr.c
--- linux.vanilla/fs/nfs/nfs2xdr.c Tue Mar 10 21:26:56 1998
+++ linux/fs/nfs/nfs2xdr.c Fri Aug 7 18:13:52 1998
@@ -5,6 +5,9 @@
*
* Copyright (C) 1992, 1993, 1994 Rick Sladkey
* Copyright (C) 1996 Olaf Kirch
+ *
+ * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
+ * FIFO's need special handling in NFSv2
*/

#define NFS_NEED_XDR_TYPES
@@ -114,6 +117,11 @@
fattr->mtime.useconds = ntohl(*p++);
fattr->ctime.seconds = ntohl(*p++);
fattr->ctime.useconds = ntohl(*p++);
+ if (fattr->type == NFCHR && fattr->rdev == NFS_FIFO_DEV) {
+ fattr->type = NFFIFO;
+ fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
+ fattr->rdev = 0;
+ }
return p;
}

diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/fs/nfs/write.c linux/fs/nfs/write.c
--- linux.vanilla/fs/nfs/write.c Mon Jul 6 16:35:26 1998
+++ linux/fs/nfs/write.c Mon Aug 17 17:13:18 1998
@@ -468,7 +468,9 @@
struct wait_queue wait = { current, NULL };
struct page *page = req->wb_page;
int retval;
+ sigset_t oldmask;

+ rpc_clnt_sigmask(NFS_CLIENT(req->wb_inode), &oldmask);
add_wait_queue(&page->wait, &wait);
atomic_inc(&page->count);
for (;;) {
@@ -477,7 +479,8 @@
if (!PageLocked(page))
break;
retval = -ERESTARTSYS;
- if (IS_SOFT && signalled())
+ /* IS_SOFT is a timeout item .. */
+ if (signalled())
break;
schedule();
}
@@ -485,6 +488,7 @@
current->state = TASK_RUNNING;
/* N.B. page may have been unused, so we must use free_page() */
free_page(page_address(page));
+ rpc_clnt_sigunmask(NFS_CLIENT(req->wb_inode), &oldmask);
return retval;
}

@@ -534,6 +538,10 @@
if ((req = find_write_request(inode, page)) != NULL) {
if (update_write_request(req, offset, count)) {
/* N.B. check for a fault here and cancel the req */
+ /*
+ * SECURITY - copy_from_user must zero the
+ * rest of the data after a fault!
+ */
copy_from_user(page_addr + offset, buffer, count);
goto updated;
}
@@ -889,6 +897,9 @@
/* Update attributes as result of writeback.
* Beware: when UDP replies arrive out of order, we
* may end up overwriting a previous, bigger file size.
+ *
+ * When the file size shrinks we cancel all pending
+ * writebacks.
*/
if (fattr->mtime.seconds >= inode->i_mtime) {
if (fattr->size < inode->i_size)
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- linux.vanilla/fs/nfsd/vfs.c Tue Jul 21 14:19:29 1998
+++ linux/fs/nfsd/vfs.c Fri Aug 7 23:27:44 1998
@@ -1159,8 +1159,12 @@

/* Hewlett Packard ignores the eof flag on READDIR. Some
* fs-specific readdir implementations seem to reset f_pos to 0
- * at EOF however, causing an endless loop. */
- if (cd.offset && !eof)
+ * at EOF however, causing an endless loop.
+ *
+ * We should always return the current offset in the directory
+ * even if we are at EOF. Return -1 is wrong.
+ */
+ if (cd.offset)
*cd.offset = htonl(file.f_pos);

p = cd.buffer;
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/clnt.h linux/include/linux/sunrpc/clnt.h
--- linux.vanilla/include/linux/sunrpc/clnt.h Fri May 8 02:15:58 1998
+++ linux/include/linux/sunrpc/clnt.h Mon Aug 17 20:33:26 1998
@@ -118,6 +118,9 @@
void *argp, void *resp, int flags,
rpc_action callback, void *clntdata);
void rpc_restart_call(struct rpc_task *);
+void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
+void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
+
#define rpc_call(clnt, proc, argp, resp, flags) \
rpc_do_call(clnt, proc, argp, resp, flags, NULL, NULL)

diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/sched.h linux/include/linux/sunrpc/sched.h
--- linux.vanilla/include/linux/sunrpc/sched.h Mon Jul 6 16:18:15 1998
+++ linux/include/linux/sunrpc/sched.h Mon Aug 10 21:39:54 1998
@@ -146,6 +146,8 @@
void rpc_free(void *);
int rpciod_up(void);
void rpciod_down(void);
+void rpciod_wake_up(void);
+void rpciod_tcp_dispatcher(void);
#ifdef RPC_DEBUG
void rpc_show_tasks(void);
#endif
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/include/linux/sunrpc/xprt.h linux/include/linux/sunrpc/xprt.h
--- linux.vanilla/include/linux/sunrpc/xprt.h Tue Aug 4 13:52:19 1998
+++ linux/include/linux/sunrpc/xprt.h Mon Aug 17 20:26:56 1998
@@ -36,7 +36,7 @@
* Note: on machines with low memory we should probably use a smaller
* MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
* reassembly will frequently run out of memory.
- * Come Linux 2.1, we'll handle fragments directly.
+ * Come Linux 2.3, we'll handle fragments directly.
*/
#define RPC_MAXCONG 16
#define RPC_MAXREQS (RPC_MAXCONG + 1)
@@ -103,6 +103,12 @@
* For authentication (e.g. auth_des)
*/
u32 rq_creddata[2];
+
+ /*
+ * Partial send handling
+ */
+
+ u32 rq_bytes_sent; /* Bytes we have sent */

#ifdef RPC_PROFILE
unsigned long rq_xtime; /* when transmitted */
@@ -166,6 +172,8 @@
*/
struct rpc_iov snd_buf; /* send buffer */
struct rpc_task * snd_task; /* Task blocked in send */
+ u32 snd_sent; /* Bytes we have sent */
+

void (*old_data_ready)(struct sock *, int);
void (*old_state_change)(struct sock *);
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/mm/filemap.c linux/mm/filemap.c
--- linux.vanilla/mm/filemap.c Fri Aug 7 17:21:02 1998
+++ linux/mm/filemap.c Mon Aug 17 16:51:52 1998
@@ -7,7 +7,7 @@
/*
* This file handles the generic file mmap semantics used by
* most "normal" filesystems (but you don't /have/ to use this:
- * the NFS filesystem does this differently, for example)
+ * the NFS filesystem used to do this differently, for example)
*/
#include <linux/stat.h>
#include <linux/sched.h>
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/net/sunrpc/auth_unix.c linux/net/sunrpc/auth_unix.c
--- linux.vanilla/net/sunrpc/auth_unix.c Sun Mar 22 23:06:14 1998
+++ linux/net/sunrpc/auth_unix.c Sun Aug 9 20:31:24 1998
@@ -178,6 +178,11 @@
base = p++;
*p++ = htonl(jiffies/HZ);
#ifndef DONT_FILLIN_HOSTNAME
+ /*
+ * Problem: The UTS name could change under us. We can't lock
+ * here to handle this. On the other hand we can't really
+ * go building a bad RPC!
+ */
if ((n = strlen((char *) system_utsname.nodename)) > UNX_MAXNODENAME)
n = UNX_MAXNODENAME;
*p++ = htonl(n);
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- linux.vanilla/net/sunrpc/clnt.c Tue Jul 21 14:19:32 1998
+++ linux/net/sunrpc/clnt.c Mon Aug 17 17:15:52 1998
@@ -191,22 +191,15 @@
}

/*
- * New rpc_call implementation
+ * Export the signal mask handling for aysnchronous code that
+ * sleeps on RPC calls
*/
-int
-rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
- int flags, rpc_action func, void *data)
+
+void rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset)
{
- struct rpc_task my_task, *task = &my_task;
unsigned long sigallow = sigmask(SIGKILL);
- sigset_t oldset;
unsigned long irqflags;
- int async, status;
-
- /* If this client is slain all further I/O fails */
- if (clnt->cl_dead)
- return -EIO;
-
+
/* Turn off various signals */
if (clnt->cl_intr) {
struct k_sigaction *action = current->sig->action;
@@ -216,10 +209,38 @@
sigallow |= sigmask(SIGQUIT);
}
spin_lock_irqsave(&current->sigmask_lock, irqflags);
- oldset = current->blocked;
- siginitsetinv(&current->blocked, sigallow & ~oldset.sig[0]);
+ *oldset = current->blocked;
+ siginitsetinv(&current->blocked, sigallow & ~oldset->sig[0]);
recalc_sigpending(current);
spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+}
+
+void rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset)
+{
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&current->sigmask_lock, irqflags);
+ current->blocked = *oldset;
+ recalc_sigpending(current);
+ spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+}
+
+/*
+ * New rpc_call implementation
+ */
+int
+rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
+ int flags, rpc_action func, void *data)
+{
+ struct rpc_task my_task, *task = &my_task;
+ sigset_t oldset;
+ int async, status;
+
+ /* If this client is slain all further I/O fails */
+ if (clnt->cl_dead)
+ return -EIO;
+
+ rpc_clnt_sigmask(clnt, &oldset);

/* Create/initialize a new RPC task */
if ((async = (flags & RPC_TASK_ASYNC)) != 0) {
@@ -248,10 +269,7 @@
}

out:
- spin_lock_irqsave(&current->sigmask_lock, irqflags);
- current->blocked = oldset;
- recalc_sigpending(current);
- spin_unlock_irqrestore(&current->sigmask_lock, irqflags);
+ rpc_clnt_sigunmask(clnt, &oldset);

return status;
}
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/net/sunrpc/sched.c linux/net/sunrpc/sched.c
--- linux.vanilla/net/sunrpc/sched.c Tue Jul 21 14:19:32 1998
+++ linux/net/sunrpc/sched.c Mon Aug 17 14:15:04 1998
@@ -176,6 +176,21 @@
task->tk_flags |= RPC_TASK_RUNNING;
}

+
+/*
+ * For other people who may need to wake the I/O daemon
+ * but should (for now) know nothing about its innards
+ */
+
+void rpciod_wake_up(void)
+{
+ if(rpciod_pid==0)
+ {
+ printk(KERN_ERR "rpciod: wot no daemon?\n");
+ }
+ wake_up(&rpciod_idle);
+}
+
/*
* Prepare for sleeping on a wait queue.
* By always appending tasks to the list we ensure FIFO behavior.
@@ -337,6 +352,7 @@
/*
* This is the RPC `scheduler' (or rather, the finite state machine).
*/
+
static int
__rpc_execute(struct rpc_task *task)
{
@@ -400,10 +416,16 @@
printk("RPC: rpciod waiting on sync task!\n");
current->timeout = 0;
sleep_on(&task->tk_wait);
-
+
/* When the task received a signal, remove from
- * any queues etc, and make runnable again. */
- if (0 && signalled())
+ * any queues etc, and make runnable again.
+ *
+ * The "intr" property isnt handled here. rpc_do_call
+ * has changed the signal mask of the process for
+ * a synchronous rpc call. If a signal gets through
+ * this then its real.
+ */
+ if (signalled())
__rpc_wake_up(task);

dprintk("RPC: %4d sync task resuming\n",
@@ -417,7 +439,7 @@
* clean up after sleeping on some queue, we don't
* break the loop here, but go around once more.
*/
- if (0 && !RPC_IS_ASYNC(task) && signalled()) {
+ if (!RPC_IS_ASYNC(task) && signalled()) {
dprintk("RPC: %4d got signal\n", task->tk_pid);
rpc_exit(task, -ERESTARTSYS);
}
@@ -795,6 +817,7 @@
dprintk("RPC: rpciod back to sleep\n");
interruptible_sleep_on(&rpciod_idle);
dprintk("RPC: switch to rpciod\n");
+ rpciod_tcp_dispatcher();
rounds = 0;
}
restore_flags(oldflags);
diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/net/sunrpc/sunrpc_syms.c linux/net/sunrpc/sunrpc_syms.c
--- linux.vanilla/net/sunrpc/sunrpc_syms.c Tue Jul 21 14:19:32 1998
+++ linux/net/sunrpc/sunrpc_syms.c Mon Aug 17 15:24:00 1998
@@ -43,6 +43,8 @@
EXPORT_SYMBOL(rpc_killall_tasks);
EXPORT_SYMBOL(rpc_do_call);
EXPORT_SYMBOL(rpc_call_setup);
+EXPORT_SYMBOL(rpc_clnt_sigmask);
+EXPORT_SYMBOL(rpc_clnt_sigunmask);
EXPORT_SYMBOL(rpc_delay);
EXPORT_SYMBOL(rpc_restart_call);

diff -u --recursive --new-file --exclude-from ../exclude linux.vanilla/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- linux.vanilla/net/sunrpc/xprt.c Tue Aug 4 13:52:20 1998
+++ linux/net/sunrpc/xprt.c Mon Aug 17 22:19:53 1998
@@ -34,6 +34,7 @@
* Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
*
* TCP callback races fixes (C) 1998 Red Hat Software <alan@redhat.com>
+ * TCP send fixes (C) 1998 Red Hat Software <alan@redhat.com>
*/

#define __KERNEL_SYSCALLS__
@@ -136,8 +137,49 @@
}

/*
+ * Adjust the iovec to move on 'n' bytes
+ */
+
+extern inline void xprt_move_iov(struct msghdr *msg, int amount)
+{
+ struct iovec niv[MAX_IOVEC];
+ struct iovec *iv=msg->msg_iov;
+
+ /*
+ * Eat any sent iovecs
+ */
+
+ while(iv->iov_len < amount)
+ {
+ amount-=iv->iov_len;
+ iv++;
+ msg->msg_iovlen--;
+ }
+
+ msg->msg_iov=niv;
+
+ /*
+ * And chew down the partial one
+ */
+
+ niv[0].iov_len = iv->iov_len-amount;
+ niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
+ iv++;
+
+ /*
+ * And copy any others
+ */
+
+ for(amount=1;amount<msg->msg_iovlen; amount++)
+ {
+ niv[amount]=*iv++;
+ }
+}
+
+/*
* Write data to socket.
*/
+
static inline int
xprt_sendmsg(struct rpc_xprt *xprt)
{
@@ -150,7 +192,6 @@
xprt->snd_buf.io_vec->iov_base,
xprt->snd_buf.io_vec->iov_len);

-#if LINUX_VERSION_CODE >= 0x020100
msg.msg_flags = MSG_DONTWAIT;
msg.msg_iov = xprt->snd_buf.io_vec;
msg.msg_iovlen = xprt->snd_buf.io_nr;
@@ -158,27 +199,21 @@
msg.msg_namelen = sizeof(xprt->addr);
msg.msg_control = NULL;

+ /* Dont repeat bytes */
+
+ if(xprt->snd_sent)
+ xprt_move_iov(&msg, xprt->snd_sent);
+
oldfs = get_fs(); set_fs(get_ds());
result = sock_sendmsg(sock, &msg, xprt->snd_buf.io_len);
set_fs(oldfs);
-#else
- msg.msg_flags = 0;
- msg.msg_iov = xprt->snd_buf.io_vec;
- msg.msg_iovlen = xprt->snd_buf.io_nr;
- msg.msg_name = (struct sockaddr *) &xprt->addr;
- msg.msg_namelen = sizeof(xprt->addr);
- msg.msg_control = NULL;
-
- oldfs = get_fs(); set_fs(get_ds());
- result = sock->ops->sendmsg(sock, &msg, xprt->snd_buf.io_len, 1, 0);
- set_fs(oldfs);
-#endif

dprintk("RPC: xprt_sendmsg(%d) = %d\n",
xprt->snd_buf.io_len, result);

if (result >= 0) {
xprt->snd_buf.io_len -= result;
+ xprt->snd_sent += result;
return result;
}

@@ -188,6 +223,8 @@
* prompts ECONNREFUSED.
*/
break;
+ case -EAGAIN:
+ return 0;
case -ENOTCONN: case -EPIPE:
/* connection broken */
break;
@@ -324,6 +361,12 @@
fput(xprt->file);
else
sock_release(xprt->sock);
+ /*
+ * TCP doesnt require the rpciod now - other things may
+ * but rpciod handles that not us.
+ */
+ if(xprt->stream)
+ rpciod_down();
}

/*
@@ -700,19 +743,17 @@

static struct rpc_xprt *rpc_xprt_pending = NULL; /* Chain by rx_pending of rpc_xprt's */

-static struct tq_struct rpc_tcp_tqueue = { 0, 0, 0, 0 };
-
-
/*
- * This is protected from tcp_data_ready by the bh atomicity guarantees
+ * This is protected from tcp_data_ready and the stack as its run
+ * inside of the RPC I/O daemon
*/

-static void tcp_rpc_bh_run(void)
+void rpciod_tcp_dispatcher(void)
{
struct rpc_xprt *xprt;
int result;

- dprintk("tcp_rpc_bh_run: Queue Running\n");
+ dprintk("rpciod_tcp_dispatcher: Queue Running\n");

/*
* Empty each pending socket
@@ -725,7 +766,7 @@
rpc_xprt_pending=xprt->rx_pending;
xprt->rx_pending_flag=0;

- dprintk("tcp_rpc_run_bh: Processing %p\n", xprt);
+ dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt);

do
{
@@ -750,12 +791,9 @@
}


-static void tcp_rpc_bh_queue(void)
+extern inline void tcp_rpciod_queue(void)
{
- rpc_tcp_tqueue.routine=(void *)(void *)tcp_rpc_bh_run;
- queue_task(&rpc_tcp_tqueue, &tq_immediate);
- dprintk("RPC: tcp_rpc_bh_queue: immediate op queued\n");
- mark_bh(IMMEDIATE_BH);
+ rpciod_wake_up();
}

/*
@@ -787,7 +825,7 @@
{
dprintk("RPC: xprt queue\n");
if(rpc_xprt_pending==NULL)
- tcp_rpc_bh_queue();
+ tcp_rpciod_queue();
xprt->rx_pending_flag=1;
xprt->rx_pending=rpc_xprt_pending;
rpc_xprt_pending=xprt;
@@ -827,9 +865,19 @@

if (!(xprt = xprt_from_sock(sk)))
return;
- xprt->write_space = 1;
- if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
- rpc_wake_up_task(xprt->snd_task);
+ if(xprt->snd_sent && xprt->snd_task)
+ printk("write space\n");
+ if(xprt->write_space == 0)
+ {
+ xprt->write_space = 1;
+ if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
+ {
+ if(xprt->snd_sent)
+ printk("Write wakeup snd_sent =%d\n",
+ xprt->snd_sent);
+ rpc_wake_up_task(xprt->snd_task);
+ }
+ }
}

/*
@@ -888,6 +936,8 @@
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_xprt *xprt = req->rq_xprt;

+ /*DEBUG*/int ac_debug=xprt->snd_sent;
+
dprintk("RPC: %4d xprt_transmit(%x)\n", task->tk_pid,
*(u32 *)(req->rq_svec[0].iov_base));

@@ -934,6 +984,8 @@
}
xprt->snd_buf = req->rq_snd_buf;
xprt->snd_task = task;
+ xprt->snd_sent = 0;
+ /*DEBUG*/ac_debug = 0;
}

/* For fast networks/servers we have to put the request on
@@ -953,10 +1005,12 @@
if (xprt_transmit_some(xprt, task) != -EAGAIN) {
dprintk("RPC: %4d xmit complete\n", task->tk_pid);
xprt->snd_task = NULL;
+ if(ac_debug)
+ printk("Partial xmit finished\n");
return;
}

- dprintk("RPC: %4d xmit incomplete (%d left of %d)\n",
+ /*d*/printk("RPC: %4d xmit incomplete (%d left of %d)\n",
task->tk_pid, xprt->snd_buf.io_len,
req->rq_slen);
task->tk_status = 0;
@@ -983,10 +1037,15 @@
struct rpc_xprt *xprt = task->tk_client->cl_xprt;

dprintk("RPC: %4d transmit_status %d\n", task->tk_pid, task->tk_status);
- if (xprt->snd_task == task) {
+ if (xprt->snd_task == task)
+ {
if (task->tk_status < 0)
+ {
xprt->snd_task = NULL;
- xprt_disconnect(xprt);
+ xprt_disconnect(xprt);
+ }
+ else
+ xprt_transmit(task);
}
}

@@ -1279,6 +1338,12 @@
xprt->free = xprt->slot;

dprintk("RPC: created transport %p\n", xprt);
+
+ /*
+ * TCP requires the rpc I/O daemon is present
+ */
+ if(proto==IPPROTO_TCP)
+ rpciod_up();
return xprt;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html