[PATCH 4/4] nfsd: use guard(mutex) for all ->config_mutex locking.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Several function that lock ->config_mutex have multiple error paths.
Part of handling this is "goto unlock" statements, part is having
__write_foo() functions which are called by write_foo() after taking
the lock.

This can all be handled more neatly with
   guard(mutex)(&nn->config_mutex)
which ensures the mutex is dropped at the end of the scope.

this patch changes all locking on ->config_mutex to use guard() or
occasionally scoped_guard(), and folds the __write_foo() functions back
into write_foo().

Those function which are changed in this way have other clean changed
from goto to guard() or __free(), as mixing cleanup function with gotos
can sometimes be awkward.

This necessitates adding a guard for spin_lock_bh() and a __free function
for nlmsg.  This should probably go in the relevant header files at some
stage.

Signed-off-by: NeilBrown <neil@xxxxxxxxxx>
---
 fs/nfsd/nfsctl.c | 442 ++++++++++++++++++-----------------------------
 fs/nfsd/nfssvc.c |  17 +-
 2 files changed, 176 insertions(+), 283 deletions(-)

diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index eaed3df8b84b..06e39dbf9512 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -443,9 +443,8 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
 		if (newthreads < 0)
 			return -EINVAL;
 		trace_nfsd_ctl_threads(net, newthreads);
-		mutex_lock(&nn->config_mutex);
-		rv = nfsd_svc(1, &newthreads, net, file->f_cred, NULL);
-		mutex_unlock(&nn->config_mutex);
+		scoped_guard(mutex, &nn->config_mutex)
+			rv = nfsd_svc(1, &newthreads, net, file->f_cred, NULL);
 		if (rv < 0)
 			return rv;
 	} else
@@ -486,11 +485,12 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 	int rv;
 	int len;
 	int npools;
-	int *nthreads;
+	int *nthreads __free(kfree) = NULL;
 	struct net *net = netns(file);
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
+
 	npools = nfsd_nrpools(net);
 	if (npools == 0) {
 		/*
@@ -498,15 +498,13 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 		 * writing to the threads file but NOT the pool_threads
 		 * file, sorry.  Report zero threads.
 		 */
-		mutex_unlock(&nn->config_mutex);
 		strcpy(buf, "0\n");
 		return strlen(buf);
 	}
 
 	nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
-	rv = -ENOMEM;
 	if (nthreads == NULL)
-		goto out_free;
+		return -ENOMEM;
 
 	if (size > 0) {
 		for (i = 0; i < npools; i++) {
@@ -514,10 +512,9 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 			if (rv == -ENOENT)
 				break;		/* fewer numbers than pools */
 			if (rv)
-				goto out_free;	/* syntax error */
-			rv = -EINVAL;
+				return rv;	/* syntax error */
 			if (nthreads[i] < 0)
-				goto out_free;
+				return -EINVAL;
 			trace_nfsd_ctl_pool_threads(net, i, nthreads[i]);
 		}
 
@@ -530,12 +527,12 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 
 		rv = nfsd_set_nrthreads(i, nthreads, net);
 		if (rv)
-			goto out_free;
+			return rv;
 	}
 
 	rv = nfsd_get_nrthreads(npools, nthreads, net);
 	if (rv)
-		goto out_free;
+		return rv;
 
 	mesg = buf;
 	size = SIMPLE_TRANSACTION_LIMIT;
@@ -545,11 +542,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 		size -= len;
 		mesg += len;
 	}
-	rv = mesg - buf;
-out_free:
-	kfree(nthreads);
-	mutex_lock(&nn->config_mutex);
-	return rv;
+	return mesg - buf;
 }
 
 static ssize_t
@@ -573,7 +566,39 @@ nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining,
 			supported ? '+' : '-', vers, minor);
 }
 
-static ssize_t __write_versions(struct file *file, char *buf, size_t size)
+/*
+ * write_versions - Set or report the available NFS protocol versions
+ *
+ * Input:
+ *			buf:		ignored
+ *			size:		zero
+ * Output:
+ *	On success:	passed-in buffer filled with '\n'-terminated C
+ *			string containing positive or negative integer
+ *			values representing the current status of each
+ *			protocol version;
+ *			return code is the size in bytes of the string
+ *	On error:	return code is zero or a negative errno value
+ *
+ * OR
+ *
+ * Input:
+ *			buf:		C string containing whitespace-
+ *					separated positive or negative
+ *					integer values representing NFS
+ *					protocol versions to enable ("+n")
+ *					or disable ("-n")
+ *			size:		non-zero length of C string in @buf
+ * Output:
+ *	On success:	status of zero or more protocol versions has
+ *			been updated; passed-in buffer filled with
+ *			'\n'-terminated C string containing positive
+ *			or negative integer values representing the
+ *			current status of each protocol version;
+ *			return code is the size in bytes of the string
+ *	On error:	return code is zero or a negative errno value
+ */
+static ssize_t write_versions(struct file *file, char *buf, size_t size)
 {
 	char *mesg = buf;
 	char *vers, *minorp, sign;
@@ -582,6 +607,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 	char *sep;
 	struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
 
+	guard(mutex)(&nn->config_mutex);
 	if (size > 0) {
 		if (nn->nfsd_serv)
 			/* Cannot change versions without updating
@@ -677,49 +703,6 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 	return tlen + len;
 }
 
-/*
- * write_versions - Set or report the available NFS protocol versions
- *
- * Input:
- *			buf:		ignored
- *			size:		zero
- * Output:
- *	On success:	passed-in buffer filled with '\n'-terminated C
- *			string containing positive or negative integer
- *			values representing the current status of each
- *			protocol version;
- *			return code is the size in bytes of the string
- *	On error:	return code is zero or a negative errno value
- *
- * OR
- *
- * Input:
- *			buf:		C string containing whitespace-
- *					separated positive or negative
- *					integer values representing NFS
- *					protocol versions to enable ("+n")
- *					or disable ("-n")
- *			size:		non-zero length of C string in @buf
- * Output:
- *	On success:	status of zero or more protocol versions has
- *			been updated; passed-in buffer filled with
- *			'\n'-terminated C string containing positive
- *			or negative integer values representing the
- *			current status of each protocol version;
- *			return code is the size in bytes of the string
- *	On error:	return code is zero or a negative errno value
- */
-static ssize_t write_versions(struct file *file, char *buf, size_t size)
-{
-	struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
-	ssize_t rv;
-
-	mutex_lock(&nn->config_mutex);
-	rv = __write_versions(file, buf, size);
-	mutex_unlock(&nn->config_mutex);
-	return rv;
-}
-
 /*
  * Zero-length write.  Return a list of NFSD's current listener
  * transports.
@@ -811,21 +794,6 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr
 	return err;
 }
 
-static ssize_t __write_ports(struct file *file, char *buf, size_t size,
-			     struct net *net)
-{
-	if (size == 0)
-		return __write_ports_names(buf, net);
-
-	if (isdigit(buf[0]))
-		return __write_ports_addfd(buf, net, file->f_cred);
-
-	if (isalpha(buf[0]))
-		return __write_ports_addxprt(buf, net, file->f_cred);
-
-	return -EINVAL;
-}
-
 /*
  * write_ports - Pass a socket file descriptor or transport name to listen on
  *
@@ -871,13 +839,21 @@ 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 nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
-	ssize_t rv;
+	struct net *net = netns(file);
+	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-	mutex_lock(&nn->config_mutex);
-	rv = __write_ports(file, buf, size, netns(file));
-	mutex_unlock(&nn->config_mutex);
-	return rv;
+	guard(mutex)(&nn->config_mutex);
+
+	if (size == 0)
+		return __write_ports_names(buf, net);
+
+	if (isdigit(buf[0]))
+		return __write_ports_addfd(buf, net, file->f_cred);
+
+	if (isalpha(buf[0]))
+		return __write_ports_addxprt(buf, net, file->f_cred);
+
+	return -EINVAL;
 }
 
 int nfsd_max_blksize;
@@ -921,13 +897,11 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
 		bsize = max_t(int, bsize, 1024);
 		bsize = min_t(int, bsize, NFSSVC_MAXBLKSIZE);
 		bsize &= ~(1024-1);
-		mutex_lock(&nn->config_mutex);
-		if (nn->nfsd_serv) {
-			mutex_unlock(&nn->config_mutex);
+
+		guard(mutex)(&nn->config_mutex);
+		if (nn->nfsd_serv)
 			return -EBUSY;
-		}
 		nfsd_max_blksize = bsize;
-		mutex_unlock(&nn->config_mutex);
 	}
 
 	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%d\n",
@@ -974,12 +948,8 @@ static ssize_t __nfsd4_write_time(struct file *file, char *buf, size_t size,
 static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
 				time64_t *time, struct nfsd_net *nn)
 {
-	ssize_t rv;
-
-	mutex_lock(&nn->config_mutex);
-	rv = __nfsd4_write_time(file, buf, size, time, nn);
-	mutex_unlock(&nn->config_mutex);
-	return rv;
+	guard(mutex)(&nn->config_mutex);
+	return __nfsd4_write_time(file, buf, size, time, nn);
 }
 
 /*
@@ -1026,35 +996,6 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
 }
 
 #ifdef CONFIG_NFSD_LEGACY_CLIENT_TRACKING
-static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
-				   struct nfsd_net *nn)
-{
-	char *mesg = buf;
-	char *recdir;
-	int len, status;
-
-	if (size > 0) {
-		if (nn->nfsd_serv)
-			return -EBUSY;
-		if (size > PATH_MAX || buf[size-1] != '\n')
-			return -EINVAL;
-		buf[size-1] = 0;
-
-		recdir = mesg;
-		len = qword_get(&mesg, recdir, size);
-		if (len <= 0)
-			return -EINVAL;
-		trace_nfsd_ctl_recoverydir(netns(file), recdir);
-
-		status = nfs4_reset_recoverydir(recdir);
-		if (status)
-			return status;
-	}
-
-	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
-							nfs4_recoverydir());
-}
-
 /*
  * write_recoverydir - Set or report the pathname of the recovery directory
  *
@@ -1078,13 +1019,33 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
  */
 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
 {
-	ssize_t rv;
 	struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
+	char *mesg = buf;
+	char *recdir;
+	int len, status;
 
-	mutex_lock(&nn->config_mutex);
-	rv = __write_recoverydir(file, buf, size, nn);
-	mutex_unlock(&nn->config_mutex);
-	return rv;
+	guard(mutex)(&nn->config_mutex);
+
+	if (size > 0) {
+		if (nn->nfsd_serv)
+			return -EBUSY;
+		if (size > PATH_MAX || buf[size-1] != '\n')
+			return -EINVAL;
+		buf[size-1] = 0;
+
+		recdir = mesg;
+		len = qword_get(&mesg, recdir, size);
+		if (len <= 0)
+			return -EINVAL;
+		trace_nfsd_ctl_recoverydir(netns(file), recdir);
+
+		status = nfs4_reset_recoverydir(recdir);
+		if (status)
+			return status;
+	}
+
+	return scnprintf(buf, SIMPLE_TRANSACTION_LIMIT, "%s\n",
+							nfs4_recoverydir());
 }
 #endif
 
@@ -1552,13 +1513,11 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
 	int i, ret, rqstp_index = 0;
 	struct nfsd_net *nn = net_generic(sock_net(skb->sk), nfsd_net_id);
 
-	mutex_lock(&nn->config_mutex);
-	if (!nn->nfsd_serv) {
-		ret = -ENODEV;
-		goto out_unlock;
-	}
+	guard(mutex)(&nn->config_mutex);
+	if (!nn->nfsd_serv)
+		return -ENODEV;
 
-	rcu_read_lock();
+	guard(rcu)();
 
 	for (i = 0; i < nn->nfsd_serv->sv_nrpools; i++) {
 		struct svc_rqst *rqstp;
@@ -1624,17 +1583,13 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
 			ret = nfsd_genl_rpc_status_compose_msg(skb, cb,
 							       &genl_rqstp);
 			if (ret)
-				goto out;
+				return ret;
 		}
 	}
 
 	cb->args[0] = i;
 	cb->args[1] = rqstp_index;
 	ret = skb->len;
-out:
-	rcu_read_unlock();
-out_unlock:
-	mutex_unlock(&nn->config_mutex);
 
 	return ret;
 }
@@ -1648,7 +1603,8 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
  */
 int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
 {
-	int *nthreads, count = 0, nrpools, i, ret = -EOPNOTSUPP, rem;
+	int count = 0, nrpools, i, ret = -EOPNOTSUPP, rem;
+	int *nthreads __free(kfree) = NULL;
 	struct net *net = genl_info_net(info);
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 	const struct nlattr *attr;
@@ -1663,14 +1619,12 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
 			count++;
 	}
 
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
 
 	nrpools = max(count, nfsd_nrpools(net));
 	nthreads = kcalloc(nrpools, sizeof(int), GFP_KERNEL);
-	if (!nthreads) {
-		ret = -ENOMEM;
-		goto out_unlock;
-	}
+	if (!nthreads)
+		return -ENOMEM;
 
 	i = 0;
 	nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
@@ -1684,17 +1638,15 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
 	if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
 	    info->attrs[NFSD_A_SERVER_LEASETIME] ||
 	    info->attrs[NFSD_A_SERVER_SCOPE]) {
-		ret = -EBUSY;
 		if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads)
-			goto out_unlock;
+			return -EBUSY;
 
-		ret = -EINVAL;
 		attr = info->attrs[NFSD_A_SERVER_GRACETIME];
 		if (attr) {
 			u32 gracetime = nla_get_u32(attr);
 
 			if (gracetime < 10 || gracetime > 3600)
-				goto out_unlock;
+				return -EINVAL;
 
 			nn->nfsd4_grace = gracetime;
 		}
@@ -1704,7 +1656,7 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
 			u32 leasetime = nla_get_u32(attr);
 
 			if (leasetime < 10 || leasetime > 3600)
-				goto out_unlock;
+				return -EINVAL;
 
 			nn->nfsd4_lease = leasetime;
 		}
@@ -1717,12 +1669,10 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
 	ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
 	if (ret > 0)
 		ret = 0;
-out_unlock:
-	mutex_unlock(&nn->config_mutex);
-	kfree(nthreads);
 	return ret;
 }
 
+DEFINE_FREE(nlmsg_free, struct sk_buff *, if (_T) nlmsg_free(_T))
 /**
  * nfsd_nl_threads_get_doit - get the number of running threads
  * @skb: reply buffer
@@ -1734,29 +1684,28 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
 {
 	struct net *net = genl_info_net(info);
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+	struct sk_buff *reply __free(nlmsg_free) =
+		genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
 	void *hdr;
 	int err;
 
-	skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
+	if (!reply)
 		return -ENOMEM;
 
-	hdr = genlmsg_iput(skb, info);
-	if (!hdr) {
-		err = -EMSGSIZE;
-		goto err_free_msg;
-	}
+	hdr = genlmsg_iput(reply, info);
+	if (!hdr)
+		return -EMSGSIZE;
 
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
 
-	err = nla_put_u32(skb, NFSD_A_SERVER_GRACETIME,
+	err = nla_put_u32(reply, NFSD_A_SERVER_GRACETIME,
 			  nn->nfsd4_grace) ||
-	      nla_put_u32(skb, NFSD_A_SERVER_LEASETIME,
+	      nla_put_u32(reply, NFSD_A_SERVER_LEASETIME,
 			  nn->nfsd4_lease) ||
-	      nla_put_string(skb, NFSD_A_SERVER_SCOPE,
+	      nla_put_string(reply, NFSD_A_SERVER_SCOPE,
 			  nn->nfsd_name);
 	if (err)
-		goto err_unlock;
+		return err;
 
 	if (nn->nfsd_serv) {
 		int i;
@@ -1764,29 +1713,20 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
 		for (i = 0; i < nfsd_nrpools(net); ++i) {
 			struct svc_pool *sp = &nn->nfsd_serv->sv_pools[i];
 
-			err = nla_put_u32(skb, NFSD_A_SERVER_THREADS,
+			err = nla_put_u32(reply, NFSD_A_SERVER_THREADS,
 					  sp->sp_nrthreads);
 			if (err)
-				goto err_unlock;
+				return err;
 		}
 	} else {
-		err = nla_put_u32(skb, NFSD_A_SERVER_THREADS, 0);
+		err = nla_put_u32(reply, NFSD_A_SERVER_THREADS, 0);
 		if (err)
-			goto err_unlock;
+			return err;
 	}
 
-	mutex_unlock(&nn->config_mutex);
-
-	genlmsg_end(skb, hdr);
+	genlmsg_end(reply, hdr);
 
-	return genlmsg_reply(skb, info);
-
-err_unlock:
-	mutex_unlock(&nn->config_mutex);
-err_free_msg:
-	nlmsg_free(skb);
-
-	return err;
+	return genlmsg_reply(no_free_ptr(reply), info);
 }
 
 /**
@@ -1806,11 +1746,9 @@ int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info)
 		return -EINVAL;
 
 	nn = net_generic(genl_info_net(info), nfsd_net_id);
-	mutex_lock(&nn->config_mutex);
-	if (nn->nfsd_serv) {
-		mutex_unlock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
+	if (nn->nfsd_serv)
 		return -EBUSY;
-	}
 
 	/* clear current supported versions. */
 	nfsd_vers(nn, 2, NFSD_CLEAR);
@@ -1853,8 +1791,6 @@ int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info)
 		}
 	}
 
-	mutex_unlock(&nn->config_mutex);
-
 	return 0;
 }
 
@@ -1868,21 +1804,20 @@ int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info)
 int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info)
 {
 	struct nfsd_net *nn;
-	int i, err;
+	struct sk_buff *reply __free(nlmsg_free) =
+		genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	int i;
 	void *hdr;
 
-	skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
+	if (!reply)
 		return -ENOMEM;
 
-	hdr = genlmsg_iput(skb, info);
-	if (!hdr) {
-		err = -EMSGSIZE;
-		goto err_free_msg;
-	}
+	hdr = genlmsg_iput(reply, info);
+	if (!hdr)
+		return -EMSGSIZE;
 
 	nn = net_generic(genl_info_net(info), nfsd_net_id);
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
 
 	for (i = 2; i <= 4; i++) {
 		int j;
@@ -1900,42 +1835,28 @@ int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info)
 			if (i < 4 && j)
 				continue;
 
-			attr = nla_nest_start(skb,
+			attr = nla_nest_start(reply,
 					      NFSD_A_SERVER_PROTO_VERSION);
-			if (!attr) {
-				err = -EINVAL;
-				goto err_nfsd_unlock;
-			}
+			if (!attr)
+				return -EINVAL;
 
-			if (nla_put_u32(skb, NFSD_A_VERSION_MAJOR, i) ||
-			    nla_put_u32(skb, NFSD_A_VERSION_MINOR, j)) {
-				err = -EINVAL;
-				goto err_nfsd_unlock;
-			}
+			if (nla_put_u32(reply, NFSD_A_VERSION_MAJOR, i) ||
+			    nla_put_u32(reply, NFSD_A_VERSION_MINOR, j))
+				return -EINVAL;
 
 			/* Set the enabled flag if the version is enabled */
 			if (nfsd_vers(nn, i, NFSD_TEST) &&
 			    (i < 4 || nfsd_minorversion(nn, j, NFSD_TEST)) &&
-			    nla_put_flag(skb, NFSD_A_VERSION_ENABLED)) {
-				err = -EINVAL;
-				goto err_nfsd_unlock;
-			}
+			    nla_put_flag(reply, NFSD_A_VERSION_ENABLED))
+				return -EINVAL;
 
-			nla_nest_end(skb, attr);
+			nla_nest_end(reply, attr);
 		}
 	}
 
-	mutex_unlock(&nn->config_mutex);
-	genlmsg_end(skb, hdr);
-
-	return genlmsg_reply(skb, info);
-
-err_nfsd_unlock:
-	mutex_unlock(&nn->config_mutex);
-err_free_msg:
-	nlmsg_free(skb);
+	genlmsg_end(reply, hdr);
 
-	return err;
+	return genlmsg_reply(no_free_ptr(reply), info);
 }
 
 /**
@@ -1957,13 +1878,11 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
 	int err, rem;
 
 	nn = net_generic(net, nfsd_net_id);
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
 
 	err = nfsd_create_serv(net);
-	if (err) {
-		mutex_unlock(&nn->config_mutex);
+	if (err)
 		return err;
-	}
 
 	serv = nn->nfsd_serv;
 
@@ -2025,10 +1944,8 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
 	spin_unlock_bh(&serv->sv_lock);
 
 	/* Do not remove listeners while there are active threads. */
-	if (serv->sv_nrthreads) {
-		err = -EBUSY;
-		goto out_unlock_mtx;
-	}
+	if (serv->sv_nrthreads)
+		return -EBUSY;
 
 	/*
 	 * Since we can't delete an arbitrary llist entry, destroy the
@@ -2079,12 +1996,10 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
 	if (!serv->sv_nrthreads && list_empty(&nn->nfsd_serv->sv_permsocks))
 		nfsd_destroy_serv(net);
 
-out_unlock_mtx:
-	mutex_unlock(&nn->config_mutex);
-
 	return err;
 }
 
+DEFINE_GUARD(spin_lock_bh, spinlock_t *, spin_lock_bh(_T), spin_unlock_bh(_T))
 /**
  * nfsd_nl_listener_get_doit - get the nfs running listeners
  * @skb: reply buffer
@@ -2098,61 +2013,44 @@ int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info)
 	struct svc_serv *serv;
 	struct nfsd_net *nn;
 	void *hdr;
-	int err;
 
-	skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
-	if (!skb)
+	struct sk_buff __free(nlmsg_free) *reply =
+			genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!reply)
 		return -ENOMEM;
 
-	hdr = genlmsg_iput(skb, info);
-	if (!hdr) {
-		err = -EMSGSIZE;
-		goto err_free_msg;
-	}
+	hdr = genlmsg_iput(reply, info);
+	if (!hdr)
+		return -EMSGSIZE;
 
 	nn = net_generic(genl_info_net(info), nfsd_net_id);
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
 
 	/* no nfs server? Just send empty socket list */
-	if (!nn->nfsd_serv)
-		goto out_unlock_mtx;
+	if (nn->nfsd_serv) {
+		serv = nn->nfsd_serv;
+		guard(spin_lock_bh)(&serv->sv_lock);
+		list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
+			struct nlattr *attr;
 
-	serv = nn->nfsd_serv;
-	spin_lock_bh(&serv->sv_lock);
-	list_for_each_entry(xprt, &serv->sv_permsocks, xpt_list) {
-		struct nlattr *attr;
+			attr = nla_nest_start(reply, NFSD_A_SERVER_SOCK_ADDR);
+			if (!attr)
+				return -EINVAL;
 
-		attr = nla_nest_start(skb, NFSD_A_SERVER_SOCK_ADDR);
-		if (!attr) {
-			err = -EINVAL;
-			goto err_serv_unlock;
-		}
+			if (nla_put_string(reply, NFSD_A_SOCK_TRANSPORT_NAME,
+					   xprt->xpt_class->xcl_name) ||
+			    nla_put(reply, NFSD_A_SOCK_ADDR,
+				    sizeof(struct sockaddr_storage),
+				    &xprt->xpt_local))
+				return -EINVAL;
 
-		if (nla_put_string(skb, NFSD_A_SOCK_TRANSPORT_NAME,
-				   xprt->xpt_class->xcl_name) ||
-		    nla_put(skb, NFSD_A_SOCK_ADDR,
-			    sizeof(struct sockaddr_storage),
-			    &xprt->xpt_local)) {
-			err = -EINVAL;
-			goto err_serv_unlock;
+			nla_nest_end(reply, attr);
 		}
-
-		nla_nest_end(skb, attr);
 	}
-	spin_unlock_bh(&serv->sv_lock);
-out_unlock_mtx:
-	mutex_unlock(&nn->config_mutex);
-	genlmsg_end(skb, hdr);
-
-	return genlmsg_reply(skb, info);
 
-err_serv_unlock:
-	spin_unlock_bh(&serv->sv_lock);
-	mutex_unlock(&nn->config_mutex);
-err_free_msg:
-	nlmsg_free(skb);
+	genlmsg_end(reply, hdr);
 
-	return err;
+	return genlmsg_reply(no_free_ptr(reply), info);
 }
 
 /**
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index c19e608802a6..b459d6283f16 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -225,14 +225,12 @@ static void nfsd_net_free(struct percpu_ref *ref)
 
 int nfsd_nrthreads(struct net *net)
 {
-	int rv = 0;
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
-	mutex_lock(&nn->config_mutex);
-	if (nn->nfsd_serv)
-		rv = nn->nfsd_serv->sv_nrthreads;
-	mutex_unlock(&nn->config_mutex);
-	return rv;
+	guard(mutex)(&nn->config_mutex);
+	if (!nn->nfsd_serv)
+		return 0;
+	return nn->nfsd_serv->sv_nrthreads;
 }
 
 static int nfsd_init_socks(struct net *net, const struct cred *cred)
@@ -578,17 +576,14 @@ void nfsd_shutdown_threads(struct net *net)
 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 	struct svc_serv *serv;
 
-	mutex_lock(&nn->config_mutex);
+	guard(mutex)(&nn->config_mutex);
 	serv = nn->nfsd_serv;
-	if (serv == NULL) {
-		mutex_unlock(&nn->config_mutex);
+	if (serv == NULL)
 		return;
-	}
 
 	/* Kill outstanding nfsd threads */
 	svc_set_num_threads(serv, NULL, 0);
 	nfsd_destroy_serv(net);
-	mutex_unlock(&nn->config_mutex);
 }
 
 struct svc_rqst *nfsd_current_rqst(void)
-- 
2.49.0





[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux