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: NeilBrown <neilb@suse.de>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
NeilBrown 2024-08-06 21:11:32 -04:00 committed by Chuck Lever
parent c9f10f811c
commit 73598a0cfb
5 changed files with 35 additions and 94 deletions

View File

@ -10,7 +10,7 @@
#define NFSCACHE_H #define NFSCACHE_H
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc.h>
#include "netns.h" #include "nfsd.h"
/* /*
* Representation of a reply cache entry. * Representation of a reply cache entry.

View File

@ -152,8 +152,8 @@ struct nfsd_net {
/* /*
* Version information * Version information
*/ */
bool *nfsd_versions; bool nfsd_versions[NFSD_MAXVERS + 1];
bool *nfsd4_minorversions; bool nfsd4_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1];
/* /*
* Duplicate reply cache * Duplicate reply cache
@ -219,8 +219,6 @@ struct nfsd_net {
#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
extern bool nfsd_support_version(int vers); extern bool nfsd_support_version(int vers);
extern void nfsd_netns_free_versions(struct nfsd_net *nn);
extern unsigned int nfsd_net_id; extern unsigned int nfsd_net_id;
void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn); void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn);

View File

@ -2231,8 +2231,9 @@ err_free_msg:
*/ */
static __net_init int nfsd_net_init(struct net *net) static __net_init int nfsd_net_init(struct net *net)
{ {
int retval;
struct nfsd_net *nn = net_generic(net, nfsd_net_id); struct nfsd_net *nn = net_generic(net, nfsd_net_id);
int retval;
int i;
retval = nfsd_export_init(net); retval = nfsd_export_init(net);
if (retval) if (retval)
@ -2246,8 +2247,10 @@ static __net_init int nfsd_net_init(struct net *net)
goto out_repcache_error; goto out_repcache_error;
memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats)); memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
nn->nfsd_svcstats.program = &nfsd_program; nn->nfsd_svcstats.program = &nfsd_program;
nn->nfsd_versions = NULL; for (i = 0; i < sizeof(nn->nfsd_versions); i++)
nn->nfsd4_minorversions = NULL; 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_info.mutex = &nfsd_mutex;
nn->nfsd_serv = NULL; nn->nfsd_serv = NULL;
nfsd4_init_leases_net(nn); 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); percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
nfsd_idmap_shutdown(net); nfsd_idmap_shutdown(net);
nfsd_export_shutdown(net); nfsd_export_shutdown(net);
nfsd_netns_free_versions(nn);
} }
static struct pernet_operations nfsd_net_ops = { static struct pernet_operations nfsd_net_ops = {

View File

@ -23,9 +23,7 @@
#include <uapi/linux/nfsd/debug.h> #include <uapi/linux/nfsd/debug.h>
#include "netns.h"
#include "export.h" #include "export.h"
#include "stats.h"
#undef ifdebug #undef ifdebug
#ifdef CONFIG_SUNRPC_DEBUG #ifdef CONFIG_SUNRPC_DEBUG
@ -37,7 +35,14 @@
/* /*
* nfsd version * nfsd version
*/ */
#define NFSD_MINVERS 2
#define NFSD_MAXVERS 4
#define NFSD_SUPPORTED_MINOR_VERSION 2 #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. * Maximum blocksizes supported by daemon under various circumstances.
*/ */

View File

@ -106,7 +106,7 @@ static struct svc_program nfsd_acl_program = {
#endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ #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) #if defined(CONFIG_NFSD_V2)
[2] = &nfsd_version2, [2] = &nfsd_version2,
#endif #endif
@ -116,15 +116,12 @@ static const struct svc_version *nfsd_version[] = {
#endif #endif
}; };
#define NFSD_MINVERS 2
#define NFSD_NRVERS ARRAY_SIZE(nfsd_version)
struct svc_program nfsd_program = { struct svc_program nfsd_program = {
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
.pg_next = &nfsd_acl_program, .pg_next = &nfsd_acl_program,
#endif #endif
.pg_prog = NFS_PROGRAM, /* program number */ .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_vers = nfsd_version, /* version table */
.pg_name = "nfsd", /* program name */ .pg_name = "nfsd", /* program name */
.pg_class = "nfsd", /* authentication class */ .pg_class = "nfsd", /* authentication class */
@ -135,78 +132,24 @@ struct svc_program nfsd_program = {
bool nfsd_support_version(int vers) 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 nfsd_version[vers] != NULL;
return false; 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) 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; return 0;
switch(change) { switch(change) {
case NFSD_SET: case NFSD_SET:
if (nn->nfsd_versions) nn->nfsd_versions[vers] = nfsd_support_version(vers);
nn->nfsd_versions[vers] = nfsd_support_version(vers);
break; break;
case NFSD_CLEAR: case NFSD_CLEAR:
nfsd_netns_init_versions(nn); nn->nfsd_versions[vers] = false;
if (nn->nfsd_versions)
nn->nfsd_versions[vers] = false;
break; break;
case NFSD_TEST: case NFSD_TEST:
if (nn->nfsd_versions) return nn->nfsd_versions[vers];
return nn->nfsd_versions[vers];
fallthrough;
case NFSD_AVAIL: case NFSD_AVAIL:
return nfsd_support_version(vers); return nfsd_support_version(vers);
} }
@ -233,23 +176,16 @@ int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change
switch(change) { switch(change) {
case NFSD_SET: case NFSD_SET:
if (nn->nfsd4_minorversions) { nfsd_vers(nn, 4, NFSD_SET);
nfsd_vers(nn, 4, NFSD_SET); nn->nfsd4_minorversions[minorversion] =
nn->nfsd4_minorversions[minorversion] = nfsd_vers(nn, 4, NFSD_TEST);
nfsd_vers(nn, 4, NFSD_TEST);
}
break; break;
case NFSD_CLEAR: case NFSD_CLEAR:
nfsd_netns_init_versions(nn); nn->nfsd4_minorversions[minorversion] = false;
if (nn->nfsd4_minorversions) { nfsd_adjust_nfsd_versions4(nn);
nn->nfsd4_minorversions[minorversion] = false;
nfsd_adjust_nfsd_versions4(nn);
}
break; break;
case NFSD_TEST: case NFSD_TEST:
if (nn->nfsd4_minorversions) return nn->nfsd4_minorversions[minorversion];
return nn->nfsd4_minorversions[minorversion];
return nfsd_vers(nn, 4, NFSD_TEST);
case NFSD_AVAIL: case NFSD_AVAIL:
return minorversion <= NFSD_SUPPORTED_MINOR_VERSION && return minorversion <= NFSD_SUPPORTED_MINOR_VERSION &&
nfsd_vers(nn, 4, NFSD_AVAIL); nfsd_vers(nn, 4, NFSD_AVAIL);
@ -568,11 +504,11 @@ void nfsd_reset_versions(struct nfsd_net *nn)
{ {
int i; int i;
for (i = 0; i < NFSD_NRVERS; i++) for (i = 0; i <= NFSD_MAXVERS; i++)
if (nfsd_vers(nn, i, NFSD_TEST)) if (nfsd_vers(nn, i, NFSD_TEST))
return; return;
for (i = 0; i < NFSD_NRVERS; i++) for (i = 0; i <= NFSD_MAXVERS; i++)
if (i != 4) if (i != 4)
nfsd_vers(nn, i, NFSD_SET); nfsd_vers(nn, i, NFSD_SET);
else { else {
@ -905,17 +841,17 @@ nfsd_init_request(struct svc_rqst *rqstp,
if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST))) if (likely(nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
return svc_generic_init_request(rqstp, progp, ret); return svc_generic_init_request(rqstp, progp, ret);
ret->mismatch.lovers = NFSD_NRVERS; ret->mismatch.lovers = NFSD_MAXVERS + 1;
for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) { for (i = NFSD_MINVERS; i <= NFSD_MAXVERS; i++) {
if (nfsd_vers(nn, i, NFSD_TEST)) { if (nfsd_vers(nn, i, NFSD_TEST)) {
ret->mismatch.lovers = i; ret->mismatch.lovers = i;
break; break;
} }
} }
if (ret->mismatch.lovers == NFSD_NRVERS) if (ret->mismatch.lovers > NFSD_MAXVERS)
return rpc_prog_unavail; return rpc_prog_unavail;
ret->mismatch.hivers = NFSD_MINVERS; 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)) { if (nfsd_vers(nn, i, NFSD_TEST)) {
ret->mismatch.hivers = i; ret->mismatch.hivers = i;
break; break;