2014-04-30 02:46:46

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 0/9] fix the NULL pointer when use nfs in diferent net ns

After 3.4 stable apply commit f7fb86c6e639(nfsd: use "init_net"
for portmapper). When starting NFSd in a non init_net network
namespace will trigger kernel panic. Because RPCBIND client
will be NULL when register RPC service with the local portmapper
in svc_addsock(). This new bug also exists in 3.8, but disappears
after patch commit 11f779421a39("containerize NFSd filesystem") in
3.9.

So backport Stanislav's patches from 3.8 and 3.9 to cleanup init_net
reference, and get proper network namespace from superblock instead of
using hard-coded "init_net" to make NFSd keep using a consistent network
namespace all the time to resolve the bug.

After this patchset, testing NFS in different network namespace will
not trigger kernel panic any more, and other NFS client can use the
NFS server's shared files normally which was started in init_net namespace.

v1->v2:
- no commit 7fb86c6e639(nfsd: use "init_net" for portmapper) which has been
apply to 3.4 stable in the first version
- one more fix patch commit 3064639423c4(nfsd: check passed socket's net matches
NFSd superblock's one) for commit 11f779421a39("nfsd: containerize NFSd filesystem")
- fix build error for commit db6e182c17cb(nfsd: pass net to nfsd_init_socks())

Stanislav Kinsbursky (9):
nfsd: pass net to nfsd_init_socks()
nfsd: pass net to nfsd_startup() and nfsd_shutdown()
nfsd: pass net to nfsd_create_serv()
nfsd: pass net to nfsd_svc()
nfsd: pass net to nfsd_set_nrthreads()
nfsd: pass net to __write_ports() and down
nfsd: pass proper net to nfsd_destroy() from NFSd kthreads
nfsd: containerize NFSd filesystem
nfsd: check passed socket's net matches NFSd superblock's one

fs/nfsd/nfsctl.c | 62 +++++++++++++++++++++++++++++-------------
fs/nfsd/nfsd.h | 6 ++--
fs/nfsd/nfssvc.c | 41 ++++++++++++++--------------
include/linux/sunrpc/svcsock.h | 1 +
net/sunrpc/svcsock.c | 16 +++++++++++
5 files changed, 83 insertions(+), 43 deletions(-)

--
1.8.2.2




2014-04-30 02:47:19

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 7/9] nfsd: pass proper net to nfsd_destroy() from NFSd kthreads

From: Stanislav Kinsbursky <[email protected]>

commit 88c47666171989ed4c5b1a5687df09511e8c5e35 upstream.

Since NFSd service is per-net now, we have to pass proper network
context in nfsd_shutdown() from NFSd kthreads.

The simplest way I found is to get proper net from one of transports
with permanent sockets.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4: adjust context]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfssvc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 0974818..5bc9380 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -483,6 +483,8 @@ static int
nfsd(void *vrqstp)
{
struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp;
+ struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list);
+ struct net *net = perm_sock->xpt_net;
int err, preverr = 0;

/* Lock module and set up kernel thread */
@@ -557,7 +559,7 @@ out:
/* Release the thread */
svc_exit_thread(rqstp);

- nfsd_destroy(&init_net);
+ nfsd_destroy(net);

/* Release module */
mutex_unlock(&nfsd_mutex);
--
1.8.2.2



2014-04-30 02:47:17

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 3/9] nfsd: pass net to nfsd_create_serv()

From: Stanislav Kinsbursky <[email protected]>

commit 6777436b0f072fb20a025a73e9b67a35ad8a5451 upstream.

Precursor patch. Hard-coded "init_net" will be replaced by proper one in
future.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4: adjust context]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfsctl.c | 4 ++--
fs/nfsd/nfsd.h | 2 +-
fs/nfsd/nfssvc.c | 5 ++---
3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index d014727..e18f0a5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -657,7 +657,7 @@ static ssize_t __write_ports_addfd(char *buf)
if (err != 0 || fd < 0)
return -EINVAL;

- err = nfsd_create_serv();
+ err = nfsd_create_serv(net);
if (err != 0)
return err;

@@ -708,7 +708,7 @@ static ssize_t __write_ports_addxprt(char *buf)
if (port < 1 || port > USHRT_MAX)
return -EINVAL;

- err = nfsd_create_serv();
+ err = nfsd_create_serv(net);
if (err != 0)
return err;

diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 1336a65..356da43 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -101,7 +101,7 @@ enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
int nfsd_vers(int vers, enum vers_op change);
int nfsd_minorversion(u32 minorversion, enum vers_op change);
void nfsd_reset_versions(void);
-int nfsd_create_serv(void);
+int nfsd_create_serv(struct net *net);

extern int nfsd_max_blksize;

diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index f8dae75..632d11e 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -326,10 +326,9 @@ static int nfsd_get_default_max_blksize(void)
return ret;
}

-int nfsd_create_serv(void)
+int nfsd_create_serv(struct net *net)
{
int error;
- struct net *net = &init_net;

WARN_ON(!mutex_is_locked(&nfsd_mutex));
if (nfsd_serv) {
@@ -451,7 +450,7 @@ nfsd_svc(unsigned short port, int nrservs)
if (nrservs == 0 && nfsd_serv == NULL)
goto out;

- error = nfsd_create_serv();
+ error = nfsd_create_serv(net);
if (error)
goto out;

--
1.8.2.2



2014-04-30 02:56:56

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 9/9] nfsd: check passed socket's net matches NFSd superblock's one

From: Stanislav Kinsbursky <[email protected]>

commit 3064639423c48d6e0eb9ecc27c512a58e38c6c57 upstream.

There could be a case, when NFSd file system is mounted in network, different
to socket's one, like below:

"ip netns exec" creates new network and mount namespace, which duplicates NFSd
mount point, created in init_net context. And thus NFS server stop in nested
network context leads to RPCBIND client destruction in init_net.
Then, on NFSd start in nested network context, rpc.nfsd process creates socket
in nested net and passes it into "write_ports", which leads to RPCBIND sockets
creation in init_net context because of the same reason (NFSd monut point was
created in init_net context). An attempt to register passed socket in nested
net leads to panic, because no RPCBIND client present in nexted network
namespace.

This patch add check that passed socket's net matches NFSd superblock's one.
And returns -EINVAL error to user psace otherwise.

v2: Put socket on exit.

Reported-by: Weng Meiling <[email protected]>
Signed-off-by: Stanislav Kinsbursky <[email protected]>
Cc: [email protected]
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4: adjust context]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfsctl.c | 5 +++++
include/linux/sunrpc/svcsock.h | 1 +
net/sunrpc/svcsock.c | 16 ++++++++++++++++
3 files changed, 22 insertions(+)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index cebc9ef..4db777d 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -660,6 +660,11 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net)
if (err != 0 || fd < 0)
return -EINVAL;

+ if (svc_alien_sock(net, fd)) {
+ printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
+ return -EINVAL;
+ }
+
err = nfsd_create_serv(net);
if (err != 0)
return err;
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index cb4ac69..e4c6cec 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -42,6 +42,7 @@ void svc_sock_update_bufs(struct svc_serv *serv);
int svc_sock_names(struct svc_serv *serv, char *buf,
const size_t buflen,
const char *toclose);
+bool svc_alien_sock(struct net *net, int fd);
int svc_addsock(struct svc_serv *serv, const int fd,
char *name_return, const size_t len);
void svc_init_xprt_sock(void);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index f190ea9..4c23cfc 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1441,6 +1441,22 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
return svsk;
}

+bool svc_alien_sock(struct net *net, int fd)
+{
+ int err;
+ struct socket *sock = sockfd_lookup(fd, &err);
+ bool ret = false;
+
+ if (!sock)
+ goto out;
+ if (sock_net(sock->sk) != net)
+ ret = true;
+ sockfd_put(sock);
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(svc_alien_sock);
+
/**
* svc_addsock - add a listener socket to an RPC service
* @serv: pointer to RPC service to which to add a new listener
--
1.8.2.2



2014-04-30 02:47:16

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 2/9] nfsd: pass net to nfsd_startup() and nfsd_shutdown()

From: Stanislav Kinsbursky <[email protected]>

commit db42d1a76a8dfcaba7a2dc9c591fa4e231db22b3 upstream.

Precursor patch. Hard-coded "init_net" will be replaced by proper one in
future.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4:
- adjust context
- one more parameter(int port) for nfsd_startup()
- no net ns initialization in nfsd_shutdown()
- pass @net to lockd_up() in nfsd_startup()
- pass @net to lockd_down() in nfsd_shutdown()]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfssvc.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 517a883..f8dae75 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -203,10 +203,9 @@ static int nfsd_init_socks(int port, struct net *net)

static bool nfsd_up = false;

-static int nfsd_startup(unsigned short port, int nrservs)
+static int nfsd_startup(unsigned short port, int nrservs, struct net *net)
{
int ret;
- struct net *net = &init_net;

if (nfsd_up)
return 0;
@@ -221,7 +220,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
ret = nfsd_init_socks(port, net);
if (ret)
goto out_racache;
- ret = lockd_up(&init_net);
+ ret = lockd_up(net);
if (ret)
goto out_racache;
ret = nfs4_state_start();
@@ -230,13 +229,13 @@ static int nfsd_startup(unsigned short port, int nrservs)
nfsd_up = true;
return 0;
out_lockd:
- lockd_down(&init_net);
+ lockd_down(net);
out_racache:
nfsd_racache_shutdown();
return ret;
}

-static void nfsd_shutdown(void)
+static void nfsd_shutdown(struct net *net)
{
/*
* write_ports can create the server without actually starting
@@ -247,14 +246,14 @@ static void nfsd_shutdown(void)
if (!nfsd_up)
return;
nfs4_state_shutdown();
- lockd_down(&init_net);
+ lockd_down(net);
nfsd_racache_shutdown();
nfsd_up = false;
}

static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
{
- nfsd_shutdown();
+ nfsd_shutdown(net);

svc_rpcb_cleanup(serv, net);

@@ -458,7 +457,7 @@ nfsd_svc(unsigned short port, int nrservs)

nfsd_up_before = nfsd_up;

- error = nfsd_startup(port, nrservs);
+ error = nfsd_startup(port, nrservs, net);
if (error)
goto out_destroy;
error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
@@ -471,7 +470,7 @@ nfsd_svc(unsigned short port, int nrservs)
error = nfsd_serv->sv_nrthreads - 1;
out_shutdown:
if (error < 0 && !nfsd_up_before)
- nfsd_shutdown();
+ nfsd_shutdown(net);
out_destroy:
nfsd_destroy(net); /* Release server */
out:
--
1.8.2.2



2014-04-30 02:46:48

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 1/9] nfsd: pass net to nfsd_init_socks()

From: Stanislav Kinsbursky <[email protected]>

commit db6e182c17cb1a7069f7f8924721ce58ac05d9a3 upstream.

Precursor patch. Hard-coded "init_net" will be replaced by proper one in
future.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4:
- adjust context
- one more parameter(int port) for nfsd_init_socks()
- net initialization in nfsd_startup()]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfssvc.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 25d839e..517a883 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -182,18 +182,18 @@ int nfsd_nrthreads(void)
return rv;
}

-static int nfsd_init_socks(int port)
+static int nfsd_init_socks(int port, struct net *net)
{
int error;
if (!list_empty(&nfsd_serv->sv_permsocks))
return 0;

- error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port,
+ error = svc_create_xprt(nfsd_serv, "udp", net, PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;

- error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port,
+ error = svc_create_xprt(nfsd_serv, "tcp", net, PF_INET, port,
SVC_SOCK_DEFAULTS);
if (error < 0)
return error;
@@ -206,6 +206,7 @@ static bool nfsd_up = false;
static int nfsd_startup(unsigned short port, int nrservs)
{
int ret;
+ struct net *net = &init_net;

if (nfsd_up)
return 0;
@@ -217,7 +218,7 @@ static int nfsd_startup(unsigned short port, int nrservs)
ret = nfsd_racache_init(2*nrservs);
if (ret)
return ret;
- ret = nfsd_init_socks(port);
+ ret = nfsd_init_socks(port, net);
if (ret)
goto out_racache;
ret = lockd_up(&init_net);
--
1.8.2.2



2014-04-30 02:46:53

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 8/9] nfsd: containerize NFSd filesystem

From: Stanislav Kinsbursky <[email protected]>

note: this backport is just for the null pointer problem when
start nfsd in none init netns. The nfsd is still not containerized.

commit 11f779421a39b86da8a523d97e5fd3477878d44f upstream.

This patch makes NFSD file system superblock to be created per net.
This makes possible to get proper network namespace from superblock instead of
using hard-coded "init_net".

Note: NFSd fs super-block holds network namespace. This garantees, that
network namespace won't disappear from underneath of it.
This, obviously, means, that in case of kill of a container's "init" (which is not a mount
namespace, but network namespace creator) netowrk namespace won't be
destroyed.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4:
- export cache not per netns
- NFSD service structure not per netns]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfsctl.c | 30 +++++++++++++++++++++++-------
fs/nfsd/nfssvc.c | 2 +-
2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 1d74af2..cebc9ef 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -213,6 +213,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
struct sockaddr *sap = (struct sockaddr *)&address;
size_t salen = sizeof(address);
char *fo_path;
+ struct net *net = file->f_dentry->d_sb->s_fs_info;

/* sanity check */
if (size == 0)
@@ -225,7 +226,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
if (qword_get(&buf, fo_path, size) < 0)
return -EINVAL;

- if (rpc_pton(&init_net, fo_path, size, sap, salen) == 0)
+ if (rpc_pton(net, fo_path, size, sap, salen) == 0)
return -EINVAL;

return nlmsvc_unlock_all_by_ip(sap);
@@ -389,7 +390,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
{
char *mesg = buf;
int rv;
- struct net *net = &init_net;
+ struct net *net = file->f_dentry->d_sb->s_fs_info;

if (size > 0) {
int newthreads;
@@ -440,7 +441,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
int len;
int npools;
int *nthreads;
- struct net *net = &init_net;
+ struct net *net = file->f_dentry->d_sb->s_fs_info;

mutex_lock(&nfsd_mutex);
npools = nfsd_nrpools();
@@ -857,7 +858,7 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size,
static ssize_t write_ports(struct file *file, char *buf, size_t size)
{
ssize_t rv;
- struct net *net = &init_net;
+ struct net *net = file->f_dentry->d_sb->s_fs_info;

mutex_lock(&nfsd_mutex);
rv = __write_ports(file, buf, size, net);
@@ -1095,20 +1096,35 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
#endif
/* last one */ {""}
};
- return simple_fill_super(sb, 0x6e667364, nfsd_files);
+ struct net *net = data;
+ int ret;
+
+ ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
+ if (ret)
+ return ret;
+ sb->s_fs_info = get_net(net);
+ return 0;
}

static struct dentry *nfsd_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
- return mount_single(fs_type, flags, data, nfsd_fill_super);
+ return mount_ns(fs_type, flags, current->nsproxy->net_ns, nfsd_fill_super);
+}
+
+static void nfsd_umount(struct super_block *sb)
+{
+ struct net *net = sb->s_fs_info;
+
+ kill_litter_super(sb);
+ put_net(net);
}

static struct file_system_type nfsd_fs_type = {
.owner = THIS_MODULE,
.name = "nfsd",
.mount = nfsd_mount,
- .kill_sb = kill_litter_super,
+ .kill_sb = nfsd_umount,
};

#ifdef CONFIG_PROC_FS
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 5bc9380..ed8eedf 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -670,7 +670,7 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file)
int nfsd_pool_stats_release(struct inode *inode, struct file *file)
{
int ret = seq_release(inode, file);
- struct net *net = &init_net;
+ struct net *net = inode->i_sb->s_fs_info;

mutex_lock(&nfsd_mutex);
/* this function really, really should have been called svc_put() */
--
1.8.2.2



2014-04-30 02:46:46

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 5/9] nfsd: pass net to nfsd_set_nrthreads()

From: Stanislav Kinsbursky <[email protected]>

commit 3938a0d5eb5effcc89c6909741403f4e6a37252d upstream.

Precursor patch. Hard-coded "init_net" will be replaced by proper one in
future.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4: adjust context]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfsctl.c | 3 ++-
fs/nfsd/nfsd.h | 2 +-
fs/nfsd/nfssvc.c | 3 +--
3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 9463bc0..f58e0f9 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -440,6 +440,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
int len;
int npools;
int *nthreads;
+ struct net *net = &init_net;

mutex_lock(&nfsd_mutex);
npools = nfsd_nrpools();
@@ -470,7 +471,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
if (nthreads[i] < 0)
goto out_free;
}
- rv = nfsd_set_nrthreads(i, nthreads);
+ rv = nfsd_set_nrthreads(i, nthreads, net);
if (rv)
goto out_free;
}
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 5007654..a0989a2 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -71,7 +71,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
int nfsd_nrthreads(void);
int nfsd_nrpools(void);
int nfsd_get_nrthreads(int n, int *);
-int nfsd_set_nrthreads(int n, int *);
+int nfsd_set_nrthreads(int n, int *, struct net *);

static inline void nfsd_destroy(struct net *net)
{
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index b8aea64..0974818 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -374,12 +374,11 @@ int nfsd_get_nrthreads(int n, int *nthreads)
return 0;
}

-int nfsd_set_nrthreads(int n, int *nthreads)
+int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
{
int i = 0;
int tot = 0;
int err = 0;
- struct net *net = &init_net;

WARN_ON(!mutex_is_locked(&nfsd_mutex));

--
1.8.2.2



2014-04-30 02:46:47

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 6/9] nfsd: pass net to __write_ports() and down

From: Stanislav Kinsbursky <[email protected]>

commit 081603520b25f7b35ef63a363376a17c36ef74ed upstream.

Precursor patch. Hard-coded "init_net" will be replaced by proper one in
future.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4:
- adjust context
- add net_ns parameter to __write_ports_delxprt()]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfsctl.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index f58e0f9..1d74af2 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -650,11 +650,10 @@ static ssize_t __write_ports_names(char *buf)
* a socket of a supported family/protocol, and we use it as an
* nfsd listener.
*/
-static ssize_t __write_ports_addfd(char *buf)
+static ssize_t __write_ports_addfd(char *buf, struct net *net)
{
char *mesg = buf;
int fd, err;
- struct net *net = &init_net;

err = get_int(&mesg, &fd);
if (err != 0 || fd < 0)
@@ -698,12 +697,11 @@ static ssize_t __write_ports_delfd(char *buf)
* A transport listener is added by writing it's transport name and
* a port number.
*/
-static ssize_t __write_ports_addxprt(char *buf)
+static ssize_t __write_ports_addxprt(char *buf, struct net *net)
{
char transport[16];
struct svc_xprt *xprt;
int port, err;
- struct net *net = &init_net;

if (sscanf(buf, "%15s %4u", transport, &port) != 2)
return -EINVAL;
@@ -743,7 +741,7 @@ out_err:
* A transport listener is removed by writing a "-", it's transport
* name, and it's port number.
*/
-static ssize_t __write_ports_delxprt(char *buf)
+static ssize_t __write_ports_delxprt(char *buf, struct net *net)
{
struct svc_xprt *xprt;
char transport[16];
@@ -755,7 +753,7 @@ static ssize_t __write_ports_delxprt(char *buf)
if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL)
return -EINVAL;

- xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port);
+ xprt = svc_find_xprt(nfsd_serv, transport, net, AF_UNSPEC, port);
if (xprt == NULL)
return -ENOTCONN;

@@ -764,22 +762,23 @@ static ssize_t __write_ports_delxprt(char *buf)
return 0;
}

-static ssize_t __write_ports(struct file *file, char *buf, size_t size)
+static ssize_t __write_ports(struct file *file, char *buf, size_t size,
+ struct net *net)
{
if (size == 0)
return __write_ports_names(buf);

if (isdigit(buf[0]))
- return __write_ports_addfd(buf);
+ return __write_ports_addfd(buf, net);

if (buf[0] == '-' && isdigit(buf[1]))
return __write_ports_delfd(buf);

if (isalpha(buf[0]))
- return __write_ports_addxprt(buf);
+ return __write_ports_addxprt(buf, net);

if (buf[0] == '-' && isalpha(buf[1]))
- return __write_ports_delxprt(buf);
+ return __write_ports_delxprt(buf, net);

return -EINVAL;
}
@@ -858,9 +857,10 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
static ssize_t write_ports(struct file *file, char *buf, size_t size)
{
ssize_t rv;
+ struct net *net = &init_net;

mutex_lock(&nfsd_mutex);
- rv = __write_ports(file, buf, size);
+ rv = __write_ports(file, buf, size, net);
mutex_unlock(&nfsd_mutex);
return rv;
}
--
1.8.2.2



2014-04-30 02:47:16

by Weng Meiling

[permalink] [raw]
Subject: [PATCH v2 3.4 4/9] nfsd: pass net to nfsd_svc()

From: Stanislav Kinsbursky <[email protected]>

commit d41a9417cd89a69f58a26935034b4264a2d882d6 upstream.

Precursor patch. Hard-coded "init_net" will be replaced by proper one in
future.

Signed-off-by: Stanislav Kinsbursky <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
[wengmeiling: backport to 3.4:
- adjust context
- one more parameter(int port) for nfsd_svc()]
Signed-off-by: Weng Meiling <[email protected]>
---
fs/nfsd/nfsctl.c | 4 +++-
fs/nfsd/nfsd.h | 2 +-
fs/nfsd/nfssvc.c | 3 +--
3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index e18f0a5..9463bc0 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -389,6 +389,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
{
char *mesg = buf;
int rv;
+ struct net *net = &init_net;
+
if (size > 0) {
int newthreads;
rv = get_int(&mesg, &newthreads);
@@ -396,7 +398,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
return rv;
if (newthreads < 0)
return -EINVAL;
- rv = nfsd_svc(NFS_PORT, newthreads);
+ rv = nfsd_svc(NFS_PORT, newthreads, net);
if (rv < 0)
return rv;
} else
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h
index 356da43..5007654 100644
--- a/fs/nfsd/nfsd.h
+++ b/fs/nfsd/nfsd.h
@@ -65,7 +65,7 @@ extern const struct seq_operations nfs_exports_op;
/*
* Function prototypes.
*/
-int nfsd_svc(unsigned short port, int nrservs);
+int nfsd_svc(unsigned short port, int nrservs, struct net *net);
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);

int nfsd_nrthreads(void);
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 632d11e..b8aea64 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -434,11 +434,10 @@ int nfsd_set_nrthreads(int n, int *nthreads)
* this is the first time nrservs is nonzero.
*/
int
-nfsd_svc(unsigned short port, int nrservs)
+nfsd_svc(unsigned short port, int nrservs, struct net *net)
{
int error;
bool nfsd_up_before;
- struct net *net = &init_net;

mutex_lock(&nfsd_mutex);
dprintk("nfsd: creating service\n");
--
1.8.2.2



2014-05-04 12:31:03

by J. Bruce Fields

[permalink] [raw]
Subject: Re: [PATCH v2 3.4 0/9] fix the NULL pointer when use nfs in diferent net ns

ACK to these for stable.--b.

On Wed, Apr 30, 2014 at 10:43:35AM +0800, Weng Meiling wrote:
> After 3.4 stable apply commit f7fb86c6e639(nfsd: use "init_net"
> for portmapper). When starting NFSd in a non init_net network
> namespace will trigger kernel panic. Because RPCBIND client
> will be NULL when register RPC service with the local portmapper
> in svc_addsock(). This new bug also exists in 3.8, but disappears
> after patch commit 11f779421a39("containerize NFSd filesystem") in
> 3.9.
>
> So backport Stanislav's patches from 3.8 and 3.9 to cleanup init_net
> reference, and get proper network namespace from superblock instead of
> using hard-coded "init_net" to make NFSd keep using a consistent network
> namespace all the time to resolve the bug.
>
> After this patchset, testing NFS in different network namespace will
> not trigger kernel panic any more, and other NFS client can use the
> NFS server's shared files normally which was started in init_net namespace.
>
> v1->v2:
> - no commit 7fb86c6e639(nfsd: use "init_net" for portmapper) which has been
> apply to 3.4 stable in the first version
> - one more fix patch commit 3064639423c4(nfsd: check passed socket's net matches
> NFSd superblock's one) for commit 11f779421a39("nfsd: containerize NFSd filesystem")
> - fix build error for commit db6e182c17cb(nfsd: pass net to nfsd_init_socks())
>
> Stanislav Kinsbursky (9):
> nfsd: pass net to nfsd_init_socks()
> nfsd: pass net to nfsd_startup() and nfsd_shutdown()
> nfsd: pass net to nfsd_create_serv()
> nfsd: pass net to nfsd_svc()
> nfsd: pass net to nfsd_set_nrthreads()
> nfsd: pass net to __write_ports() and down
> nfsd: pass proper net to nfsd_destroy() from NFSd kthreads
> nfsd: containerize NFSd filesystem
> nfsd: check passed socket's net matches NFSd superblock's one
>
> fs/nfsd/nfsctl.c | 62 +++++++++++++++++++++++++++++-------------
> fs/nfsd/nfsd.h | 6 ++--
> fs/nfsd/nfssvc.c | 41 ++++++++++++++--------------
> include/linux/sunrpc/svcsock.h | 1 +
> net/sunrpc/svcsock.c | 16 +++++++++++
> 5 files changed, 83 insertions(+), 43 deletions(-)
>
> --
> 1.8.2.2
>
>

2014-06-09 23:45:26

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH v2 3.4 0/9] fix the NULL pointer when use nfs in diferent net ns

On Sun, May 04, 2014 at 08:30:11AM -0400, J. Bruce Fields wrote:
> ACK to these for stable.--b.

All now queued up, thanks.

greg k-h