[Debian] Re: lenny updates

Kir Kolyshkin kir at openvz.org
Mon Mar 9 17:36:49 EDT 2009


Ola Lundqvist wrote:
> Hi Dann
>
> I have to ask Kir about some of the things. Kir, please comment on the below.
>
>   
>>>>> #501985:
>>>>> From: maximilian attems
>>>>> the upstream nfs fixes are abi breakers and thus can't be integrated
>>>>> at this point they will be for the first point release were abi
>>>>> breaking will be allowed again.
>>>>>           
>>>> What is the fix for this - does upstream openvz include it?
>>>>         
>>> Yes it is found upstream. See the file
>>> http://download.openvz.org/kernel/branches/2.6.26/current/patches/patch-chekhov.1-combined.gz
>>> The current patch do not touch any nfs/ files and upstream does. The patch
>>> now in use was not fully completed when it was incorporated by Maximilian.
>>>       
>> I see - so we need to identify which additional changes are needed.
>> http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=66ec7f7f493fb98e8baa6591e9225086ae640fb8
>> http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=39bb1ee59237272cd20e1f8696cefbd6a787cfc8
>>
>> Is this severe enough to fix in a stable release? If we consider this
>> a regression from etch (since kernel-patch-openvz supplied this), than
>> maybe so. Is the risk of regression low? Well - these patches would
>> only get applied on openvz kernels which currently don't support nfs
>> at all so, assuming these changes are nfs-specific, risk should be
>> low.
>>     
>
> This is where I need to ask Kir. Kir do you know the answer to this question?

If we do want to have working NFS from a container, the following 
patches are a must:

http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=66ec7f7f493fb98e8baa6591e9225086ae640fb8
http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=2a083801fe1655bf9e403469c494b83a72186f56
http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=b8b70c37c8b114780a02492703c9682d8b09a14b
http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=840ea01d953ca0ad7629ea66ca0f50685ca06921
http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=39bb1ee59237272cd20e1f8696cefbd6a787cfc8
http://git.openvz.org/?p=linux-2.6.26-openvz;a=commitdiff;h=ba0ce90476e6267f6c035f9c9ef7c45d6195ec6e

Those patches are also attached for your convenience.

Also, while I am at it... I am currently checking all the ~80 patches 
that are not in openvz lenny kernel. Looks like most are really needed. 
Let me suggest some in a few emails I will send as a reply to this one.
-------------- next part --------------
>From 66ec7f7f493fb98e8baa6591e9225086ae640fb8 Mon Sep 17 00:00:00 2001
From: Denis Lunev <den at openvz.org>
Date: Tue, 9 Sep 2008 18:32:50 +0400
Subject: [PATCH] nfs: fix nfs clinet in VE (finally)

Ah! Thanks to our Den we now have an NFS client back!

It turned out, that while going the 2.6.18->2.6.20->...->2.6.26
NFS changed too much and we didn't test it properly (nobody
required it badly) in the intermediate states, lost many hunks
and that's why the patch is *that* big.

Signed-off-by: Denis Lunev <den at openvz.org>
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
 fs/lockd/clntproc.c         |    4 ++
 fs/lockd/host.c             |   52 +++++++++++++++++++
 fs/lockd/svc.c              |   54 ++++++++++++++++----
 fs/lockd/svcsubs.c          |    3 +
 fs/nfs/client.c             |   11 ++++
 fs/nfs/super.c              |   70 +++++++++++++++++++++++++-
 fs/super.c                  |    2 +
 include/linux/lockd/lockd.h |    8 ++-
 include/linux/nfs_fs_sb.h   |    1 +
 include/linux/sunrpc/clnt.h |    2 +
 include/linux/sunrpc/xprt.h |    9 +++
 include/linux/ve.h          |   12 ++++
 include/linux/vzcalluser.h  |    1 +
 include/net/sock.h          |    7 +++
 net/socket.c                |    2 +-
 net/sunrpc/clnt.c           |  117 +++++++++++++++++++++++++++++++++++++++++-
 net/sunrpc/rpc_pipe.c       |    1 +
 net/sunrpc/sched.c          |   10 +++-
 net/sunrpc/sunrpc_syms.c    |    5 ++
 net/sunrpc/svcsock.c        |   21 ++------
 net/sunrpc/xprt.c           |    8 +++
 net/sunrpc/xprtsock.c       |   61 ++++++++++++++++++++--
 22 files changed, 417 insertions(+), 44 deletions(-)

diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 5df517b..d05fcba 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -156,12 +156,15 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
 {
 	struct nlm_rqst		*call;
 	int			status;
+	struct ve_struct *ve;
 
 	nlm_get_host(host);
 	call = nlm_alloc_call(host);
 	if (call == NULL)
 		return -ENOMEM;
 
+	ve = set_exec_env(host->owner_env);
+
 	nlmclnt_locks_init_private(fl, host);
 	/* Set up the argument struct */
 	nlmclnt_setlockargs(call, fl);
@@ -181,6 +184,7 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl)
 	fl->fl_ops = NULL;
 
 	dprintk("lockd: clnt proc returns %d\n", status);
+	(void)set_exec_env(ve);
 	return status;
 }
 EXPORT_SYMBOL_GPL(nlmclnt_proc);
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index a17664c..cfa0cf3 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -53,6 +53,7 @@ static struct nlm_host *nlm_lookup_host(int server,
 	struct nlm_host	*host;
 	struct nsm_handle *nsm = NULL;
 	int		hash;
+	struct ve_struct *ve;
 
 	dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
 			", p=%d, v=%u, my role=%s, name=%.*s)\n",
@@ -78,10 +79,14 @@ static struct nlm_host *nlm_lookup_host(int server,
 	 * different NLM rpc_clients into one single nlm_host object.
 	 * This would allow us to have one nlm_host per address.
 	 */
+
+	ve = get_exec_env();
 	chain = &nlm_hosts[hash];
 	hlist_for_each_entry(host, pos, chain, h_hash) {
 		if (!nlm_cmp_addr(&host->h_addr, sin))
 			continue;
+		if (!ve_accessible_strict(host->owner_env, ve))
+			continue;
 
 		/* See if we have an NSM handle for this client */
 		if (!nsm)
@@ -141,6 +146,7 @@ static struct nlm_host *nlm_lookup_host(int server,
 	spin_lock_init(&host->h_lock);
 	INIT_LIST_HEAD(&host->h_granted);
 	INIT_LIST_HEAD(&host->h_reclaim);
+	host->owner_env    = ve;
 
 	nrhosts++;
 out:
@@ -454,6 +460,52 @@ nlm_gc_hosts(void)
 	next_gc = jiffies + NLM_HOST_COLLECT;
 }
 
+#ifdef CONFIG_VE
+void ve_nlm_shutdown_hosts(struct ve_struct *ve)
+{
+	envid_t veid = ve->veid;
+	int  i;
+
+	dprintk("lockd: shutting down host module for ve %d\n", veid);
+	mutex_lock(&nlm_host_mutex);
+
+	/* Perform a garbage collection pass */
+	for (i = 0; i < NLM_HOST_NRHASH; i++) {
+		struct nlm_host	*host;
+		struct hlist_node *pos;
+
+		hlist_for_each_entry(host, pos, &nlm_hosts[i], h_hash) {
+			struct rpc_clnt	*clnt;
+
+			if (ve != host->owner_env)
+				continue;
+
+			hlist_del(&host->h_hash);
+			if (host->h_nsmhandle)
+				host->h_nsmhandle->sm_monitored = 0;
+			dprintk("lockd: delete host %s ve %d\n", host->h_name,
+				veid);
+			if ((clnt = host->h_rpcclnt) != NULL) {
+				if (!list_empty(&clnt->cl_tasks)) {
+					struct rpc_xprt *xprt;
+
+					printk(KERN_WARNING
+						"lockd: active RPC handle\n");
+					rpc_killall_tasks(clnt);
+					xprt = clnt->cl_xprt;
+					xprt_disconnect_done(xprt);
+					xprt->ops->close(xprt);
+				} else
+					rpc_shutdown_client(clnt);
+			}
+			kfree(host);
+			nrhosts--;
+		}
+	}
+
+	mutex_unlock(&nlm_host_mutex);
+}
+#endif
 
 /*
  * Manage NSM handles
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 2169af4..f9f02fc 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -27,6 +27,7 @@
 #include <linux/mutex.h>
 #include <linux/kthread.h>
 #include <linux/freezer.h>
+#include <linux/ve_proto.h>
 
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/stats.h>
@@ -48,11 +49,13 @@ struct nlmsvc_binding *		nlmsvc_ops;
 EXPORT_SYMBOL(nlmsvc_ops);
 
 static DEFINE_MUTEX(nlmsvc_mutex);
-static unsigned int		nlmsvc_users;
-static struct task_struct	*nlmsvc_task;
-static struct svc_serv		*nlmsvc_serv;
-int				nlmsvc_grace_period;
-unsigned long			nlmsvc_timeout;
+#ifndef CONFIG_VE
+static unsigned int		_nlmsvc_users;
+static struct task_struct	*_nlmsvc_task;
+int				_nlmsvc_grace_period;
+unsigned long			_nlmsvc_timeout;
+static struct svc_serv		*_nlmsvc_serv;
+#endif
 
 /*
  * These can be set at insmod time (useful for NFS as root filesystem),
@@ -175,6 +178,10 @@ lockd(void *vrqstp)
 		 */
 		err = svc_recv(rqstp, timeout);
 		if (err == -EAGAIN || err == -EINTR) {
+#ifdef CONFIG_VE
+			if (!get_exec_env()->is_running)
+				break;
+#endif
 			preverr = err;
 			continue;
 		}
@@ -338,12 +345,12 @@ lockd_down(void)
 	} else {
 		printk(KERN_ERR "lockd_down: no users! task=%p\n",
 			nlmsvc_task);
-		BUG();
+		goto out;
 	}
 
 	if (!nlmsvc_task) {
 		printk(KERN_ERR "lockd_down: no lockd running.\n");
-		BUG();
+		goto out;
 	}
 	kthread_stop(nlmsvc_task);
 out:
@@ -485,6 +492,29 @@ static int lockd_authenticate(struct svc_rqst *rqstp)
 	return SVC_DENIED;
 }
 
+#ifdef CONFIG_VE
+extern void ve_nlm_shutdown_hosts(struct ve_struct *ve);
+
+static int ve_lockd_start(void *data)
+{
+	return 0;
+}
+
+static void ve_lockd_stop(void *data)
+{
+	struct ve_struct *ve = (struct ve_struct *)data;
+
+	ve_nlm_shutdown_hosts(ve);
+	flush_scheduled_work();
+}
+
+static struct ve_hook lockd_hook = {
+	.init	  = ve_lockd_start,
+	.fini	  = ve_lockd_stop,
+	.owner	  = THIS_MODULE,
+	.priority = HOOK_PRIO_FS,
+};
+#endif
 
 param_set_min_max(port, int, simple_strtol, 0, 65535)
 param_set_min_max(grace_period, unsigned long, simple_strtoul,
@@ -512,16 +542,20 @@ module_param(nsm_use_hostnames, bool, 0644);
 
 static int __init init_nlm(void)
 {
+	ve_hook_register(VE_SS_CHAIN, &lockd_hook);
 #ifdef CONFIG_SYSCTL
 	nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root);
-	return nlm_sysctl_table ? 0 : -ENOMEM;
-#else
-	return 0;
+	if (nlm_sysctl_table == NULL) {
+		ve_hook_unregister(&lockd_hook);
+		return -ENOMEM;
+	}
 #endif
+	return 0;
 }
 
 static void __exit exit_nlm(void)
 {
+	ve_hook_unregister(&lockd_hook);
 	/* FIXME: delete all NLM clients */
 	nlm_shutdown_hosts();
 #ifdef CONFIG_SYSCTL
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index d1c48b5..c226c9d 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -335,6 +335,9 @@ nlmsvc_is_client(void *data, struct nlm_host *dummy)
 {
 	struct nlm_host *host = data;
 
+	if (!ve_accessible_strict(host->owner_env, get_exec_env()))
+		return 0;
+
 	if (host->h_server) {
 		/* we are destroying locks even though the client
 		 * hasn't asked us too, so don't unmonitor the
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index f2a092c..3366257 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -127,6 +127,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
 
 	atomic_set(&clp->cl_count, 1);
 	clp->cl_cons_state = NFS_CS_INITING;
+	clp->owner_env = get_exec_env();
 
 	memcpy(&clp->cl_addr, cl_init->addr, cl_init->addrlen);
 	clp->cl_addrlen = cl_init->addrlen;
@@ -257,6 +258,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,
 struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
 {
 	struct nfs_client *clp;
+	struct ve_struct *ve = get_exec_env();
 
 	spin_lock(&nfs_client_lock);
 	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
@@ -272,6 +274,9 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion)
 
 		if (addr->sa_family != clap->sa_family)
 			continue;
+		if (!ve_accessible_strict(clp->owner_env, ve))
+			continue;
+
 		/* Match only the IP address, not the port number */
 		if (!nfs_sockaddr_match_ipaddr(addr, clap))
 			continue;
@@ -292,6 +297,7 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
 {
 	struct sockaddr *sap = (struct sockaddr *)&clp->cl_addr;
 	u32 nfsvers = clp->rpc_ops->version;
+	struct ve_struct *ve = get_exec_env();
 
 	spin_lock(&nfs_client_lock);
 	list_for_each_entry_continue(clp, &nfs_client_list, cl_share_link) {
@@ -307,6 +313,9 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
 
 		if (sap->sa_family != clap->sa_family)
 			continue;
+		if (!ve_accessible_strict(clp->owner_env, ve))
+			continue;
+
 		/* Match only the IP address, not the port number */
 		if (!nfs_sockaddr_match_ipaddr(sap, clap))
 			continue;
@@ -326,7 +335,9 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp)
 static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *data)
 {
 	struct nfs_client *clp;
+	struct ve_struct *ve;
 
+	ve = get_exec_env();
 	list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
 		/* Don't match clients that failed to initialise properly */
 		if (clp->cl_cons_state < 0)
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 614efee..cb4e28a 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -50,6 +50,9 @@
 #include <linux/nfs_xdr.h>
 #include <linux/magic.h>
 #include <linux/parser.h>
+#include <linux/ve_proto.h>
+#include <linux/vzcalluser.h>
+#include <linux/ve_nfs.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -213,7 +216,8 @@ static struct file_system_type nfs_fs_type = {
 	.name		= "nfs",
 	.get_sb		= nfs_get_sb,
 	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|
+			  FS_BINARY_MOUNTDATA|FS_VIRTUALIZED,
 };
 
 struct file_system_type nfs_xdev_fs_type = {
@@ -221,7 +225,8 @@ struct file_system_type nfs_xdev_fs_type = {
 	.name		= "nfs",
 	.get_sb		= nfs_xdev_get_sb,
 	.kill_sb	= nfs_kill_super,
-	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+	.fs_flags	= FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|
+			  FS_BINARY_MOUNTDATA|FS_VIRTUALIZED,
 };
 
 static const struct super_operations nfs_sops = {
@@ -286,6 +291,55 @@ static struct shrinker acl_shrinker = {
 	.seeks		= DEFAULT_SEEKS,
 };
 
+#ifdef CONFIG_VE
+static int ve_nfs_start(void *data)
+{
+	return 0;
+}
+
+static void ve_nfs_stop(void *data)
+{
+	struct ve_struct *ve;
+	struct super_block *sb;
+
+	flush_scheduled_work();
+
+	ve = (struct ve_struct *)data;
+	/* Basically, on a valid stop we can be here iff NFS was mounted
+	   read-only. In such a case client force-stop is not a problem.
+	   If we are here and NFS is read-write, we are in a FORCE stop, so
+	   force the client to stop.
+	   Lock daemon is already dead.
+	   Only superblock client remains. Den */
+	spin_lock(&sb_lock);
+	list_for_each_entry(sb, &super_blocks, s_list) {
+		struct rpc_clnt *clnt;
+		struct rpc_xprt *xprt;
+		if (sb->s_type != &nfs_fs_type)
+			continue;
+		clnt = NFS_SB(sb)->client;
+		if (!ve_accessible_strict(clnt->cl_xprt->owner_env, ve))
+			continue;
+		clnt->cl_broken = 1;
+		rpc_killall_tasks(clnt);
+
+		xprt = clnt->cl_xprt;
+		xprt_disconnect_done(xprt);
+		xprt->ops->close(xprt);
+	}
+	spin_unlock(&sb_lock);
+
+	flush_scheduled_work();
+}
+
+static struct ve_hook nfs_hook = {
+	.init	  = ve_nfs_start,
+	.fini	  = ve_nfs_stop,
+	.owner	  = THIS_MODULE,
+	.priority = HOOK_PRIO_NET_POST,
+};
+#endif
+
 /*
  * Register the NFS filesystems
  */
@@ -306,6 +360,7 @@ int __init register_nfs_fs(void)
 		goto error_2;
 #endif
 	register_shrinker(&acl_shrinker);
+	ve_hook_register(VE_SS_CHAIN, &nfs_hook);
 	return 0;
 
 #ifdef CONFIG_NFS_V4
@@ -324,6 +379,7 @@ error_0:
 void __exit unregister_nfs_fs(void)
 {
 	unregister_shrinker(&acl_shrinker);
+	ve_hook_unregister(&nfs_hook);
 #ifdef CONFIG_NFS_V4
 	unregister_filesystem(&nfs4_fs_type);
 #endif
@@ -1591,6 +1647,11 @@ static int nfs_get_sb(struct file_system_type *fs_type,
 		.mntflags = flags,
 	};
 	int error = -ENOMEM;
+	struct ve_struct *ve;
+
+	ve = get_exec_env();
+	if (!ve_is_super(ve) && !(ve->features & VE_FEATURE_NFS))
+		return -ENODEV;
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
@@ -1700,6 +1761,11 @@ static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
 		.mntflags = flags,
 	};
 	int error;
+	struct ve_struct *ve;
+
+	ve = get_exec_env();
+	if (!ve_is_super(ve) && !(ve->features & VE_FEATURE_NFS))
+		return -ENODEV;
 
 	dprintk("--> nfs_xdev_get_sb()\n");
 
diff --git a/fs/super.c b/fs/super.c
index 55ce500..960317f 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -44,7 +44,9 @@
 
 
 LIST_HEAD(super_blocks);
+EXPORT_SYMBOL_GPL(super_blocks);
 DEFINE_SPINLOCK(sb_lock);
+EXPORT_SYMBOL_GPL(sb_lock);
 
 /**
  *	alloc_super	-	create new superblock
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 102d928..7ef434d 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -61,6 +61,7 @@ struct nlm_host {
 	struct list_head	h_granted;	/* Locks in GRANTED state */
 	struct list_head	h_reclaim;	/* Locks in RECLAIM state */
 	struct nsm_handle *	h_nsmhandle;	/* NSM status handle */
+	struct ve_struct *	owner_env;	/* VE owning the host */
 };
 
 struct nsm_handle {
@@ -152,8 +153,11 @@ extern struct svc_procedure	nlmsvc_procedures[];
 #ifdef CONFIG_LOCKD_V4
 extern struct svc_procedure	nlmsvc_procedures4[];
 #endif
-extern int			nlmsvc_grace_period;
-extern unsigned long		nlmsvc_timeout;
+
+#include <linux/ve_nfs.h>
+extern int			_nlmsvc_grace_period;
+extern unsigned long		_nlmsvc_timeout;
+
 extern int			nsm_use_hostnames;
 
 /*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index c9beacd..cb87ca2 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -70,6 +70,7 @@ struct nfs_client {
 	char			cl_ipaddr[48];
 	unsigned char		cl_id_uniquifier;
 #endif
+	struct ve_struct	*owner_env;
 };
 
 /*
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 6fff7f8..7b4d4cf 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -43,6 +43,7 @@ struct rpc_clnt {
 	unsigned int		cl_softrtry : 1,/* soft timeouts */
 				cl_discrtry : 1,/* disconnect before retry */
 				cl_autobind : 1;/* use getport() */
+	unsigned int		cl_broken   : 1;/* no responce for too long */
 
 	struct rpc_rtt *	cl_rtt;		/* RTO estimator data */
 	const struct rpc_timeout *cl_timeout;	/* Timeout strategy */
@@ -56,6 +57,7 @@ struct rpc_clnt {
 	struct rpc_rtt		cl_rtt_default;
 	struct rpc_timeout	cl_timeout_default;
 	struct rpc_program *	cl_program;
+	unsigned long		cl_pr_time;
 	char			cl_inline_name[32];
 };
 
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 4d80a11..ceee9a3 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -24,6 +24,14 @@
 #define RPC_MAX_SLOT_TABLE	(128U)
 
 /*
+ * Grand abort timeout (stop the client if occures)
+ */
+extern int xprt_abort_timeout;
+
+#define RPC_MIN_ABORT_TIMEOUT	300
+#define RPC_MAX_ABORT_TIMEOUT	INT_MAX
+
+/*
  * This describes a timeout strategy
  */
 struct rpc_timeout {
@@ -123,6 +131,7 @@ struct rpc_xprt_ops {
 struct rpc_xprt {
 	struct kref		kref;		/* Reference count */
 	struct rpc_xprt_ops *	ops;		/* transport methods */
+	struct ve_struct *	owner_env;	/* VE owner of mount */
 
 	const struct rpc_timeout *timeout;	/* timeout parms */
 	struct sockaddr_storage	addr;		/* server address */
diff --git a/include/linux/ve.h b/include/linux/ve.h
index 7025716..970aadc 100644
--- a/include/linux/ve.h
+++ b/include/linux/ve.h
@@ -139,6 +139,7 @@ struct ve_cpu_stats {
 
 struct ve_ipt_recent;
 struct ve_xt_hashlimit;
+struct svc_serv;
 
 struct cgroup;
 struct css_set;
@@ -183,6 +184,8 @@ struct ve_struct {
 	struct devpts_config	*devpts_config;
 #endif
 
+	struct ve_nfs_context	*nfs_context;
+
 	struct file_system_type *shmem_fstype;
 	struct vfsmount		*shmem_mnt;
 #ifdef CONFIG_SYSFS
@@ -274,6 +277,15 @@ struct ve_struct {
 	struct proc_dir_entry	*monitor_proc;
 	unsigned long		meminfo_val;
 
+#if defined(CONFIG_NFS_FS) || defined(CONFIG_NFS_FS_MODULE) \
+	|| defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
+	unsigned int		_nlmsvc_users;
+	struct task_struct*	_nlmsvc_task;
+	int			_nlmsvc_grace_period;
+	unsigned long		_nlmsvc_timeout;
+	struct svc_serv*	_nlmsvc_serv;
+#endif
+
 	struct nsproxy		*ve_ns;
 	struct net		*ve_netns;
 	struct cgroup		*ve_cgroup;
diff --git a/include/linux/vzcalluser.h b/include/linux/vzcalluser.h
index 9736479..a62b84c 100644
--- a/include/linux/vzcalluser.h
+++ b/include/linux/vzcalluser.h
@@ -102,6 +102,7 @@ struct env_create_param3 {
 };
 
 #define VE_FEATURE_SYSFS	(1ULL << 0)
+#define VE_FEATURE_NFS		(1ULL << 1)
 #define VE_FEATURE_DEF_PERMS	(1ULL << 2)
 
 #define VE_FEATURES_OLD		(VE_FEATURE_SYSFS)
diff --git a/include/net/sock.h b/include/net/sock.h
index 873caf6..718e410 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1334,6 +1334,13 @@ static inline void sk_change_net(struct sock *sk, struct net *net)
 	sock_net_set(sk, hold_net(net));
 }
 
+static inline void sk_change_net_get(struct sock *sk, struct net *net)
+{
+	struct net *old_net = sock_net(sk);
+	sock_net_set(sk, get_net(net));
+	put_net(old_net);
+}
+
 extern void sock_enable_timestamp(struct sock *sk);
 extern int sock_get_timestamp(struct sock *, struct timeval __user *);
 extern int sock_get_timestampns(struct sock *, struct timespec __user *);
diff --git a/net/socket.c b/net/socket.c
index 09d8fc5..799f3c9 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2363,7 +2363,7 @@ int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
 	struct ve_struct *old_env;
 
 	set_fs(KERNEL_DS);
-	old_env = set_exec_env(get_ve0());
+	old_env = set_exec_env(sock->sk->owner_env);
 	err = sock->ops->ioctl(sock, cmd, arg);
 	(void)set_exec_env(old_env);
 	set_fs(oldfs);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 8945307..f303e1d 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -31,6 +31,7 @@
 #include <linux/utsname.h>
 #include <linux/workqueue.h>
 #include <linux/in6.h>
+#include <linux/ve_proto.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/rpc_pipe_fs.h>
@@ -89,6 +90,35 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)
 	spin_unlock(&rpc_client_lock);
 }
 
+/*
+ * Grand abort timeout (stop the client if occures)
+ */
+int xprt_abort_timeout = RPC_MAX_ABORT_TIMEOUT;
+
+static int rpc_abort_hard(struct rpc_task *task)
+{
+	struct rpc_clnt *clnt;
+	clnt = task->tk_client;
+
+	if (clnt->cl_pr_time == 0) {
+		clnt->cl_pr_time = jiffies;
+		return 0;
+	}
+	if (xprt_abort_timeout == RPC_MAX_ABORT_TIMEOUT)
+		return 0;
+	if (time_before(jiffies, clnt->cl_pr_time + xprt_abort_timeout * HZ))
+		return 0;
+
+	clnt->cl_broken = 1;
+	rpc_killall_tasks(clnt);
+	return -ETIMEDOUT;
+}
+
+static void rpc_abort_clear(struct rpc_task *task)
+{
+	task->tk_client->cl_pr_time = 0;
+}
+
 static int
 rpc_setup_pipedir(struct rpc_clnt *clnt, char *dir_name)
 {
@@ -178,6 +208,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
 	clnt->cl_vers     = version->number;
 	clnt->cl_stats    = program->stats;
 	clnt->cl_metrics  = rpc_alloc_iostats(clnt);
+	clnt->cl_broken = 0;
 	err = -ENOMEM;
 	if (clnt->cl_metrics == NULL)
 		goto out_no_stats;
@@ -293,6 +324,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 	xprt = xprt_create_transport(&xprtargs);
 	if (IS_ERR(xprt))
 		return (struct rpc_clnt *)xprt;
+	xprt->owner_env = get_ve(get_exec_env());
 
 	/*
 	 * By default, kernel RPC client connects from a reserved port.
@@ -305,13 +337,16 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 		xprt->resvport = 0;
 
 	clnt = rpc_new_client(args, xprt);
-	if (IS_ERR(clnt))
+	if (IS_ERR(clnt)) {
+		put_ve(xprt->owner_env);
 		return clnt;
+	}
 
 	if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
 		int err = rpc_ping(clnt, RPC_TASK_SOFT);
 		if (err != 0) {
 			rpc_shutdown_client(clnt);
+			put_ve(xprt->owner_env);
 			return ERR_PTR(err);
 		}
 	}
@@ -517,6 +552,9 @@ struct rpc_task *rpc_run_task(const struct rpc_task_setup *task_setup_data)
 {
 	struct rpc_task *task, *ret;
 
+	if (task_setup_data->rpc_client->cl_broken)
+		return ERR_PTR(-EIO);
+
 	task = rpc_new_task(task_setup_data);
 	if (task == NULL) {
 		rpc_release_calldata(task_setup_data->callback_ops,
@@ -923,6 +961,7 @@ call_bind_status(struct rpc_task *task)
 
 	if (task->tk_status >= 0) {
 		dprint_status(task);
+		rpc_abort_clear(task);
 		task->tk_status = 0;
 		task->tk_action = call_connect;
 		return;
@@ -948,6 +987,10 @@ call_bind_status(struct rpc_task *task)
 	case -ETIMEDOUT:
 		dprintk("RPC: %5u rpcbind request timed out\n",
 				task->tk_pid);
+		if (rpc_abort_hard(task)) {
+			status = -EIO;
+			break;
+		}
 		goto retry_timeout;
 	case -EPFNOSUPPORT:
 		/* server doesn't support any rpcbind version we know of */
@@ -1013,6 +1056,8 @@ call_connect_status(struct rpc_task *task)
 
 	/* Something failed: remote service port may have changed */
 	rpc_force_rebind(clnt);
+	if (rpc_abort_hard(task))
+		goto exit;
 
 	switch (status) {
 	case -ENOTCONN:
@@ -1025,6 +1070,7 @@ call_connect_status(struct rpc_task *task)
 		task->tk_action = call_timeout;
 		return;
 	}
+exit:
 	rpc_exit(task, -EIO);
 }
 
@@ -1156,7 +1202,7 @@ call_timeout(struct rpc_task *task)
 	dprintk("RPC: %5u call_timeout (major)\n", task->tk_pid);
 	task->tk_timeouts++;
 
-	if (RPC_IS_SOFT(task)) {
+	if (RPC_IS_SOFT(task) || rpc_abort_hard(task)) {
 		printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
 				clnt->cl_protname, clnt->cl_server);
 		rpc_exit(task, -EIO);
@@ -1201,6 +1247,7 @@ call_decode(struct rpc_task *task)
 		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
 	}
 
+	rpc_abort_clear(task);
 	/*
 	 * Ensure that we see all writes made by xprt_complete_rqst()
 	 * before it changed req->rq_received.
@@ -1213,7 +1260,7 @@ call_decode(struct rpc_task *task)
 				sizeof(req->rq_rcv_buf)) != 0);
 
 	if (req->rq_rcv_buf.len < 12) {
-		if (!RPC_IS_SOFT(task)) {
+		if (!RPC_IS_SOFT(task) && !rpc_abort_hard(task)) {
 			task->tk_action = call_bind;
 			clnt->cl_stats->rpcretrans++;
 			goto out_retry;
@@ -1558,3 +1605,67 @@ out:
 	spin_unlock(&rpc_client_lock);
 }
 #endif
+
+#ifdef CONFIG_VE
+static int ve_sunrpc_start(void *data)
+{
+	return 0;
+}
+
+void ve_sunrpc_stop(void *data)
+{
+	struct ve_struct *ve = (struct ve_struct *)data;
+	struct rpc_clnt *clnt;
+	struct rpc_task	*rovr;
+
+	dprintk("RPC:       killing all tasks for VE %d\n", ve->veid);
+
+	spin_lock(&rpc_client_lock);
+	list_for_each_entry(clnt, &all_clients, cl_clients) {
+		if (clnt->cl_xprt->owner_env != ve)
+			continue;
+
+		spin_lock(&clnt->cl_lock);
+		list_for_each_entry(rovr, &clnt->cl_tasks, tk_task) {
+			if (!RPC_IS_ACTIVATED(rovr))
+				continue;
+			printk(KERN_WARNING "RPC: Killing task %d client %p\n",
+			       rovr->tk_pid, clnt);
+
+			rovr->tk_flags |= RPC_TASK_KILLED;
+			rpc_exit(rovr, -EIO);
+			rpc_wake_up_queued_task(rovr->tk_waitqueue, rovr);
+		}
+		schedule_work(&clnt->cl_xprt->task_cleanup);
+		spin_unlock(&clnt->cl_lock);
+	}
+	spin_unlock(&rpc_client_lock);
+
+	flush_scheduled_work();
+}
+
+static struct ve_hook sunrpc_hook = {
+	.init	  = ve_sunrpc_start,
+	.fini	  = ve_sunrpc_stop,
+	.owner	  = THIS_MODULE,
+	.priority = HOOK_PRIO_NET_PRE,
+};
+
+void ve_sunrpc_hook_register(void)
+{
+	ve_hook_register(VE_SS_CHAIN, &sunrpc_hook);
+}
+
+void ve_sunrpc_hook_unregister(void)
+{
+	ve_hook_unregister(&sunrpc_hook);
+}
+#else
+void ve_sunrpc_hook_register(void)
+{
+}
+
+void ve_sunrpc_hook_unregister(void)
+{
+}
+#endif
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 5a9b0e7..ab6bf80 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -894,6 +894,7 @@ static struct file_system_type rpc_pipe_fs_type = {
 	.name		= "rpc_pipefs",
 	.get_sb		= rpc_get_sb,
 	.kill_sb	= kill_litter_super,
+	.fs_flags	= FS_VIRTUALIZED,	
 };
 
 static void
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 4fba93a..265296d 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -617,7 +617,7 @@ static void __rpc_execute(struct rpc_task *task)
 	int		status = 0;
 	struct ve_struct *env;
 
-	env = set_exec_env(get_ve0());
+	env = set_exec_env(task->tk_client->cl_xprt->owner_env);
 	dprintk("RPC: %5u __rpc_execute flags=0x%x\n",
 			task->tk_pid, task->tk_flags);
 
@@ -663,10 +663,14 @@ static void __rpc_execute(struct rpc_task *task)
 		rpc_clear_running(task);
 		if (RPC_IS_ASYNC(task)) {
 			/* Careful! we may have raced... */
-			if (RPC_IS_QUEUED(task))
+			if (RPC_IS_QUEUED(task)) {
+				(void)set_exec_env(env);
 				return;
-			if (rpc_test_and_set_running(task))
+			}
+			if (rpc_test_and_set_running(task)) {
+				(void)set_exec_env(env);
 				return;
+			}
 			continue;
 		}
 
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 843629f..94c3fb0 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -24,6 +24,9 @@
 
 extern struct cache_detail ip_map_cache, unix_gid_cache;
 
+extern void ve_sunrpc_hook_register(void);
+extern void ve_sunrpc_hook_unregister(void);
+
 static int __init
 init_sunrpc(void)
 {
@@ -46,6 +49,7 @@ init_sunrpc(void)
 	svc_init_xprt_sock();	/* svc sock transport */
 	init_socket_xprt();	/* clnt sock transport */
 	rpcauth_init_module();
+	ve_sunrpc_hook_register();
 out:
 	return err;
 }
@@ -53,6 +57,7 @@ out:
 static void __exit
 cleanup_sunrpc(void)
 {
+	ve_sunrpc_hook_unregister();
 	rpcauth_remove_module();
 	cleanup_socket_xprt();
 	svc_cleanup_xprt_sock();
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 029c673..0d49dfc 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -180,7 +180,7 @@ static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
 	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
 	struct ve_struct *old_env;
 
-	old_env = set_exec_env(get_ve0());
+	old_env = set_exec_env(sock->sk->owner_env);
 
 	slen = xdr->len;
 
@@ -321,14 +321,11 @@ static int svc_recvfrom(struct svc_rqst *rqstp, struct kvec *iov, int nr,
 		.msg_flags	= MSG_DONTWAIT,
 	};
 	int len;
-	struct ve_struct *old_env;
 
 	rqstp->rq_xprt_hlen = 0;
 
-	old_env = set_exec_env(get_ve0());
 	len = kernel_recvmsg(svsk->sk_sock, &msg, iov, nr, buflen,
 				msg.msg_flags);
-	(void)set_exec_env(get_ve0());
 
 	dprintk("svc: socket %p recvfrom(%p, %Zu) = %d\n",
 		svsk, iov[0].iov_base, iov[0].iov_len, len);
@@ -727,13 +724,11 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 	struct svc_sock	*newsvsk;
 	int		err, slen;
 	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
-	struct ve_struct *old_env;
 
 	dprintk("svc: tcp_accept %p sock %p\n", svsk, sock);
 	if (!sock)
 		return NULL;
 
-	old_env = set_exec_env(get_ve0());
 	clear_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
 	err = kernel_accept(sock, &newsock, O_NONBLOCK);
 	if (err < 0) {
@@ -743,7 +738,7 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 		else if (err != -EAGAIN && net_ratelimit())
 			printk(KERN_WARNING "%s: accept failed (err %d)!\n",
 				   serv->sv_name, -err);
-		goto restore;
+		return NULL;
 	}
 	set_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags);
 
@@ -784,8 +779,6 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 	}
 	svc_xprt_set_local(&newsvsk->sk_xprt, sin, slen);
 
-	(void)set_exec_env(old_env);
-
 	if (serv->sv_stats)
 		serv->sv_stats->nettcpconn++;
 
@@ -793,8 +786,6 @@ static struct svc_xprt *svc_tcp_accept(struct svc_xprt *xprt)
 
 failed:
 	sock_release(newsock);
-restore:
-	(void)set_exec_env(old_env);
 	return NULL;
 }
 
@@ -1225,7 +1216,6 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
 	struct sockaddr *newsin = (struct sockaddr *)&addr;
 	int		newlen;
 	RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
-	struct ve_struct *old_env;
 
 	dprintk("svc: svc_create_socket(%s, %d, %s)\n",
 			serv->sv_program->pg_name, protocol,
@@ -1238,11 +1228,11 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
 	}
 	type = (protocol == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
 
-	old_env = set_exec_env(get_ve0());
 	error = sock_create_kern(sin->sa_family, type, protocol, &sock);
 	if (error < 0)
-		goto restore;
+		return ERR_PTR(-ENOMEM);
 
+	sk_change_net_get(sock->sk, get_exec_env()->ve_netns);
 	svc_reclassify_socket(sock);
 
 	if (type == SOCK_STREAM)
@@ -1263,15 +1253,12 @@ static struct svc_xprt *svc_create_socket(struct svc_serv *serv,
 
 	if ((svsk = svc_setup_socket(serv, sock, &error, flags)) != NULL) {
 		svc_xprt_set_local(&svsk->sk_xprt, newsin, newlen);
-		(void)set_exec_env(old_env);
 		return (struct svc_xprt *)svsk;
 	}
 
 bummer:
 	dprintk("svc: svc_create_socket error = %d\n", -error);
 	sock_release(sock);
-restore:
-	(void)set_exec_env(old_env);
 	return ERR_PTR(error);
 }
 
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index e1770f7..831ad1b 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -568,10 +568,13 @@ static void xprt_autoclose(struct work_struct *work)
 {
 	struct rpc_xprt *xprt =
 		container_of(work, struct rpc_xprt, task_cleanup);
+	struct ve_struct *ve;
 
+	ve = set_exec_env(xprt->owner_env);
 	xprt->ops->close(xprt);
 	clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
 	xprt_release_write(xprt, NULL);
+	(void)set_exec_env(ve);
 }
 
 /**
@@ -638,7 +641,9 @@ static void
 xprt_init_autodisconnect(unsigned long data)
 {
 	struct rpc_xprt *xprt = (struct rpc_xprt *)data;
+	struct ve_struct *ve;
 
+	ve = set_exec_env(xprt->owner_env);
 	spin_lock(&xprt->transport_lock);
 	if (!list_empty(&xprt->recv) || xprt->shutdown)
 		goto out_abort;
@@ -649,9 +654,11 @@ xprt_init_autodisconnect(unsigned long data)
 		xprt_release_write(xprt, NULL);
 	else
 		queue_work(rpciod_workqueue, &xprt->task_cleanup);
+	(void)set_exec_env(ve);
 	return;
 out_abort:
 	spin_unlock(&xprt->transport_lock);
+	(void)set_exec_env(ve);
 }
 
 /**
@@ -1049,6 +1056,7 @@ found:
 	xprt->last_used = jiffies;
 	xprt->cwnd = RPC_INITCWND;
 	xprt->bind_index = 0;
+	xprt->owner_env = get_exec_env();
 
 	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
 	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index ddbe981..7ade3e3 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -64,6 +64,8 @@ static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE;
 static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE;
 static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT;
 static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT;
+static int xprt_min_abort_timeout = RPC_MIN_ABORT_TIMEOUT;
+static int xprt_max_abort_timeout = RPC_MAX_ABORT_TIMEOUT;
 
 static struct ctl_table_header *sunrpc_table_header;
 
@@ -117,6 +119,16 @@ static ctl_table xs_tunables_table[] = {
 		.extra2		= &xprt_max_resvport_limit
 	},
 	{
+		.procname	= "abort_timeout",
+		.data		= &xprt_abort_timeout,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec_minmax,
+		.strategy	= &sysctl_intvec,
+		.extra1		= &xprt_min_abort_timeout,
+		.extra2		= &xprt_max_abort_timeout
+	},
+	{
 		.ctl_name = 0,
 	},
 };
@@ -754,18 +766,23 @@ out_release:
 static void xs_close(struct rpc_xprt *xprt)
 {
 	struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
-	struct socket *sock = transport->sock;
-	struct sock *sk = transport->inet;
-
-	if (!sk)
-		goto clear_close_wait;
+	struct socket *sock;
+	struct sock *sk;
 
 	dprintk("RPC:       xs_close xprt %p\n", xprt);
 
-	write_lock_bh(&sk->sk_callback_lock);
+	spin_lock_bh(&xprt->transport_lock);
+	if (transport->sock == NULL) {
+		spin_unlock_bh(&xprt->transport_lock);
+		goto clear_close_wait;
+	}
+	sock = transport->sock;
+	sk = transport->inet;
 	transport->inet = NULL;
 	transport->sock = NULL;
+	spin_unlock_bh(&xprt->transport_lock);
 
+	write_lock_bh(&sk->sk_callback_lock);
 	sk->sk_user_data = NULL;
 	sk->sk_data_ready = transport->old_data_ready;
 	sk->sk_state_change = transport->old_state_change;
@@ -1489,7 +1506,12 @@ static void xs_udp_connect_worker4(struct work_struct *work)
 	struct rpc_xprt *xprt = &transport->xprt;
 	struct socket *sock = transport->sock;
 	int err, status = -EIO;
+	struct ve_struct *ve;
 
+	ve = set_exec_env(xprt->owner_env);
+	down_read(&xprt->owner_env->op_sem);
+	if (!xprt->owner_env->is_running)
+		goto out;
 	if (xprt->shutdown || !xprt_bound(xprt))
 		goto out;
 
@@ -1500,6 +1522,7 @@ static void xs_udp_connect_worker4(struct work_struct *work)
 		dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
 		goto out;
 	}
+	sk_change_net_get(sock->sk, xprt->owner_env->ve_netns);
 	xs_reclassify_socket4(sock);
 
 	if (xs_bind4(transport, sock)) {
@@ -1515,6 +1538,8 @@ static void xs_udp_connect_worker4(struct work_struct *work)
 out:
 	xprt_wake_pending_tasks(xprt, status);
 	xprt_clear_connecting(xprt);
+	up_read(&xprt->owner_env->op_sem);
+	(void)set_exec_env(ve);
 }
 
 /**
@@ -1530,7 +1555,12 @@ static void xs_udp_connect_worker6(struct work_struct *work)
 	struct rpc_xprt *xprt = &transport->xprt;
 	struct socket *sock = transport->sock;
 	int err, status = -EIO;
+	struct ve_struct *ve;
 
+	ve = set_exec_env(xprt->owner_env);
+	down_read(&xprt->owner_env->op_sem);
+	if (!xprt->owner_env->is_running)
+		goto out;
 	if (xprt->shutdown || !xprt_bound(xprt))
 		goto out;
 
@@ -1541,6 +1571,7 @@ static void xs_udp_connect_worker6(struct work_struct *work)
 		dprintk("RPC:       can't create UDP transport socket (%d).\n", -err);
 		goto out;
 	}
+	sk_change_net_get(sock->sk, xprt->owner_env->ve_netns);
 	xs_reclassify_socket6(sock);
 
 	if (xs_bind6(transport, sock) < 0) {
@@ -1556,6 +1587,8 @@ static void xs_udp_connect_worker6(struct work_struct *work)
 out:
 	xprt_wake_pending_tasks(xprt, status);
 	xprt_clear_connecting(xprt);
+	up_read(&xprt->owner_env->op_sem);
+	(void)set_exec_env(ve);
 }
 
 /*
@@ -1634,7 +1667,12 @@ static void xs_tcp_connect_worker4(struct work_struct *work)
 	struct rpc_xprt *xprt = &transport->xprt;
 	struct socket *sock = transport->sock;
 	int err, status = -EIO;
+	struct ve_struct *ve;
 
+	ve = set_exec_env(xprt->owner_env);
+	down_read(&xprt->owner_env->op_sem);
+	if (!xprt->owner_env->is_running)
+		goto out;
 	if (xprt->shutdown || !xprt_bound(xprt))
 		goto out;
 
@@ -1644,6 +1682,7 @@ static void xs_tcp_connect_worker4(struct work_struct *work)
 			dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
 			goto out;
 		}
+		sk_change_net_get(sock->sk, xprt->owner_env->ve_netns);
 		xs_reclassify_socket4(sock);
 
 		if (xs_bind4(transport, sock) < 0) {
@@ -1679,6 +1718,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);
 }
 
 /**
@@ -1694,7 +1735,12 @@ static void xs_tcp_connect_worker6(struct work_struct *work)
 	struct rpc_xprt *xprt = &transport->xprt;
 	struct socket *sock = transport->sock;
 	int err, status = -EIO;
+	struct ve_struct *ve;
 
+	ve = set_exec_env(xprt->owner_env);
+	down_read(&xprt->owner_env->op_sem);
+	if (!xprt->owner_env->is_running)
+		goto out;
 	if (xprt->shutdown || !xprt_bound(xprt))
 		goto out;
 
@@ -1704,6 +1750,7 @@ static void xs_tcp_connect_worker6(struct work_struct *work)
 			dprintk("RPC:       can't create TCP transport socket (%d).\n", -err);
 			goto out;
 		}
+		sk_change_net_get(sock->sk, xprt->owner_env->ve_netns);
 		xs_reclassify_socket6(sock);
 
 		if (xs_bind6(transport, sock) < 0) {
@@ -1738,6 +1785,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);
 }
 
 /**
-- 
1.6.0.6

-------------- next part --------------
>From 2a083801fe1655bf9e403469c494b83a72186f56 Mon Sep 17 00:00:00 2001
From: Denis Lunev <den at openvz.org>
Date: Wed, 10 Sep 2008 12:02:33 +0400
Subject: [PATCH] nfs: add missed ve_nfs.h file

Lost when committing 66ec7f7f493fb98e8baa6591e9225086ae640fb8

Signed-off-by: Denis Lunev <den at openvz.org>
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
 include/linux/ve_nfs.h |   30 ++++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/ve_nfs.h

diff --git a/include/linux/ve_nfs.h b/include/linux/ve_nfs.h
new file mode 100644
index 0000000..4ed5105
--- /dev/null
+++ b/include/linux/ve_nfs.h
@@ -0,0 +1,30 @@
+/*
+ * linux/include/ve_nfs.h
+ *
+ * VE context for NFS
+ *
+ * Copyright (C) 2007 SWsoft
+ */
+
+#ifndef __VE_NFS_H__
+#define __VE_NFS_H__
+
+#ifdef CONFIG_VE
+
+#include <linux/ve.h>
+
+#define NFS_CTX_FIELD(arg)  (get_exec_env()->_##arg)
+
+#else /* CONFIG_VE */
+
+#define NFS_CTX_FIELD(arg)	_##arg
+
+#endif /* CONFIG_VE */
+
+#define nlmsvc_grace_period	NFS_CTX_FIELD(nlmsvc_grace_period)
+#define nlmsvc_timeout		NFS_CTX_FIELD(nlmsvc_timeout)
+#define nlmsvc_users		NFS_CTX_FIELD(nlmsvc_users)
+#define nlmsvc_task		NFS_CTX_FIELD(nlmsvc_task)
+#define nlmsvc_serv		NFS_CTX_FIELD(nlmsvc_serv)
+
+#endif
-- 
1.6.0.6

-------------- next part --------------
>From b8b70c37c8b114780a02492703c9682d8b09a14b Mon Sep 17 00:00:00 2001
From: Vitaliy Gusev <vgusev at openvz.org>
Date: Wed, 24 Dec 2008 20:32:43 +0300
Subject: [PATCH] nfs: Fix access to freed memory

rpc_shutdown_client() frees xprt, so we can't use this xprt.
So move put_ve() to xprt::destroy level.

Bug https://bugzilla.sw.ru/show_bug.cgi?id=265628

Signed-off-by: Vitaliy Gusev <vgusev at openvz.org>
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
 net/sunrpc/clnt.c               |    2 --
 net/sunrpc/xprt.c               |    2 +-
 net/sunrpc/xprtrdma/transport.c |    1 +
 net/sunrpc/xprtsock.c           |    1 +
 4 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index f303e1d..b6f53f1 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -324,7 +324,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 	xprt = xprt_create_transport(&xprtargs);
 	if (IS_ERR(xprt))
 		return (struct rpc_clnt *)xprt;
-	xprt->owner_env = get_ve(get_exec_env());
 
 	/*
 	 * By default, kernel RPC client connects from a reserved port.
@@ -346,7 +345,6 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 		int err = rpc_ping(clnt, RPC_TASK_SOFT);
 		if (err != 0) {
 			rpc_shutdown_client(clnt);
-			put_ve(xprt->owner_env);
 			return ERR_PTR(err);
 		}
 	}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 831ad1b..23ce2ce 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1056,7 +1056,7 @@ found:
 	xprt->last_used = jiffies;
 	xprt->cwnd = RPC_INITCWND;
 	xprt->bind_index = 0;
-	xprt->owner_env = get_exec_env();
+	xprt->owner_env = get_ve(get_exec_env());
 
 	rpc_init_wait_queue(&xprt->binding, "xprt_binding");
 	rpc_init_wait_queue(&xprt->pending, "xprt_pending");
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index a564c1a..77714e3 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -286,6 +286,7 @@ xprt_rdma_destroy(struct rpc_xprt *xprt)
 
 	kfree(xprt->slot);
 	xprt->slot = NULL;
+	put_ve(xprt->owner_env);
 	kfree(xprt);
 
 	dprintk("RPC:       %s: returning\n", __func__);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 7ade3e3..27e62dd 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -816,6 +816,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
 	xs_close(xprt);
 	xs_free_peer_addresses(xprt);
 	kfree(xprt->slot);
+	put_ve(xprt->owner_env);
 	kfree(xprt);
 	module_put(THIS_MODULE);
 }
-- 
1.6.0.6

-------------- next part --------------
>From 840ea01d953ca0ad7629ea66ca0f50685ca06921 Mon Sep 17 00:00:00 2001
From: Denis Lunev <den at openvz.org>
Date: Mon, 29 Dec 2008 20:34:32 +0300
Subject: [PATCH] NFS: NFS super blocks in different VEs should be different

NFS: NFS super blocks in different VEs should be different

Teach nfs_compare_super to this

Bug #265926

Signed-off-by: Denis V. Lunev <den at openvz.org>
Signed-off-by: Vitaliy Gusev <vgusev at openvz.org>
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
 fs/nfs/super.c |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index cb4e28a..cf38e22 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1619,6 +1619,10 @@ static int nfs_compare_super(struct super_block *sb, void *data)
 	struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
 	int mntflags = sb_mntdata->mntflags;
 
+	if (!ve_accessible_strict(old->client->cl_xprt->owner_env,
+				  get_exec_env()))
+		return 0;
+
 	if (!nfs_compare_super_address(old, server))
 		return 0;
 	/* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */
-- 
1.6.0.6

-------------- next part --------------
>From 39bb1ee59237272cd20e1f8696cefbd6a787cfc8 Mon Sep 17 00:00:00 2001
From: Vitaliy Gusev <vgusev at openvz.org>
Date: Mon, 12 Jan 2009 17:29:54 +0300
Subject: [PATCH] nfs: Fix nfs_match_client()

nfs_match_client() can return nfs_client from other VE.

Bug https://bugzilla.sw.ru/show_bug.cgi?id=266951

Original-patch-by: Denis Lunev <den at openvz.org>
Signed-off-by: Vitaliy Gusev <vgusev at openvz.org>
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
 fs/nfs/client.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 3366257..d773ed5 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -343,6 +343,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
 		if (clp->cl_cons_state < 0)
 			continue;
 
+		if (!ve_accessible_strict(clp->owner_env, ve))
+				continue;
+
 		/* Different NFS versions cannot share the same nfs_client */
 		if (clp->rpc_ops != data->rpc_ops)
 			continue;
-- 
1.6.0.6

-------------- next part --------------
>From ba0ce90476e6267f6c035f9c9ef7c45d6195ec6e Mon Sep 17 00:00:00 2001
From: Vitaliy Gusev <vgusev at openvz.org>
Date: Tue, 13 Jan 2009 18:23:56 +0300
Subject: [PATCH] nfs: use kthread_run_ve to start lockd

Lockd is virtualized, so must be created in VE context.
The reason it worked before (in 2.6.18 kernel for example) is that lockd is
rewritten to use new kthread API, which was not capable for creating threads
in containers.

Signed-off-by: Vitaliy Gusev <vgusev at openvz.org>
Signed-off-by: Pavel Emelyanov <xemul at openvz.org>
---
 fs/lockd/svc.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index f9f02fc..50b29d5 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -307,7 +307,7 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
 	svc_sock_update_bufs(serv);
 	nlmsvc_serv = rqstp->rq_server;
 
-	nlmsvc_task = kthread_run(lockd, rqstp, serv->sv_name);
+	nlmsvc_task = kthread_run_ve(get_exec_env(), lockd, rqstp, serv->sv_name);
 	if (IS_ERR(nlmsvc_task)) {
 		error = PTR_ERR(nlmsvc_task);
 		nlmsvc_task = NULL;
-- 
1.6.0.6



More information about the Debian mailing list