From: Trond Myklebust <trond.myklebust@fys.uio.no>

NFSv4/RPCSEC_GSS: Ensure that RPC userland upcalls time out correctly if the corresponding userland daemon is not up and running.


---

 fs/nfs/idmap.c                     |    1 +
 include/linux/sunrpc/rpc_pipe_fs.h |    1 +
 net/sunrpc/auth_gss/auth_gss.c     |    1 +
 net/sunrpc/clnt.c                  |    1 +
 net/sunrpc/rpc_pipe.c              |   29 +++++++++++++++++++++++++++--
 net/sunrpc/sunrpc_syms.c           |    1 +
 6 files changed, 32 insertions(+), 2 deletions(-)

diff -puN fs/nfs/idmap.c~nfs-01-rpc_pipe_timeout fs/nfs/idmap.c
--- 25/fs/nfs/idmap.c~nfs-01-rpc_pipe_timeout	2004-01-09 22:16:03.000000000 -0800
+++ 25-akpm/fs/nfs/idmap.c	2004-01-09 22:16:03.000000000 -0800
@@ -43,6 +43,7 @@
 #include <linux/sched.h>
 
 #include <linux/sunrpc/clnt.h>
+#include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
 #include <linux/nfs_fs_sb.h>
diff -puN include/linux/sunrpc/rpc_pipe_fs.h~nfs-01-rpc_pipe_timeout include/linux/sunrpc/rpc_pipe_fs.h
--- 25/include/linux/sunrpc/rpc_pipe_fs.h~nfs-01-rpc_pipe_timeout	2004-01-09 22:16:03.000000000 -0800
+++ 25-akpm/include/linux/sunrpc/rpc_pipe_fs.h	2004-01-09 22:16:03.000000000 -0800
@@ -27,6 +27,7 @@ struct rpc_inode {
 #define RPC_PIPE_WAIT_FOR_OPEN	1
 	int flags;
 	struct rpc_pipe_ops *ops;
+	struct work_struct queue_timeout;
 };
 
 static inline struct rpc_inode *
diff -puN net/sunrpc/auth_gss/auth_gss.c~nfs-01-rpc_pipe_timeout net/sunrpc/auth_gss/auth_gss.c
--- 25/net/sunrpc/auth_gss/auth_gss.c~nfs-01-rpc_pipe_timeout	2004-01-09 22:16:03.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/auth_gss.c	2004-01-09 22:16:03.000000000 -0800
@@ -49,6 +49,7 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/auth_gss.h>
 #include <linux/sunrpc/gss_err.h>
+#include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <asm/uaccess.h>
 
diff -puN net/sunrpc/clnt.c~nfs-01-rpc_pipe_timeout net/sunrpc/clnt.c
--- 25/net/sunrpc/clnt.c~nfs-01-rpc_pipe_timeout	2004-01-09 22:16:03.000000000 -0800
+++ 25-akpm/net/sunrpc/clnt.c	2004-01-09 22:16:03.000000000 -0800
@@ -30,6 +30,7 @@
 #include <linux/utsname.h>
 
 #include <linux/sunrpc/clnt.h>
+#include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
 #include <linux/nfs.h>
diff -puN net/sunrpc/rpc_pipe.c~nfs-01-rpc_pipe_timeout net/sunrpc/rpc_pipe.c
--- 25/net/sunrpc/rpc_pipe.c~nfs-01-rpc_pipe_timeout	2004-01-09 22:16:03.000000000 -0800
+++ 25-akpm/net/sunrpc/rpc_pipe.c	2004-01-09 22:16:03.000000000 -0800
@@ -25,6 +25,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/sunrpc/clnt.h>
+#include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
 static struct vfsmount *rpc_mount;
@@ -35,6 +36,8 @@ static struct file_system_type rpc_pipe_
 
 static kmem_cache_t *rpc_inode_cachep;
 
+#define RPC_UPCALL_TIMEOUT (30*HZ)
+
 static void
 __rpc_purge_upcall(struct inode *inode, int err)
 {
@@ -59,6 +62,18 @@ rpc_purge_upcall(struct inode *inode, in
 	up(&inode->i_sem);
 }
 
+static void
+rpc_timeout_upcall_queue(void *data)
+{
+	struct rpc_inode *rpci = (struct rpc_inode *)data;
+	struct inode *inode = &rpci->vfs_inode;
+
+	down(&inode->i_sem);
+	if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
+		__rpc_purge_upcall(inode, -ETIMEDOUT);
+	up(&inode->i_sem);
+}
+
 int
 rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
 {
@@ -66,7 +81,13 @@ rpc_queue_upcall(struct inode *inode, st
 	int res = 0;
 
 	down(&inode->i_sem);
-	if (rpci->nreaders || (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN)) {
+	if (rpci->nreaders) {
+		list_add_tail(&msg->list, &rpci->pipe);
+		rpci->pipelen += msg->len;
+	} else if (rpci->flags & RPC_PIPE_WAIT_FOR_OPEN) {
+		if (list_empty(&rpci->pipe))
+			schedule_delayed_work(&rpci->queue_timeout,
+					RPC_UPCALL_TIMEOUT);
 		list_add_tail(&msg->list, &rpci->pipe);
 		rpci->pipelen += msg->len;
 	} else
@@ -80,6 +101,9 @@ void
 rpc_inode_setowner(struct inode *inode, void *private)
 {
 	struct rpc_inode *rpci = RPC_I(inode);
+
+	cancel_delayed_work(&rpci->queue_timeout);
+	flush_scheduled_work();
 	down(&inode->i_sem);
 	rpci->private = private;
 	if (!private)
@@ -133,7 +157,7 @@ rpc_pipe_release(struct inode *inode, st
 	down(&inode->i_sem);
 	if (filp->f_mode & FMODE_READ)
 		rpci->nreaders --;
-	if (!rpci->nreaders && !(rpci->flags & RPC_PIPE_WAIT_FOR_OPEN))
+	if (!rpci->nreaders)
 		__rpc_purge_upcall(inode, -EPIPE);
 	up(&inode->i_sem);
 	return 0;
@@ -769,6 +793,7 @@ init_once(void * foo, kmem_cache_t * cac
 		INIT_LIST_HEAD(&rpci->pipe);
 		rpci->pipelen = 0;
 		init_waitqueue_head(&rpci->waitq);
+		INIT_WORK(&rpci->queue_timeout, rpc_timeout_upcall_queue, rpci);
 		rpci->ops = NULL;
 	}
 }
diff -puN net/sunrpc/sunrpc_syms.c~nfs-01-rpc_pipe_timeout net/sunrpc/sunrpc_syms.c
--- 25/net/sunrpc/sunrpc_syms.c~nfs-01-rpc_pipe_timeout	2004-01-09 22:16:03.000000000 -0800
+++ 25-akpm/net/sunrpc/sunrpc_syms.c	2004-01-09 22:16:03.000000000 -0800
@@ -21,6 +21,7 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/svcsock.h>
 #include <linux/sunrpc/auth.h>
+#include <linux/workqueue.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
 
 

_