<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">
From: Trond Myklebust &lt;trond.myklebust@fys.uio.no&gt;

RPCSEC_GSS: Make the upcalls detect if the userland daemon dies while
processing a request.



---

 include/linux/sunrpc/rpc_pipe_fs.h |    4 +-
 net/sunrpc/auth_gss/auth_gss.c     |   28 +++++++++++++++
 net/sunrpc/rpc_pipe.c              |   67 +++++++++++++++++++++++++------------
 3 files changed, 78 insertions(+), 21 deletions(-)

diff -puN include/linux/sunrpc/rpc_pipe_fs.h~nfs-03-pipe_close include/linux/sunrpc/rpc_pipe_fs.h
--- 25/include/linux/sunrpc/rpc_pipe_fs.h~nfs-03-pipe_close	2004-01-09 22:16:10.000000000 -0800
+++ 25-akpm/include/linux/sunrpc/rpc_pipe_fs.h	2004-01-09 22:16:10.000000000 -0800
@@ -14,6 +14,7 @@ struct rpc_pipe_msg {
 struct rpc_pipe_ops {
 	ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t);
 	ssize_t (*downcall)(struct file *, const char __user *, size_t);
+	void (*release_pipe)(struct inode *);
 	void (*destroy_msg)(struct rpc_pipe_msg *);
 };
 
@@ -21,8 +22,10 @@ struct rpc_inode {
 	struct inode vfs_inode;
 	void *private;
 	struct list_head pipe;
+	struct list_head in_upcall;
 	int pipelen;
 	int nreaders;
+	int nwriters;
 	wait_queue_head_t waitq;
 #define RPC_PIPE_WAIT_FOR_OPEN	1
 	int flags;
@@ -36,7 +39,6 @@ RPC_I(struct inode *inode)
 	return container_of(inode, struct rpc_inode, vfs_inode);
 }
 
-extern void rpc_inode_setowner(struct inode *, void *);
 extern int rpc_queue_upcall(struct inode *, struct rpc_pipe_msg *);
 
 extern struct dentry *rpc_mkdir(char *, struct rpc_clnt *);
diff -puN net/sunrpc/auth_gss/auth_gss.c~nfs-03-pipe_close net/sunrpc/auth_gss/auth_gss.c
--- 25/net/sunrpc/auth_gss/auth_gss.c~nfs-03-pipe_close	2004-01-09 22:16:10.000000000 -0800
+++ 25-akpm/net/sunrpc/auth_gss/auth_gss.c	2004-01-09 22:16:10.000000000 -0800
@@ -482,6 +482,33 @@ err:
 	return err;
 }
 
+static void
+gss_pipe_release(struct inode *inode)
+{
+	struct rpc_inode *rpci = RPC_I(inode);
+	struct rpc_clnt *clnt;
+	struct rpc_auth *auth;
+	struct gss_auth *gss_auth;
+
+	clnt = rpci-&gt;private;
+	auth = clnt-&gt;cl_auth;
+	gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+	spin_lock(&amp;gss_auth-&gt;lock);
+	while (!list_empty(&amp;gss_auth-&gt;upcalls)) {
+		struct gss_upcall_msg *gss_msg;
+
+		gss_msg = list_entry(gss_auth-&gt;upcalls.next,
+				struct gss_upcall_msg, list);
+		gss_msg-&gt;msg.errno = -EPIPE;
+		atomic_inc(&amp;gss_msg-&gt;count);
+		__gss_unhash_msg(gss_msg);
+		spin_unlock(&amp;gss_auth-&gt;lock);
+		gss_release_msg(gss_msg);
+		spin_lock(&amp;gss_auth-&gt;lock);
+	}
+	spin_unlock(&amp;gss_auth-&gt;lock);
+}
+
 void
 gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
@@ -774,6 +801,7 @@ static struct rpc_pipe_ops gss_upcall_op
 	.upcall		= gss_pipe_upcall,
 	.downcall	= gss_pipe_downcall,
 	.destroy_msg	= gss_pipe_destroy_msg,
+	.release_pipe	= gss_pipe_release,
 };
 
 /*
diff -puN net/sunrpc/rpc_pipe.c~nfs-03-pipe_close net/sunrpc/rpc_pipe.c
--- 25/net/sunrpc/rpc_pipe.c~nfs-03-pipe_close	2004-01-09 22:16:10.000000000 -0800
+++ 25-akpm/net/sunrpc/rpc_pipe.c	2004-01-09 22:16:10.000000000 -0800
@@ -50,18 +50,16 @@ __rpc_purge_upcall(struct inode *inode, 
 		msg-&gt;errno = err;
 		rpci-&gt;ops-&gt;destroy_msg(msg);
 	}
+	while (!list_empty(&amp;rpci-&gt;in_upcall)) {
+		msg = list_entry(rpci-&gt;pipe.next, struct rpc_pipe_msg, list);
+		list_del_init(&amp;msg-&gt;list);
+		msg-&gt;errno = err;
+		rpci-&gt;ops-&gt;destroy_msg(msg);
+	}
 	rpci-&gt;pipelen = 0;
 	wake_up(&amp;rpci-&gt;waitq);
 }
 
-void
-rpc_purge_upcall(struct inode *inode, int err)
-{
-	down(&amp;inode-&gt;i_sem);
-	__rpc_purge_upcall(inode, err);
-	up(&amp;inode-&gt;i_sem);
-}
-
 static void
 rpc_timeout_upcall_queue(void *data)
 {
@@ -97,20 +95,31 @@ rpc_queue_upcall(struct inode *inode, st
 	return res;
 }
 
-void
-rpc_inode_setowner(struct inode *inode, void *private)
+static void
+rpc_close_pipes(struct inode *inode)
 {
 	struct rpc_inode *rpci = RPC_I(inode);
 
 	cancel_delayed_work(&amp;rpci-&gt;queue_timeout);
 	flush_scheduled_work();
 	down(&amp;inode-&gt;i_sem);
-	rpci-&gt;private = private;
-	if (!private)
+	if (rpci-&gt;ops != NULL) {
+		rpci-&gt;nreaders = 0;
 		__rpc_purge_upcall(inode, -EPIPE);
+		rpci-&gt;nwriters = 0;
+		if (rpci-&gt;ops-&gt;release_pipe)
+			rpci-&gt;ops-&gt;release_pipe(inode);
+		rpci-&gt;ops = NULL;
+	}
 	up(&amp;inode-&gt;i_sem);
 }
 
+static inline void
+rpc_inode_setowner(struct inode *inode, void *private)
+{
+	RPC_I(inode)-&gt;private = private;
+}
+
 static struct inode *
 rpc_alloc_inode(struct super_block *sb)
 {
@@ -134,9 +143,11 @@ rpc_pipe_open(struct inode *inode, struc
 	int res = -ENXIO;
 
 	down(&amp;inode-&gt;i_sem);
-	if (rpci-&gt;private != NULL) {
+	if (rpci-&gt;ops != NULL) {
 		if (filp-&gt;f_mode &amp; FMODE_READ)
 			rpci-&gt;nreaders ++;
+		if (filp-&gt;f_mode &amp; FMODE_WRITE)
+			rpci-&gt;nwriters ++;
 		res = 0;
 	}
 	up(&amp;inode-&gt;i_sem);
@@ -149,16 +160,24 @@ rpc_pipe_release(struct inode *inode, st
 	struct rpc_inode *rpci = RPC_I(filp-&gt;f_dentry-&gt;d_inode);
 	struct rpc_pipe_msg *msg;
 
+	down(&amp;inode-&gt;i_sem);
+	if (rpci-&gt;ops == NULL)
+		goto out;
 	msg = (struct rpc_pipe_msg *)filp-&gt;private_data;
 	if (msg != NULL) {
 		msg-&gt;errno = -EPIPE;
+		list_del_init(&amp;msg-&gt;list);
 		rpci-&gt;ops-&gt;destroy_msg(msg);
 	}
-	down(&amp;inode-&gt;i_sem);
+	if (filp-&gt;f_mode &amp; FMODE_WRITE)
+		rpci-&gt;nwriters --;
 	if (filp-&gt;f_mode &amp; FMODE_READ)
 		rpci-&gt;nreaders --;
 	if (!rpci-&gt;nreaders)
 		__rpc_purge_upcall(inode, -EPIPE);
+	if (rpci-&gt;ops-&gt;release_pipe)
+		rpci-&gt;ops-&gt;release_pipe(inode);
+out:
 	up(&amp;inode-&gt;i_sem);
 	return 0;
 }
@@ -172,7 +191,7 @@ rpc_pipe_read(struct file *filp, char __
 	int res = 0;
 
 	down(&amp;inode-&gt;i_sem);
-	if (!rpci-&gt;private) {
+	if (rpci-&gt;ops == NULL) {
 		res = -EPIPE;
 		goto out_unlock;
 	}
@@ -182,7 +201,7 @@ rpc_pipe_read(struct file *filp, char __
 			msg = list_entry(rpci-&gt;pipe.next,
 					struct rpc_pipe_msg,
 					list);
-			list_del_init(&amp;msg-&gt;list);
+			list_move(&amp;msg-&gt;list, &amp;rpci-&gt;in_upcall);
 			rpci-&gt;pipelen -= msg-&gt;len;
 			filp-&gt;private_data = msg;
 			msg-&gt;copied = 0;
@@ -194,6 +213,7 @@ rpc_pipe_read(struct file *filp, char __
 	res = rpci-&gt;ops-&gt;upcall(filp, msg, buf, len);
 	if (res &lt; 0 || msg-&gt;len == msg-&gt;copied) {
 		filp-&gt;private_data = NULL;
+		list_del_init(&amp;msg-&gt;list);
 		rpci-&gt;ops-&gt;destroy_msg(msg);
 	}
 out_unlock:
@@ -210,7 +230,7 @@ rpc_pipe_write(struct file *filp, const 
 
 	down(&amp;inode-&gt;i_sem);
 	res = -EPIPE;
-	if (rpci-&gt;private != NULL)
+	if (rpci-&gt;ops != NULL)
 		res = rpci-&gt;ops-&gt;downcall(filp, buf, len);
 	up(&amp;inode-&gt;i_sem);
 	return res;
@@ -226,7 +246,7 @@ rpc_pipe_poll(struct file *filp, struct 
 	poll_wait(filp, &amp;rpci-&gt;waitq, wait);
 
 	mask = POLLOUT | POLLWRNORM;
-	if (rpci-&gt;private == NULL)
+	if (rpci-&gt;ops == NULL)
 		mask |= POLLERR | POLLHUP;
 	if (!list_empty(&amp;rpci-&gt;pipe))
 		mask |= POLLIN | POLLRDNORM;
@@ -242,7 +262,7 @@ rpc_pipe_ioctl(struct inode *ino, struct
 
 	switch (cmd) {
 	case FIONREAD:
-		if (!rpci-&gt;private)
+		if (rpci-&gt;ops == NULL)
 			return -EPIPE;
 		len = rpci-&gt;pipelen;
 		if (filp-&gt;private_data) {
@@ -484,6 +504,7 @@ repeat:
 		do {
 			dentry = dvec[--n];
 			if (dentry-&gt;d_inode) {
+				rpc_close_pipes(dentry-&gt;d_inode);
 				rpc_inode_setowner(dentry-&gt;d_inode, NULL);
 				simple_unlink(dir, dentry);
 			}
@@ -563,7 +584,10 @@ __rpc_rmdir(struct inode *dir, struct de
 	int error;
 
 	shrink_dcache_parent(dentry);
-	rpc_inode_setowner(dentry-&gt;d_inode, NULL);
+	if (dentry-&gt;d_inode) {
+		rpc_close_pipes(dentry-&gt;d_inode);
+		rpc_inode_setowner(dentry-&gt;d_inode, NULL);
+	}
 	if ((error = simple_rmdir(dir, dentry)) != 0)
 		return error;
 	if (!error) {
@@ -715,6 +739,7 @@ rpc_unlink(char *path)
 	}
 	d_drop(dentry);
 	if (dentry-&gt;d_inode) {
+		rpc_close_pipes(dentry-&gt;d_inode);
 		rpc_inode_setowner(dentry-&gt;d_inode, NULL);
 		error = simple_unlink(dir, dentry);
 	}
@@ -790,6 +815,8 @@ init_once(void * foo, kmem_cache_t * cac
 		inode_init_once(&amp;rpci-&gt;vfs_inode);
 		rpci-&gt;private = NULL;
 		rpci-&gt;nreaders = 0;
+		rpci-&gt;nwriters = 0;
+		INIT_LIST_HEAD(&amp;rpci-&gt;in_upcall);
 		INIT_LIST_HEAD(&amp;rpci-&gt;pipe);
 		rpci-&gt;pipelen = 0;
 		init_waitqueue_head(&amp;rpci-&gt;waitq);

_
</pre></body></html>