Commit 73598a0c authored by NeilBrown's avatar NeilBrown Committed by Chuck Lever
Browse files

nfsd: don't allocate the versions array.



Instead of using kmalloc to allocate an array for storing active version
info, just declare an array to the max size - it is only 5 or so.

Signed-off-by: default avatarNeilBrown <neilb@suse.de>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent c9f10f81
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#define NFSCACHE_H

#include <linux/sunrpc/svc.h>
#include "netns.h"
#include "nfsd.h"

/*
 * Representation of a reply cache entry.
+2 −4
Original line number Diff line number Diff line
@@ -152,8 +152,8 @@ struct nfsd_net {
	/*
	 * Version information
	 */
	bool *nfsd_versions;
	bool *nfsd4_minorversions;
	bool nfsd_versions[NFSD_MAXVERS + 1];
	bool nfsd4_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1];

	/*
	 * Duplicate reply cache
@@ -219,8 +219,6 @@ struct nfsd_net {
#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)

extern bool nfsd_support_version(int vers);
extern void nfsd_netns_free_versions(struct nfsd_net *nn);

extern unsigned int nfsd_net_id;

void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn);
+6 −4
Original line number Diff line number Diff line
@@ -2231,8 +2231,9 @@ int nfsd_nl_pool_mode_get_doit(struct sk_buff *skb, struct genl_info *info)
 */
static __net_init int nfsd_net_init(struct net *net)
{
	int retval;
	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
	int retval;
	int i;

	retval = nfsd_export_init(net);
	if (retval)
@@ -2246,8 +2247,10 @@ static __net_init int nfsd_net_init(struct net *net)
		goto out_repcache_error;
	memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
	nn->nfsd_svcstats.program = &nfsd_program;
	nn->nfsd_versions = NULL;
	nn->nfsd4_minorversions = NULL;
	for (i = 0; i < sizeof(nn->nfsd_versions); i++)
		nn->nfsd_versions[i] = nfsd_support_version(i);
	for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++)
		nn->nfsd4_minorversions[i] = nfsd_support_version(4);
	nn->nfsd_info.mutex = &nfsd_mutex;
	nn->nfsd_serv = NULL;
	nfsd4_init_leases_net(nn);
@@ -2278,7 +2281,6 @@ static __net_exit void nfsd_net_exit(struct net *net)
	percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
	nfsd_idmap_shutdown(net);
	nfsd_export_shutdown(net);
	nfsd_netns_free_versions(nn);
}

static struct pernet_operations nfsd_net_ops = {
+7 −2
Original line number Diff line number Diff line
@@ -23,9 +23,7 @@

#include <uapi/linux/nfsd/debug.h>

#include "netns.h"
#include "export.h"
#include "stats.h"

#undef ifdebug
#ifdef CONFIG_SUNRPC_DEBUG
@@ -37,7 +35,14 @@
/*
 * nfsd version
 */
#define NFSD_MINVERS			2
#define	NFSD_MAXVERS			4
#define NFSD_SUPPORTED_MINOR_VERSION	2
bool nfsd_support_version(int vers);

#include "netns.h"
#include "stats.h"

/*
 * Maximum blocksizes supported by daemon under various circumstances.
 */
+19 −83
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ static struct svc_program nfsd_acl_program = {

#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */

static const struct svc_version *nfsd_version[] = {
static const struct svc_version *nfsd_version[NFSD_MAXVERS+1] = {
#if defined(CONFIG_NFSD_V2)
	[2] = &nfsd_version2,
#endif
@@ -116,15 +116,12 @@ static const struct svc_version *nfsd_version[] = {
#endif
};

#define NFSD_MINVERS    	2
#define NFSD_NRVERS		ARRAY_SIZE(nfsd_version)

struct svc_program		nfsd_program = {
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
	.pg_next		= &nfsd_acl_program,
#endif
	.pg_prog		= NFS_PROGRAM,		/* program number */
	.pg_nvers		= NFSD_NRVERS,		/* nr of entries in nfsd_version */
	.pg_nvers		= NFSD_MAXVERS+1,	/* nr of entries in nfsd_version */
	.pg_vers		= nfsd_version,		/* version table */
	.pg_name		= "nfsd",		/* program name */
	.pg_class		= "nfsd",		/* authentication class */
@@ -135,78 +132,24 @@ struct svc_program nfsd_program = {

bool nfsd_support_version(int vers)
{
	if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS)
	if (vers >= NFSD_MINVERS && vers <= NFSD_MAXVERS)
		return nfsd_version[vers] != NULL;
	return false;
}

static bool *
nfsd_alloc_versions(void)
{
	bool *vers = kmalloc_array(NFSD_NRVERS, sizeof(bool), GFP_KERNEL);
	unsigned i;

	if (vers) {
		/* All compiled versions are enabled by default */
		for (i = 0; i < NFSD_NRVERS; i++)
			vers[i] = nfsd_support_version(i);
	}
	return vers;
}

static bool *
nfsd_alloc_minorversions(void)
{
	bool *vers = kmalloc_array(NFSD_SUPPORTED_MINOR_VERSION + 1,
			sizeof(bool), GFP_KERNEL);
	unsigned i;

	if (vers) {
		/* All minor versions are enabled by default */
		for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++)
			vers[i] = nfsd_support_version(4);
	}
	return vers;
}

void
nfsd_netns_free_versions(struct nfsd_net *nn)
{
	kfree(nn->nfsd_versions);
	kfree(nn->nfsd4_minorversions);
	nn->nfsd_versions = NULL;
	nn->nfsd4_minorversions = NULL;
}

static void
nfsd_netns_init_versions(struct nfsd_net *nn)
{
	if (!nn->nfsd_versions) {
		nn->nfsd_versions = nfsd_alloc_versions();
		nn->nfsd4_minorversions = nfsd_alloc_minorversions();
		if (!nn->nfsd_versions || !nn->nfsd4_minorversions)
			nfsd_netns_free_versions(nn);
	}
}

int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change)
{
	if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
	if (vers < NFSD_MINVERS || vers > NFSD_MAXVERS)
		return 0;
	switch(change) {
	case NFSD_SET:
		if (nn->nfsd_versions)
		nn->nfsd_versions[vers] = nfsd_support_version(vers);
		break;
	case NFSD_CLEAR:
		nfsd_netns_init_versions(nn);
		if (nn->nfsd_versions)
		nn->nfsd_versions[vers] = false;
		break;
	case NFSD_TEST:
		if (nn->nfsd_versions)
		return nn->nfsd_versions[vers];
		fallthrough;
	case NFSD_AVAIL:
		return nfsd_support_version(vers);
	}
@@ -233,23 +176,16 @@ int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change

	switch(change) {
	case NFSD_SET:
		if (nn->nfsd4_minorversions) {
		nfsd_vers(nn, 4, NFSD_SET);
		nn->nfsd4_minorversions[minorversion] =
			nfsd_vers(nn, 4, NFSD_TEST);
		}
		break;
	case NFSD_CLEAR:
		nfsd_netns_init_versions(nn);
		if (nn->nfsd4_minorversions) {
		nn->nfsd4_minorversions[minorversion] = false;
		nfsd_adjust_nfsd_versions4(nn);
		}
		break;
	case NFSD_TEST:
		if (nn->nfsd4_minorversions)
		return nn->nfsd4_minorversions[minorversion];
		return nfsd_vers(nn, 4, NFSD_TEST);
	case NFSD_AVAIL:
		return minorversion <= NFSD_SUPPORTED_MINOR_VERSION &&
			nfsd_vers(nn, 4, NFSD_AVAIL);
@@ -568,11 +504,11 @@ void nfsd_reset_versions(struct nfsd_net *nn)
{
	int i;

	for (i = 0; i < NFSD_NRVERS; i++)
	for (i = 0; i <= NFSD_MAXVERS; i++)
		if (nfsd_vers(nn, i, NFSD_TEST))
			return;

	for (i = 0; i < NFSD_NRVERS; i++)
	for (i = 0; i <= NFSD_MAXVERS; i++)
		if (i != 4)
			nfsd_vers(nn, i, NFSD_SET);
		else {
@@ -905,17 +841,17 @@ nfsd_init_request(struct svc_rqst *rqstp,
	if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
		return svc_generic_init_request(rqstp, progp, ret);

	ret->mismatch.lovers = NFSD_NRVERS;
	for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
	ret->mismatch.lovers = NFSD_MAXVERS + 1;
	for (i = NFSD_MINVERS; i <= NFSD_MAXVERS; i++) {
		if (nfsd_vers(nn, i, NFSD_TEST)) {
			ret->mismatch.lovers = i;
			break;
		}
	}
	if (ret->mismatch.lovers == NFSD_NRVERS)
	if (ret->mismatch.lovers > NFSD_MAXVERS)
		return rpc_prog_unavail;
	ret->mismatch.hivers = NFSD_MINVERS;
	for (i = NFSD_NRVERS - 1; i >= NFSD_MINVERS; i--) {
	for (i = NFSD_MAXVERS; i >= NFSD_MINVERS; i--) {
		if (nfsd_vers(nn, i, NFSD_TEST)) {
			ret->mismatch.hivers = i;
			break;