RPC: Ensure that nobody can queue up new upcalls after rpc_close_pipes()

 Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index ded6c63..4f188d0 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -76,25 +76,35 @@
 rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
 {
 	struct rpc_inode *rpci = RPC_I(inode);
-	int res = 0;
+	int res = -EPIPE;
 
 	down(&inode->i_sem);
+	if (rpci->ops == NULL)
+		goto out;
 	if (rpci->nreaders) {
 		list_add_tail(&msg->list, &rpci->pipe);
 		rpci->pipelen += msg->len;
+		res = 0;
 	} 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
-		res = -EPIPE;
+		res = 0;
+	}
+out:
 	up(&inode->i_sem);
 	wake_up(&rpci->waitq);
 	return res;
 }
 
+static inline void
+rpc_inode_setowner(struct inode *inode, void *private)
+{
+	RPC_I(inode)->private = private;
+}
+
 static void
 rpc_close_pipes(struct inode *inode)
 {
@@ -111,15 +121,10 @@
 			rpci->ops->release_pipe(inode);
 		rpci->ops = NULL;
 	}
+	rpc_inode_setowner(inode, NULL);
 	up(&inode->i_sem);
 }
 
-static inline void
-rpc_inode_setowner(struct inode *inode, void *private)
-{
-	RPC_I(inode)->private = private;
-}
-
 static struct inode *
 rpc_alloc_inode(struct super_block *sb)
 {
@@ -501,7 +506,6 @@
 			dentry = dvec[--n];
 			if (dentry->d_inode) {
 				rpc_close_pipes(dentry->d_inode);
-				rpc_inode_setowner(dentry->d_inode, NULL);
 				simple_unlink(dir, dentry);
 			}
 			dput(dentry);
@@ -576,10 +580,8 @@
 	int error;
 
 	shrink_dcache_parent(dentry);
-	if (dentry->d_inode) {
+	if (dentry->d_inode)
 		rpc_close_pipes(dentry->d_inode);
-		rpc_inode_setowner(dentry->d_inode, NULL);
-	}
 	if ((error = simple_rmdir(dir, dentry)) != 0)
 		return error;
 	if (!error) {
@@ -732,7 +734,6 @@
 	d_drop(dentry);
 	if (dentry->d_inode) {
 		rpc_close_pipes(dentry->d_inode);
-		rpc_inode_setowner(dentry->d_inode, NULL);
 		error = simple_unlink(dir, dentry);
 	}
 	dput(dentry);