From 1cd9cd161c89f569b90583b7797bd972c3bf0cff Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Wed, 22 Oct 2008 13:12:36 -0400 Subject: NFSD: Fix BUG during NFSD shutdown processing The Linux NFS server can be started via a user-space write to /proc/fs/nfs/threads or to /proc/fs/nfs/portlist. In the first case, all default listeners are started (both UDP and TCP). In the second, a listener is started only for one specified transport. The NFS server has to make sure lockd stays up until the last listener transport goes away. To support both start-up interfaces, it should do one lockd_up() for each NFSD listener. The nfsd_init_socks() function used to do one lockd_up() call for each svc_create_xprt(). Recently commit 26a414092353590ceaa5955bcb53f863d6ea7549 mistakenly changed nfsd_init_socks() to do only one lockd_up() call even though it still does two svc_create_xprt() calls. The end result is a lockd_down() BUG during NFSD shutdown processing because nfsd_last_threads() does a lockd_down() call for each entry on the sv_permsocks list, but the start-up code doesn't do a matching number of lockd_up() calls. Add a second lockd_up() in nfsd_init_socks() to make sure the number of lockd_up() calls matches the number of entries on the NFS servers's sv_permsocks list. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfssvc.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 59eeb46f82c..07e4f5d7baa 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -249,6 +249,10 @@ static int nfsd_init_socks(int port) if (error < 0) return error; + error = lockd_up(); + if (error < 0) + return error; + error = svc_create_xprt(nfsd_serv, "tcp", port, SVC_SOCK_DEFAULTS); if (error < 0) -- cgit v1.2.3 From 6c6a426fdcb374b7641d7cf9eea88410828b9d9a Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Wed, 22 Oct 2008 14:48:36 +0530 Subject: nfsd: Fix memory leak in nfsd_getxattr Fix a memory leak in nfsd_getxattr. nfsd_getxattr should free up memory that it allocated if vfs_getxattr fails. Signed-off-by: Krishna Kumar Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index aa1d0d6489a..9609eb51d72 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -410,6 +410,7 @@ out_nfserr: static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) { ssize_t buflen; + ssize_t ret; buflen = vfs_getxattr(dentry, key, NULL, 0); if (buflen <= 0) @@ -419,7 +420,10 @@ static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf) if (!*buf) return -ENOMEM; - return vfs_getxattr(dentry, key, *buf, buflen); + ret = vfs_getxattr(dentry, key, *buf, buflen); + if (ret < 0) + kfree(*buf); + return ret; } #endif -- cgit v1.2.3 From 6dfcde98a299196f13dd66417663a819f0ac4156 Mon Sep 17 00:00:00 2001 From: Krishna Kumar Date: Mon, 20 Oct 2008 11:44:40 +0530 Subject: nfsd: Drop reference in expkey_parse error cases Drop reference to export key on error. Compile tested. Signed-off-by: Krishna Kumar Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 9dc036f1835..7ce2c6e4e23 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -151,8 +151,10 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) /* now we want a pathname, or empty meaning NEGATIVE */ err = -EINVAL; - if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) + if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) { + cache_put(&ek->h, &svc_expkey_cache); goto out; + } dprintk("Path seems to be <%s>\n", buf); err = 0; if (len == 0) { @@ -164,8 +166,10 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) } else { struct nameidata nd; err = path_lookup(buf, 0, &nd); - if (err) + if (err) { + cache_put(&ek->h, &svc_expkey_cache); goto out; + } dprintk("Found the path %s\n", buf); key.ek_path = nd.path; -- cgit v1.2.3 From 30bc4dfd3b64eb1fbefe2c63e30d8fc129273e20 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 20 Oct 2008 16:34:21 -0400 Subject: nfsd: clean up expkey_parse error cases We might as well do all of these at the end. Fix up a couple minor style nits while we're there. Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 7ce2c6e4e23..5cd882b8871 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -99,7 +99,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) int fsidtype; char *ep; struct svc_expkey key; - struct svc_expkey *ek; + struct svc_expkey *ek = NULL; if (mesg[mlen-1] != '\n') return -EINVAL; @@ -107,7 +107,8 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) buf = kmalloc(PAGE_SIZE, GFP_KERNEL); err = -ENOMEM; - if (!buf) goto out; + if (!buf) + goto out; err = -EINVAL; if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0) @@ -151,38 +152,34 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) /* now we want a pathname, or empty meaning NEGATIVE */ err = -EINVAL; - if ((len=qword_get(&mesg, buf, PAGE_SIZE)) < 0) { - cache_put(&ek->h, &svc_expkey_cache); + len = qword_get(&mesg, buf, PAGE_SIZE); + if (len < 0) goto out; - } dprintk("Path seems to be <%s>\n", buf); err = 0; if (len == 0) { set_bit(CACHE_NEGATIVE, &key.h.flags); ek = svc_expkey_update(&key, ek); - if (ek) - cache_put(&ek->h, &svc_expkey_cache); - else err = -ENOMEM; + if (!ek) + err = -ENOMEM; } else { struct nameidata nd; err = path_lookup(buf, 0, &nd); - if (err) { - cache_put(&ek->h, &svc_expkey_cache); + if (err) goto out; - } dprintk("Found the path %s\n", buf); key.ek_path = nd.path; ek = svc_expkey_update(&key, ek); - if (ek) - cache_put(&ek->h, &svc_expkey_cache); - else + if (!ek) err = -ENOMEM; path_put(&nd.path); } cache_flush(); out: + if (ek) + cache_put(&ek->h, &svc_expkey_cache); if (dom) auth_domain_put(dom); kfree(buf); -- cgit v1.2.3