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
					
				| @ -134,10 +134,18 @@ struct nfsd_net { | ||||
| 	u32		s2s_cp_cl_id; | ||||
| 	struct idr	s2s_cp_stateids; | ||||
| 	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 */ | ||||
| #define nfsd_netns_ready(nn) ((nn)->sessionid_hashtbl) | ||||
| 
 | ||||
| extern void nfsd_netns_free_versions(struct nfsd_net *nn); | ||||
| 
 | ||||
| extern unsigned int nfsd_net_id; | ||||
| #endif /* __NFSD_NETNS_H__ */ | ||||
|  | ||||
| @ -1926,6 +1926,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) | ||||
| 	struct nfsd4_compound_state *cstate = &resp->cstate; | ||||
| 	struct svc_fh *current_fh = &cstate->current_fh; | ||||
| 	struct svc_fh *save_fh = &cstate->save_fh; | ||||
| 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||||
| 	__be32		status; | ||||
| 
 | ||||
| 	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. | ||||
| 	 */ | ||||
| 	status = nfserr_minor_vers_mismatch; | ||||
| 	if (nfsd_minorversion(args->minorversion, NFSD_TEST) <= 0) | ||||
| 	if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0) | ||||
| 		goto out; | ||||
| 	status = nfserr_resource; | ||||
| 	if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND) | ||||
|  | ||||
| @ -537,14 +537,14 @@ out_free: | ||||
| } | ||||
| 
 | ||||
| static ssize_t | ||||
| nfsd_print_version_support(char *buf, int remaining, const char *sep, | ||||
| 		unsigned vers, int minor) | ||||
| nfsd_print_version_support(struct nfsd_net *nn, char *buf, int remaining, | ||||
| 		const char *sep, unsigned vers, int minor) | ||||
| { | ||||
| 	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 && | ||||
| 	    !nfsd_minorversion(minor, NFSD_TEST)) | ||||
| 	    !nfsd_minorversion(nn, minor, NFSD_TEST)) | ||||
| 		supported = false; | ||||
| 	if (minor == 0 && supported) | ||||
| 		/*
 | ||||
| @ -599,20 +599,20 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) | ||||
| 			switch(num) { | ||||
| 			case 2: | ||||
| 			case 3: | ||||
| 				nfsd_vers(num, cmd); | ||||
| 				nfsd_vers(nn, num, cmd); | ||||
| 				break; | ||||
| 			case 4: | ||||
| 				if (*minorp == '.') { | ||||
| 					if (nfsd_minorversion(minor, cmd) < 0) | ||||
| 					if (nfsd_minorversion(nn, minor, cmd) < 0) | ||||
| 						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, | ||||
| 					 * or we have -4 and at least one minor is enabled. | ||||
| 					 * In either case, propagate 'cmd' to all minors. | ||||
| 					 */ | ||||
| 					minor = 0; | ||||
| 					while (nfsd_minorversion(minor, cmd) >= 0) | ||||
| 					while (nfsd_minorversion(nn, minor, cmd) >= 0) | ||||
| 						minor++; | ||||
| 				} | ||||
| 				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
 | ||||
| 		 * having no versions is BAD | ||||
| 		 */ | ||||
| 		nfsd_reset_versions(); | ||||
| 		nfsd_reset_versions(nn); | ||||
| 	} | ||||
| 
 | ||||
| 	/* 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; | ||||
| 	for (num=2 ; num <= 4 ; num++) { | ||||
| 		int minor; | ||||
| 		if (!nfsd_vers(num, NFSD_AVAIL)) | ||||
| 		if (!nfsd_vers(nn, num, NFSD_AVAIL)) | ||||
| 			continue; | ||||
| 
 | ||||
| 		minor = -1; | ||||
| 		do { | ||||
| 			len = nfsd_print_version_support(buf, remaining, | ||||
| 			len = nfsd_print_version_support(nn, buf, remaining, | ||||
| 					sep, num, minor); | ||||
| 			if (len >= remaining) | ||||
| 				goto out; | ||||
| @ -1239,6 +1239,8 @@ static __net_init int nfsd_init_net(struct net *net) | ||||
| 	retval = nfsd_idmap_init(net); | ||||
| 	if (retval) | ||||
| 		goto out_idmap_error; | ||||
| 	nn->nfsd_versions = NULL; | ||||
| 	nn->nfsd4_minorversions = NULL; | ||||
| 	nn->nfsd4_lease = 90;	/* default lease time */ | ||||
| 	nn->nfsd4_grace = 90; | ||||
| 	nn->somebody_reclaimed = false; | ||||
| @ -1261,6 +1263,7 @@ static __net_exit void nfsd_exit_net(struct net *net) | ||||
| { | ||||
| 	nfsd_idmap_shutdown(net); | ||||
| 	nfsd_export_shutdown(net); | ||||
| 	nfsd_netns_free_versions(net_generic(net, nfsd_net_id)); | ||||
| } | ||||
| 
 | ||||
| static struct pernet_operations nfsd_net_ops = { | ||||
|  | ||||
| @ -98,10 +98,12 @@ extern const struct svc_version nfsd_acl_version3; | ||||
| #endif | ||||
| #endif | ||||
| 
 | ||||
| struct nfsd_net; | ||||
| 
 | ||||
| enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | ||||
| int nfsd_vers(int vers, enum vers_op change); | ||||
| int nfsd_minorversion(u32 minorversion, enum vers_op change); | ||||
| void nfsd_reset_versions(void); | ||||
| int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change); | ||||
| int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change); | ||||
| void nfsd_reset_versions(struct nfsd_net *nn); | ||||
| int nfsd_create_serv(struct net *net); | ||||
| 
 | ||||
| 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, | ||||
| 						     unsigned short, | ||||
| 						     unsigned short); | ||||
| static __be32			nfsd_acl_init_request(struct svc_rqst *, | ||||
| 						const struct svc_program *, | ||||
| 						struct svc_process_info *); | ||||
| #endif | ||||
| static int			nfsd_rpcbind_set(struct net *, | ||||
| 						 const struct svc_program *, | ||||
| 						 u32, int, | ||||
| 						 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 | ||||
| @ -98,7 +104,7 @@ static struct svc_program	nfsd_acl_program = { | ||||
| 	.pg_class		= "nfsd", | ||||
| 	.pg_stats		= &nfsd_acl_svcstats, | ||||
| 	.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, | ||||
| }; | ||||
| 
 | ||||
| @ -119,7 +125,6 @@ static const struct svc_version *nfsd_version[] = { | ||||
| 
 | ||||
| #define NFSD_MINVERS    	2 | ||||
| #define NFSD_NRVERS		ARRAY_SIZE(nfsd_version) | ||||
| static const struct svc_version *nfsd_versions[NFSD_NRVERS]; | ||||
| 
 | ||||
| struct svc_program		nfsd_program = { | ||||
| #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||||
| @ -127,78 +132,136 @@ struct svc_program		nfsd_program = { | ||||
| #endif | ||||
| 	.pg_prog		= NFS_PROGRAM,		/* program number */ | ||||
| 	.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_class		= "nfsd",		/* authentication class */ | ||||
| 	.pg_stats		= &nfsd_svcstats,	/* version table */ | ||||
| 	.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, | ||||
| }; | ||||
| 
 | ||||
| static bool nfsd_supported_minorversions[NFSD_SUPPORTED_MINOR_VERSION + 1] = { | ||||
| 	[0] = 1, | ||||
| 	[1] = 1, | ||||
| 	[2] = 1, | ||||
| }; | ||||
| static bool | ||||
| nfsd_support_version(int vers) | ||||
| { | ||||
| 	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) | ||||
| 		return 0; | ||||
| 	switch(change) { | ||||
| 	case NFSD_SET: | ||||
| 		nfsd_versions[vers] = nfsd_version[vers]; | ||||
| #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||||
| 		if (vers < NFSD_ACL_NRVERS) | ||||
| 			nfsd_acl_versions[vers] = nfsd_acl_version[vers]; | ||||
| #endif | ||||
| 		if (nn->nfsd_versions) | ||||
| 			nn->nfsd_versions[vers] = nfsd_support_version(vers); | ||||
| 		break; | ||||
| 	case NFSD_CLEAR: | ||||
| 		nfsd_versions[vers] = NULL; | ||||
| #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) | ||||
| 		if (vers < NFSD_ACL_NRVERS) | ||||
| 			nfsd_acl_versions[vers] = NULL; | ||||
| #endif | ||||
| 		nfsd_netns_init_versions(nn); | ||||
| 		if (nn->nfsd_versions) | ||||
| 			nn->nfsd_versions[vers] = false; | ||||
| 		break; | ||||
| 	case NFSD_TEST: | ||||
| 		return nfsd_versions[vers] != NULL; | ||||
| 		if (nn->nfsd_versions) | ||||
| 			return nn->nfsd_versions[vers]; | ||||
| 		/* Fallthrough */ | ||||
| 	case NFSD_AVAIL: | ||||
| 		return nfsd_version[vers] != NULL; | ||||
| 		return nfsd_support_version(vers); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| nfsd_adjust_nfsd_versions4(void) | ||||
| nfsd_adjust_nfsd_versions4(struct nfsd_net *nn) | ||||
| { | ||||
| 	unsigned i; | ||||
| 
 | ||||
| 	for (i = 0; i <= NFSD_SUPPORTED_MINOR_VERSION; i++) { | ||||
| 		if (nfsd_supported_minorversions[i]) | ||||
| 		if (nn->nfsd4_minorversions[i]) | ||||
| 			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 && | ||||
| 	    change != NFSD_AVAIL) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	switch(change) { | ||||
| 	case NFSD_SET: | ||||
| 		nfsd_supported_minorversions[minorversion] = true; | ||||
| 		nfsd_vers(4, 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_supported_minorversions[minorversion] = false; | ||||
| 		nfsd_adjust_nfsd_versions4(); | ||||
| 		nfsd_netns_init_versions(nn); | ||||
| 		if (nn->nfsd4_minorversions) { | ||||
| 			nn->nfsd4_minorversions[minorversion] = false; | ||||
| 			nfsd_adjust_nfsd_versions4(nn); | ||||
| 		} | ||||
| 		break; | ||||
| 	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: | ||||
| 		return minorversion <= NFSD_SUPPORTED_MINOR_VERSION; | ||||
| 		return minorversion <= NFSD_SUPPORTED_MINOR_VERSION && | ||||
| 			nfsd_vers(nn, 4, NFSD_AVAIL); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
| @ -280,13 +343,9 @@ static void nfsd_shutdown_generic(void) | ||||
| 	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_versions[2] != NULL) || (nfsd_versions[3] != NULL); | ||||
| #else | ||||
| 	return (nfsd_versions[2] != NULL); | ||||
| #endif | ||||
| 	return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| 		goto out_socks; | ||||
| 
 | ||||
| 	if (nfsd_needs_lockd() && !nn->lockd_up) { | ||||
| 	if (nfsd_needs_lockd(nn) && !nn->lockd_up) { | ||||
| 		ret = lockd_up(net); | ||||
| 		if (ret) | ||||
| 			goto out_socks; | ||||
| @ -437,20 +496,20 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) | ||||
| 	nfsd_export_flush(net); | ||||
| } | ||||
| 
 | ||||
| void nfsd_reset_versions(void) | ||||
| void nfsd_reset_versions(struct nfsd_net *nn) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (i = 0; i < NFSD_NRVERS; i++) | ||||
| 		if (nfsd_vers(i, NFSD_TEST)) | ||||
| 		if (nfsd_vers(nn, i, NFSD_TEST)) | ||||
| 			return; | ||||
| 
 | ||||
| 	for (i = 0; i < NFSD_NRVERS; i++) | ||||
| 		if (i != 4) | ||||
| 			nfsd_vers(i, NFSD_SET); | ||||
| 			nfsd_vers(nn, i, NFSD_SET); | ||||
| 		else { | ||||
| 			int minor = 0; | ||||
| 			while (nfsd_minorversion(minor, NFSD_SET) >= 0) | ||||
| 			while (nfsd_minorversion(nn, minor, NFSD_SET) >= 0) | ||||
| 				minor++; | ||||
| 		} | ||||
| } | ||||
| @ -518,7 +577,7 @@ int nfsd_create_serv(struct net *net) | ||||
| 	} | ||||
| 	if (nfsd_max_blksize == 0) | ||||
| 		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, | ||||
| 						&nfsd_thread_sv_ops); | ||||
| 	if (nn->nfsd_serv == NULL) | ||||
| @ -697,11 +756,44 @@ nfsd_acl_rpcbind_set(struct net *net, const struct svc_program *progp, | ||||
| 		     unsigned short port) | ||||
| { | ||||
| 	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 svc_generic_rpcbind_set(net, progp, version, family, | ||||
| 			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 | ||||
| 
 | ||||
| static int | ||||
| @ -709,12 +801,42 @@ nfsd_rpcbind_set(struct net *net, const struct svc_program *progp, | ||||
| 		 u32 version, int family, unsigned short proto, | ||||
| 		 unsigned short port) | ||||
| { | ||||
| 	if (!nfsd_vers(version, NFSD_TEST)) | ||||
| 	if (!nfsd_vers(net_generic(net, nfsd_net_id), version, NFSD_TEST)) | ||||
| 		return 0; | ||||
| 	return svc_generic_rpcbind_set(net, progp, version, family, | ||||
| 			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 | ||||
|  */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user