* diff-ve-nfs-xprt-owner_env-save-20090724
Patch from Vasily Averin <vvs@openvz.org>:

prevents use-after-free in xs_tcp_connect_worker() while accessing
xprt->owner_env when xprt is alread destroyed.

https://bugzilla.sw.ru/show_bug.cgi?id=439585
================================================================
--- ./net/sunrpc/xprtsock.c.xprt1	2009-07-02 18:22:15.000000000 +0400
+++ ./net/sunrpc/xprtsock.c	2009-07-24 17:01:12.000000000 +0400
@@ -1059,11 +1059,12 @@ static void xs_udp_connect_worker(void *
 	struct rpc_xprt *xprt = (struct rpc_xprt *) args;
 	struct socket *sock = xprt->sock;
 	int err, status = -EIO;
-	struct ve_struct *ve;
+	struct ve_struct *ve, *old_ve;
 
-	ve = set_exec_env(xprt->owner_env);
-	down_read(&xprt->owner_env->op_sem);
-	if (!xprt->owner_env->is_running)
+	ve = xprt->owner_env;
+	old_ve = set_exec_env(ve);
+	down_read(&ve->op_sem);
+	if (!ve->is_running)
 		goto out;
 	if (xprt->shutdown || xprt->addr.sin_port == 0)
 		goto out;
@@ -1111,8 +1112,8 @@ static void xs_udp_connect_worker(void *
 out:
 	xprt_wake_pending_tasks(xprt, status);
 	xprt_clear_connecting(xprt);
-	up_read(&xprt->owner_env->op_sem);
-	(void)set_exec_env(ve);
+	up_read(&ve->op_sem);
+	(void)set_exec_env(old_ve);
 }
 
 /*
@@ -1150,11 +1151,12 @@ static void xs_tcp_connect_worker(void *
 	struct rpc_xprt *xprt = (struct rpc_xprt *)args;
 	struct socket *sock = xprt->sock;
 	int err, status = -EIO;
-	struct ve_struct *ve;
+	struct ve_struct *ve, *old_ve;
 
-	ve = set_exec_env(xprt->owner_env);
-	down_read(&xprt->owner_env->op_sem);
-	if (!xprt->owner_env->is_running)
+	ve = xprt->owner_env;
+	old_ve = set_exec_env(ve);
+	down_read(&ve->op_sem);
+	if (!ve->is_running)
 		goto out;
 	if (xprt->shutdown || xprt->addr.sin_port == 0)
 		goto out;
@@ -1208,7 +1210,7 @@ static void xs_tcp_connect_worker(void *
 
 	/* wait, before we connect, if there's a user specified src
 	   addr, honour it */
-	if (xprt_rpc_src_addr != 0 && ve_is_super(xprt->owner_env)) {
+	if (xprt_rpc_src_addr != 0 && ve_is_super(ve)) {
 		struct sock *sk = sock->sk;
 		struct inet_sock *inet = inet_sk(sk);
 		lock_sock(sk);
@@ -1242,8 +1244,8 @@ out:
 	xprt_wake_pending_tasks(xprt, status);
 out_clear:
 	xprt_clear_connecting(xprt);
-	up_read(&xprt->owner_env->op_sem);
-	(void)set_exec_env(ve);
+	up_read(&ve->op_sem);
+	(void)set_exec_env(old_ve);
 }
 
 /**
