mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	nfsd: Allow containers to set supported nfs versions
Support use of the --nfs-version/--no-nfs-version arguments to rpc.nfsd in containers. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
		
							parent
							
								
									029be5d033
								
							
						
					
					
						commit
						e333f3bbef
					
				
					 5 changed files with 197 additions and 61 deletions
				
			
		| 
						 | 
					@ -134,10 +134,18 @@ struct nfsd_net {
 | 
				
			||||||
	u32		s2s_cp_cl_id;
 | 
						u32		s2s_cp_cl_id;
 | 
				
			||||||
	struct idr	s2s_cp_stateids;
 | 
						struct idr	s2s_cp_stateids;
 | 
				
			||||||
	spinlock_t	s2s_cp_lock;
 | 
						spinlock_t	s2s_cp_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Version information
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bool *nfsd_versions;
 | 
				
			||||||
 | 
						bool *nfsd4_minorversions;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Simple check to find out if a given net was properly initialized */
 | 
					/* Simple check to find out if a given net was properly initialized */
 | 
				
			||||||
#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
 | 
					#define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void nfsd_netns_free_versions(struct nfsd_net *nn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern unsigned int nfsd_net_id;
 | 
					extern unsigned int nfsd_net_id;
 | 
				
			||||||
#endif /* __NFSD_NETNS_H__ */
 | 
					#endif /* __NFSD_NETNS_H__ */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1926,6 +1926,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
 | 
				
			||||||
	struct nfsd4_compound_state *cstate = &resp->cstate;
 | 
						struct nfsd4_compound_state *cstate = &resp->cstate;
 | 
				
			||||||
	struct svc_fh *current_fh = &cstate->current_fh;
 | 
						struct svc_fh *current_fh = &cstate->current_fh;
 | 
				
			||||||
	struct svc_fh *save_fh = &cstate->save_fh;
 | 
						struct svc_fh *save_fh = &cstate->save_fh;
 | 
				
			||||||
 | 
						struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 | 
				
			||||||
	__be32		status;
 | 
						__be32		status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	svcxdr_init_encode(rqstp, resp);
 | 
						svcxdr_init_encode(rqstp, resp);
 | 
				
			||||||
| 
						 | 
					@ -1948,7 +1949,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp)
 | 
				
			||||||
	 * According to RFC3010, this takes precedence over all other errors.
 | 
						 * According to RFC3010, this takes precedence over all other errors.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	status = nfserr_minor_vers_mismatch;
 | 
						status = nfserr_minor_vers_mismatch;
 | 
				
			||||||
	if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0)
 | 
						if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	status = nfserr_resource;
 | 
						status = nfserr_resource;
 | 
				
			||||||
	if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND)
 | 
						if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -537,14 +537,14 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t
 | 
					static ssize_t
 | 
				
			||||||
nfsd_print_version_support(char *buf, int remaining, const char *sep,
 | 
					nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining,
 | 
				
			||||||
		unsigned vers, int minor)
 | 
							const char *sep, unsigned vers, int minor)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u";
 | 
						const char *format = minor < 0 ? "%s%c%u" : "%s%c%u.%u";
 | 
				
			||||||
	bool supported = !!nfsd_vers(vers, NFSD_TEST);
 | 
						bool supported = !!nfsd_vers(nn, vers, NFSD_TEST);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (vers == 4 && minor >= 0 &&
 | 
						if (vers == 4 && minor >= 0 &&
 | 
				
			||||||
	    !nfsd_minorversion(minor, NFSD_TEST))
 | 
						    !nfsd_minorversion(nn, minor, NFSD_TEST))
 | 
				
			||||||
		supported = false;
 | 
							supported = false;
 | 
				
			||||||
	if (minor == 0 && supported)
 | 
						if (minor == 0 && supported)
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					@ -599,20 +599,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 | 
				
			||||||
			switch(num) {
 | 
								switch(num) {
 | 
				
			||||||
			case 2:
 | 
								case 2:
 | 
				
			||||||
			case 3:
 | 
								case 3:
 | 
				
			||||||
				nfsd_vers(num, cmd);
 | 
									nfsd_vers(nn, num, cmd);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			case 4:
 | 
								case 4:
 | 
				
			||||||
				if (*minorp == '.') {
 | 
									if (*minorp == '.') {
 | 
				
			||||||
					if (nfsd_minorversion(minor, cmd) < 0)
 | 
										if (nfsd_minorversion(nn, minor, cmd) < 0)
 | 
				
			||||||
						return -EINVAL;
 | 
											return -EINVAL;
 | 
				
			||||||
				} else if ((cmd == NFSD_SET) != nfsd_vers(num, NFSD_TEST)) {
 | 
									} else if ((cmd == NFSD_SET) != nfsd_vers(nn, num, NFSD_TEST)) {
 | 
				
			||||||
					/*
 | 
										/*
 | 
				
			||||||
					 * Either we have +4 and no minors are enabled,
 | 
										 * Either we have +4 and no minors are enabled,
 | 
				
			||||||
					 * or we have -4 and at least one minor is enabled.
 | 
										 * or we have -4 and at least one minor is enabled.
 | 
				
			||||||
					 * In either case, propagate 'cmd' to all minors.
 | 
										 * In either case, propagate 'cmd' to all minors.
 | 
				
			||||||
					 */
 | 
										 */
 | 
				
			||||||
					minor = 0;
 | 
										minor = 0;
 | 
				
			||||||
					while (nfsd_minorversion(minor, cmd) >= 0)
 | 
										while (nfsd_minorversion(nn, minor, cmd) >= 0)
 | 
				
			||||||
						minor++;
 | 
											minor++;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
| 
						 | 
					@ -624,7 +624,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 | 
				
			||||||
		/* If all get turned off, turn them back on, as
 | 
							/* If all get turned off, turn them back on, as
 | 
				
			||||||
		 * having no versions is BAD
 | 
							 * having no versions is BAD
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		nfsd_reset_versions();
 | 
							nfsd_reset_versions(nn);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Now write current state into reply buffer */
 | 
						/* Now write current state into reply buffer */
 | 
				
			||||||
| 
						 | 
					@ -633,12 +633,12 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
 | 
				
			||||||
	remaining = SIMPLE_TRANSACTION_LIMIT;
 | 
						remaining = SIMPLE_TRANSACTION_LIMIT;
 | 
				
			||||||
	for (num=2 ; num <= 4 ; num++) {
 | 
						for (num=2 ; num <= 4 ; num++) {
 | 
				
			||||||
		int minor;
 | 
							int minor;
 | 
				
			||||||
		if (!nfsd_vers(num, NFSD_AVAIL))
 | 
							if (!nfsd_vers(nn, num, NFSD_AVAIL))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		minor = -1;
 | 
							minor = -1;
 | 
				
			||||||
		do {
 | 
							do {
 | 
				
			||||||
			len = nfsd_print_version_support(buf, remaining,
 | 
								len = nfsd_print_version_support(nn, buf, remaining,
 | 
				
			||||||
					sep, num, minor);
 | 
										sep, num, minor);
 | 
				
			||||||
			if (len >= remaining)
 | 
								if (len >= remaining)
 | 
				
			||||||
				goto out;
 | 
									goto out;
 | 
				
			||||||
| 
						 | 
					@ -1239,6 +1239,8 @@ static __net_init int nfsd_init_net(struct net *net)
 | 
				
			||||||
	retval = nfsd_idmap_init(net);
 | 
						retval = nfsd_idmap_init(net);
 | 
				
			||||||
	if (retval)
 | 
						if (retval)
 | 
				
			||||||
		goto out_idmap_error;
 | 
							goto out_idmap_error;
 | 
				
			||||||
 | 
						nn->nfsd_versions = NULL;
 | 
				
			||||||
 | 
						nn->nfsd4_minorversions = NULL;
 | 
				
			||||||
	nn->nfsd4_lease = 90;	/* default lease time */
 | 
						nn->nfsd4_lease = 90;	/* default lease time */
 | 
				
			||||||
	nn->nfsd4_grace = 90;
 | 
						nn->nfsd4_grace = 90;
 | 
				
			||||||
	nn->somebody_reclaimed = false;
 | 
						nn->somebody_reclaimed = false;
 | 
				
			||||||
| 
						 | 
					@ -1261,6 +1263,7 @@ static __net_exit void nfsd_exit_net(struct net *net)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	nfsd_idmap_shutdown(net);
 | 
						nfsd_idmap_shutdown(net);
 | 
				
			||||||
	nfsd_export_shutdown(net);
 | 
						nfsd_export_shutdown(net);
 | 
				
			||||||
 | 
						nfsd_netns_free_versions(net_generic(net, nfsd_net_id));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pernet_operations nfsd_net_ops = {
 | 
					static struct pernet_operations nfsd_net_ops = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,10 +98,12 @@ extern const struct svc_version nfsd_acl_version3;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct nfsd_net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
 | 
					enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
 | 
				
			||||||
int nfsd_vers(int vers, enum vers_op change);
 | 
					int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change);
 | 
				
			||||||
int nfsd_minorversion(u32 minorversion, enum vers_op change);
 | 
					int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change);
 | 
				
			||||||
void nfsd_reset_versions(void);
 | 
					void nfsd_reset_versions(struct nfsd_net *nn);
 | 
				
			||||||
int nfsd_create_serv(struct net *net);
 | 
					int nfsd_create_serv(struct net *net);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int nfsd_max_blksize;
 | 
					extern int nfsd_max_blksize;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										214
									
								
								fs/nfsd/nfssvc.c
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								fs/nfsd/nfssvc.c
									
									
									
									
									
								
							| 
						 | 
					@ -38,12 +38,18 @@ static int			nfsd_acl_rpcbind_set(struct net *,
 | 
				
			||||||
						     u32, int,
 | 
											     u32, int,
 | 
				
			||||||
						     unsigned short,
 | 
											     unsigned short,
 | 
				
			||||||
						     unsigned short);
 | 
											     unsigned short);
 | 
				
			||||||
 | 
					static __be32			nfsd_acl_init_request(struct svc_rqst *,
 | 
				
			||||||
 | 
											const struct svc_program *,
 | 
				
			||||||
 | 
											struct svc_process_info *);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
static int			nfsd_rpcbind_set(struct net *,
 | 
					static int			nfsd_rpcbind_set(struct net *,
 | 
				
			||||||
						 const struct svc_program *,
 | 
											 const struct svc_program *,
 | 
				
			||||||
						 u32, int,
 | 
											 u32, int,
 | 
				
			||||||
						 unsigned short,
 | 
											 unsigned short,
 | 
				
			||||||
						 unsigned short);
 | 
											 unsigned short);
 | 
				
			||||||
 | 
					static __be32			nfsd_init_request(struct svc_rqst *,
 | 
				
			||||||
 | 
											const struct svc_program *,
 | 
				
			||||||
 | 
											struct svc_process_info *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
 | 
					 * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members
 | 
				
			||||||
| 
						 | 
					@ -98,7 +104,7 @@ static struct svc_program	nfsd_acl_program = {
 | 
				
			||||||
	.pg_class		= "nfsd",
 | 
						.pg_class		= "nfsd",
 | 
				
			||||||
	.pg_stats		= &nfsd_acl_svcstats,
 | 
						.pg_stats		= &nfsd_acl_svcstats,
 | 
				
			||||||
	.pg_authenticate	= &svc_set_client,
 | 
						.pg_authenticate	= &svc_set_client,
 | 
				
			||||||
	.pg_init_request	= svc_generic_init_request,
 | 
						.pg_init_request	= nfsd_acl_init_request,
 | 
				
			||||||
	.pg_rpcbind_set		= nfsd_acl_rpcbind_set,
 | 
						.pg_rpcbind_set		= nfsd_acl_rpcbind_set,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,7 +125,6 @@ static const struct svc_version *nfsd_version[] = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NFSD_MINVERS    	2
 | 
					#define NFSD_MINVERS    	2
 | 
				
			||||||
#define NFSD_NRVERS		ARRAY_SIZE(nfsd_version)
 | 
					#define NFSD_NRVERS		ARRAY_SIZE(nfsd_version)
 | 
				
			||||||
static const struct svc_version *nfsd_versions[NFSD_NRVERS];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
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)
 | 
				
			||||||
| 
						 | 
					@ -127,78 +132,136 @@ struct svc_program		nfsd_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_NRVERS,		/* nr of entries in nfsd_version */
 | 
				
			||||||
	.pg_vers		= nfsd_versions,	/* 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 */
 | 
				
			||||||
	.pg_stats		= &nfsd_svcstats,	/* version table */
 | 
						.pg_stats		= &nfsd_svcstats,	/* version table */
 | 
				
			||||||
	.pg_authenticate	= &svc_set_client,	/* export authentication */
 | 
						.pg_authenticate	= &svc_set_client,	/* export authentication */
 | 
				
			||||||
	.pg_init_request	= svc_generic_init_request,
 | 
						.pg_init_request	= nfsd_init_request,
 | 
				
			||||||
	.pg_rpcbind_set		= nfsd_rpcbind_set,
 | 
						.pg_rpcbind_set		= nfsd_rpcbind_set,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = {
 | 
					static bool
 | 
				
			||||||
	[0] = 1,
 | 
					nfsd_support_version(int vers)
 | 
				
			||||||
	[1] = 1,
 | 
					{
 | 
				
			||||||
	[2] = 1,
 | 
						if (vers >= NFSD_MINVERS && vers < NFSD_NRVERS)
 | 
				
			||||||
};
 | 
							return nfsd_version[vers] != NULL;
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfsd_vers(int vers, enum vers_op change)
 | 
					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_NRVERS)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	switch(change) {
 | 
						switch(change) {
 | 
				
			||||||
	case NFSD_SET:
 | 
						case NFSD_SET:
 | 
				
			||||||
		nfsd_versions[vers] = nfsd_version[vers];
 | 
							if (nn->nfsd_versions)
 | 
				
			||||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 | 
								nn->nfsd_versions[vers] = nfsd_support_version(vers);
 | 
				
			||||||
		if (vers < NFSD_ACL_NRVERS)
 | 
					 | 
				
			||||||
			nfsd_acl_versions[vers] = nfsd_acl_version[vers];
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case NFSD_CLEAR:
 | 
						case NFSD_CLEAR:
 | 
				
			||||||
		nfsd_versions[vers] = NULL;
 | 
							nfsd_netns_init_versions(nn);
 | 
				
			||||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
 | 
							if (nn->nfsd_versions)
 | 
				
			||||||
		if (vers < NFSD_ACL_NRVERS)
 | 
								nn->nfsd_versions[vers] = false;
 | 
				
			||||||
			nfsd_acl_versions[vers] = NULL;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case NFSD_TEST:
 | 
						case NFSD_TEST:
 | 
				
			||||||
		return nfsd_versions[vers] != NULL;
 | 
							if (nn->nfsd_versions)
 | 
				
			||||||
 | 
								return nn->nfsd_versions[vers];
 | 
				
			||||||
 | 
							/* Fallthrough */
 | 
				
			||||||
	case NFSD_AVAIL:
 | 
						case NFSD_AVAIL:
 | 
				
			||||||
		return nfsd_version[vers] != NULL;
 | 
							return nfsd_support_version(vers);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
nfsd_adjust_nfsd_versions4(void)
 | 
					nfsd_adjust_nfsd_versions4(struct nfsd_net *nn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned i;
 | 
						unsigned i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) {
 | 
						for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) {
 | 
				
			||||||
		if (nfsd_supported_minorversions[i])
 | 
							if (nn->nfsd4_minorversions[i])
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	nfsd_vers(4, NFSD_CLEAR);
 | 
						nfsd_vers(nn, 4, NFSD_CLEAR);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int nfsd_minorversion(u32 minorversion, enum vers_op change)
 | 
					int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (minorversion > NFSD_SUPPORTED_MINOR_VERSION &&
 | 
						if (minorversion > NFSD_SUPPORTED_MINOR_VERSION &&
 | 
				
			||||||
	    change != NFSD_AVAIL)
 | 
						    change != NFSD_AVAIL)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(change) {
 | 
						switch(change) {
 | 
				
			||||||
	case NFSD_SET:
 | 
						case NFSD_SET:
 | 
				
			||||||
		nfsd_supported_minorversions[minorversion] = true;
 | 
							if (nn->nfsd4_minorversions) {
 | 
				
			||||||
		nfsd_vers(4, NFSD_SET);
 | 
								nfsd_vers(nn, 4, NFSD_SET);
 | 
				
			||||||
 | 
								nn->nfsd4_minorversions[minorversion] =
 | 
				
			||||||
 | 
									nfsd_vers(nn, 4, NFSD_TEST);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case NFSD_CLEAR:
 | 
						case NFSD_CLEAR:
 | 
				
			||||||
		nfsd_supported_minorversions[minorversion] = false;
 | 
							nfsd_netns_init_versions(nn);
 | 
				
			||||||
		nfsd_adjust_nfsd_versions4();
 | 
							if (nn->nfsd4_minorversions) {
 | 
				
			||||||
 | 
								nn->nfsd4_minorversions[minorversion] = false;
 | 
				
			||||||
 | 
								nfsd_adjust_nfsd_versions4(nn);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case NFSD_TEST:
 | 
						case NFSD_TEST:
 | 
				
			||||||
		return nfsd_supported_minorversions[minorversion];
 | 
							if (nn->nfsd4_minorversions)
 | 
				
			||||||
 | 
								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);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -280,13 +343,9 @@ static void nfsd_shutdown_generic(void)
 | 
				
			||||||
	nfsd_racache_shutdown();
 | 
						nfsd_racache_shutdown();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool nfsd_needs_lockd(void)
 | 
					static bool nfsd_needs_lockd(struct nfsd_net *nn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#if defined(CONFIG_NFSD_V3)
 | 
						return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST);
 | 
				
			||||||
	return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	return (nfsd_versions[2] != NULL);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int nfsd_startup_net(int nrservs, struct net *net)
 | 
					static int nfsd_startup_net(int nrservs, struct net *net)
 | 
				
			||||||
| 
						 | 
					@ -304,7 +363,7 @@ static int nfsd_startup_net(int nrservs, struct net *net)
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto out_socks;
 | 
							goto out_socks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nfsd_needs_lockd() && !nn->lockd_up) {
 | 
						if (nfsd_needs_lockd(nn) && !nn->lockd_up) {
 | 
				
			||||||
		ret = lockd_up(net);
 | 
							ret = lockd_up(net);
 | 
				
			||||||
		if (ret)
 | 
							if (ret)
 | 
				
			||||||
			goto out_socks;
 | 
								goto out_socks;
 | 
				
			||||||
| 
						 | 
					@ -437,20 +496,20 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
 | 
				
			||||||
	nfsd_export_flush(net);
 | 
						nfsd_export_flush(net);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void nfsd_reset_versions(void)
 | 
					void nfsd_reset_versions(struct nfsd_net *nn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < NFSD_NRVERS; i++)
 | 
						for (i = 0; i < NFSD_NRVERS; i++)
 | 
				
			||||||
		if (nfsd_vers(i, NFSD_TEST))
 | 
							if (nfsd_vers(nn, i, NFSD_TEST))
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < NFSD_NRVERS; i++)
 | 
						for (i = 0; i < NFSD_NRVERS; i++)
 | 
				
			||||||
		if (i != 4)
 | 
							if (i != 4)
 | 
				
			||||||
			nfsd_vers(i, NFSD_SET);
 | 
								nfsd_vers(nn, i, NFSD_SET);
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
			int minor = 0;
 | 
								int minor = 0;
 | 
				
			||||||
			while (nfsd_minorversion(minor, NFSD_SET) >= 0)
 | 
								while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0)
 | 
				
			||||||
				minor++;
 | 
									minor++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -518,7 +577,7 @@ int nfsd_create_serv(struct net *net)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (nfsd_max_blksize == 0)
 | 
						if (nfsd_max_blksize == 0)
 | 
				
			||||||
		nfsd_max_blksize = nfsd_get_default_max_blksize();
 | 
							nfsd_max_blksize = nfsd_get_default_max_blksize();
 | 
				
			||||||
	nfsd_reset_versions();
 | 
						nfsd_reset_versions(nn);
 | 
				
			||||||
	nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
 | 
						nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
 | 
				
			||||||
						&nfsd_thread_sv_ops);
 | 
											&nfsd_thread_sv_ops);
 | 
				
			||||||
	if (nn->nfsd_serv == NULL)
 | 
						if (nn->nfsd_serv == NULL)
 | 
				
			||||||
| 
						 | 
					@ -697,11 +756,44 @@ nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp,
 | 
				
			||||||
		     unsigned short port)
 | 
							     unsigned short port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!nfsd_support_acl_version(version) ||
 | 
						if (!nfsd_support_acl_version(version) ||
 | 
				
			||||||
	    !nfsd_vers(version, NFSD_TEST))
 | 
						    !nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return svc_generic_rpcbind_set(net, progp, version, family,
 | 
						return svc_generic_rpcbind_set(net, progp, version, family,
 | 
				
			||||||
			proto, port);
 | 
								proto, port);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __be32
 | 
				
			||||||
 | 
					nfsd_acl_init_request(struct svc_rqst *rqstp,
 | 
				
			||||||
 | 
							      const struct svc_program *progp,
 | 
				
			||||||
 | 
							      struct svc_process_info *ret)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (likely(nfsd_support_acl_version(rqstp->rq_vers) &&
 | 
				
			||||||
 | 
						    nfsd_vers(nn, rqstp->rq_vers, NFSD_TEST)))
 | 
				
			||||||
 | 
							return svc_generic_init_request(rqstp, progp, ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret->mismatch.lovers = NFSD_ACL_NRVERS;
 | 
				
			||||||
 | 
						for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
 | 
				
			||||||
 | 
							if (nfsd_support_acl_version(rqstp->rq_vers) &&
 | 
				
			||||||
 | 
							    nfsd_vers(nn, i, NFSD_TEST)) {
 | 
				
			||||||
 | 
								ret->mismatch.lovers = i;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ret->mismatch.lovers == NFSD_ACL_NRVERS)
 | 
				
			||||||
 | 
							return rpc_prog_unavail;
 | 
				
			||||||
 | 
						ret->mismatch.hivers = NFSD_ACL_MINVERS;
 | 
				
			||||||
 | 
						for (i = NFSD_ACL_NRVERS - 1; i >= NFSD_ACL_MINVERS; i--) {
 | 
				
			||||||
 | 
							if (nfsd_support_acl_version(rqstp->rq_vers) &&
 | 
				
			||||||
 | 
							    nfsd_vers(nn, i, NFSD_TEST)) {
 | 
				
			||||||
 | 
								ret->mismatch.hivers = i;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rpc_prog_mismatch;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
| 
						 | 
					@ -709,12 +801,42 @@ nfsd_rpcbind_set(struct net *net, const struct svc_program *progp,
 | 
				
			||||||
		 u32 version, int family, unsigned short proto,
 | 
							 u32 version, int family, unsigned short proto,
 | 
				
			||||||
		 unsigned short port)
 | 
							 unsigned short port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!nfsd_vers(version, NFSD_TEST))
 | 
						if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	return svc_generic_rpcbind_set(net, progp, version, family,
 | 
						return svc_generic_rpcbind_set(net, progp, version, family,
 | 
				
			||||||
			proto, port);
 | 
								proto, port);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static __be32
 | 
				
			||||||
 | 
					nfsd_init_request(struct svc_rqst *rqstp,
 | 
				
			||||||
 | 
							  const struct svc_program *progp,
 | 
				
			||||||
 | 
							  struct svc_process_info *ret)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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++) {
 | 
				
			||||||
 | 
							if (nfsd_vers(nn, i, NFSD_TEST)) {
 | 
				
			||||||
 | 
								ret->mismatch.lovers = i;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (ret->mismatch.lovers == NFSD_NRVERS)
 | 
				
			||||||
 | 
							return rpc_prog_unavail;
 | 
				
			||||||
 | 
						ret->mismatch.hivers = NFSD_MINVERS;
 | 
				
			||||||
 | 
						for (i = NFSD_NRVERS - 1; i >= NFSD_MINVERS; i--) {
 | 
				
			||||||
 | 
							if (nfsd_vers(nn, i, NFSD_TEST)) {
 | 
				
			||||||
 | 
								ret->mismatch.hivers = i;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return rpc_prog_mismatch;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This is the NFS server kernel thread
 | 
					 * This is the NFS server kernel thread
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue