mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	nfsd: Support the server resetting the boot verifier
Add support to allow the server to reset the boot verifier in order to force clients to resend I/O after a timeout failure. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Lance Shelton <lance.shelton@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
		
							parent
							
								
									5e113224c1
								
							
						
					
					
						commit
						27c438f53e
					
				
					 5 changed files with 48 additions and 15 deletions
				
			
		|  | @ -104,6 +104,7 @@ struct nfsd_net { | |||
| 
 | ||||
| 	/* Time of server startup */ | ||||
| 	struct timespec64 nfssvc_boot; | ||||
| 	seqlock_t boot_lock; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Max number of connections this nfsd container will allow. Defaults | ||||
|  | @ -179,4 +180,7 @@ struct nfsd_net { | |||
| extern void nfsd_netns_free_versions(struct nfsd_net *nn); | ||||
| 
 | ||||
| extern unsigned int nfsd_net_id; | ||||
| 
 | ||||
| void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn); | ||||
| void nfsd_reset_boot_verifier(struct nfsd_net *nn); | ||||
| #endif /* __NFSD_NETNS_H__ */ | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ static u32	nfs3_ftypes[] = { | |||
| 	NF3SOCK, NF3BAD,  NF3LNK, NF3BAD, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
|  * XDR functions for basic NFS types | ||||
|  */ | ||||
|  | @ -751,14 +752,16 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) | |||
| { | ||||
| 	struct nfsd3_writeres *resp = rqstp->rq_resp; | ||||
| 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||||
| 	__be32 verf[2]; | ||||
| 
 | ||||
| 	p = encode_wcc_data(rqstp, p, &resp->fh); | ||||
| 	if (resp->status == 0) { | ||||
| 		*p++ = htonl(resp->count); | ||||
| 		*p++ = htonl(resp->committed); | ||||
| 		/* unique identifier, y2038 overflow can be ignored */ | ||||
| 		*p++ = htonl((u32)nn->nfssvc_boot.tv_sec); | ||||
| 		*p++ = htonl(nn->nfssvc_boot.tv_nsec); | ||||
| 		nfsd_copy_boot_verifier(verf, nn); | ||||
| 		*p++ = verf[0]; | ||||
| 		*p++ = verf[1]; | ||||
| 	} | ||||
| 	return xdr_ressize_check(rqstp, p); | ||||
| } | ||||
|  | @ -1125,13 +1128,15 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) | |||
| { | ||||
| 	struct nfsd3_commitres *resp = rqstp->rq_resp; | ||||
| 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||||
| 	__be32 verf[2]; | ||||
| 
 | ||||
| 	p = encode_wcc_data(rqstp, p, &resp->fh); | ||||
| 	/* Write verifier */ | ||||
| 	if (resp->status == 0) { | ||||
| 		/* unique identifier, y2038 overflow can be ignored */ | ||||
| 		*p++ = htonl((u32)nn->nfssvc_boot.tv_sec); | ||||
| 		*p++ = htonl(nn->nfssvc_boot.tv_nsec); | ||||
| 		nfsd_copy_boot_verifier(verf, nn); | ||||
| 		*p++ = verf[0]; | ||||
| 		*p++ = verf[1]; | ||||
| 	} | ||||
| 	return xdr_ressize_check(rqstp, p); | ||||
| } | ||||
|  |  | |||
|  | @ -568,17 +568,11 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 
 | ||||
| static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) | ||||
| { | ||||
| 	__be32 verf[2]; | ||||
| 	struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||||
| 	__be32 *verf = (__be32 *)verifier->data; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This is opaque to client, so no need to byte-swap. Use | ||||
| 	 * __force to keep sparse happy. y2038 time_t overflow is | ||||
| 	 * irrelevant in this usage. | ||||
| 	 */ | ||||
| 	verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; | ||||
| 	verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; | ||||
| 	memcpy(verifier->data, verf, sizeof(verifier->data)); | ||||
| 	BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data)); | ||||
| 
 | ||||
| 	nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id)); | ||||
| } | ||||
| 
 | ||||
| static __be32 | ||||
|  |  | |||
|  | @ -1477,6 +1477,7 @@ static __net_init int nfsd_init_net(struct net *net) | |||
| 
 | ||||
| 	atomic_set(&nn->ntf_refcnt, 0); | ||||
| 	init_waitqueue_head(&nn->ntf_wq); | ||||
| 	seqlock_init(&nn->boot_lock); | ||||
| 
 | ||||
| 	mnt =  vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL); | ||||
| 	if (IS_ERR(mnt)) { | ||||
|  |  | |||
|  | @ -344,6 +344,35 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn) | |||
| 	return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); | ||||
| } | ||||
| 
 | ||||
| void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) | ||||
| { | ||||
| 	int seq = 0; | ||||
| 
 | ||||
| 	do { | ||||
| 		read_seqbegin_or_lock(&nn->boot_lock, &seq); | ||||
| 		/*
 | ||||
| 		 * This is opaque to client, so no need to byte-swap. Use | ||||
| 		 * __force to keep sparse happy. y2038 time_t overflow is | ||||
| 		 * irrelevant in this usage | ||||
| 		 */ | ||||
| 		verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; | ||||
| 		verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; | ||||
| 	} while (need_seqretry(&nn->boot_lock, seq)); | ||||
| 	done_seqretry(&nn->boot_lock, seq); | ||||
| } | ||||
| 
 | ||||
| void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) | ||||
| { | ||||
| 	ktime_get_real_ts64(&nn->nfssvc_boot); | ||||
| } | ||||
| 
 | ||||
| void nfsd_reset_boot_verifier(struct nfsd_net *nn) | ||||
| { | ||||
| 	write_seqlock(&nn->boot_lock); | ||||
| 	nfsd_reset_boot_verifier_locked(nn); | ||||
| 	write_sequnlock(&nn->boot_lock); | ||||
| } | ||||
| 
 | ||||
| static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred) | ||||
| { | ||||
| 	struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||||
|  | @ -596,7 +625,7 @@ int nfsd_create_serv(struct net *net) | |||
| #endif | ||||
| 	} | ||||
| 	atomic_inc(&nn->ntf_refcnt); | ||||
| 	ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ | ||||
| 	nfsd_reset_boot_verifier(nn); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Trond Myklebust
						Trond Myklebust