summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2019-09-02 13:02:56 -0400
committerJ. Bruce Fields <bfields@redhat.com>2019-09-10 09:23:41 -0400
commit27c438f53e79b81dc8805a81f6cd74824ba57290 (patch)
tree58165481c4ed3f51742526143c7e4db3f273338b
parent5e113224c17e2fb156b785ddbbc48a0209fddb0c (diff)
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>
-rw-r--r--fs/nfsd/netns.h4
-rw-r--r--fs/nfsd/nfs3xdr.c13
-rw-r--r--fs/nfsd/nfs4proc.c14
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/nfssvc.c31
5 files changed, 48 insertions, 15 deletions
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index bdfe5bcb3dcd..9a4ef815fb8c 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -104,6 +104,7 @@ struct nfsd_net {
104 104
105 /* Time of server startup */ 105 /* Time of server startup */
106 struct timespec64 nfssvc_boot; 106 struct timespec64 nfssvc_boot;
107 seqlock_t boot_lock;
107 108
108 /* 109 /*
109 * Max number of connections this nfsd container will allow. Defaults 110 * Max number of connections this nfsd container will allow. Defaults
@@ -179,4 +180,7 @@ struct nfsd_net {
179extern void nfsd_netns_free_versions(struct nfsd_net *nn); 180extern void nfsd_netns_free_versions(struct nfsd_net *nn);
180 181
181extern unsigned int nfsd_net_id; 182extern unsigned int nfsd_net_id;
183
184void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn);
185void nfsd_reset_boot_verifier(struct nfsd_net *nn);
182#endif /* __NFSD_NETNS_H__ */ 186#endif /* __NFSD_NETNS_H__ */
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index fcf31822c74c..86e5658651f1 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -27,6 +27,7 @@ static u32 nfs3_ftypes[] = {
27 NF3SOCK, NF3BAD, NF3LNK, NF3BAD, 27 NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
28}; 28};
29 29
30
30/* 31/*
31 * XDR functions for basic NFS types 32 * XDR functions for basic NFS types
32 */ 33 */
@@ -751,14 +752,16 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
751{ 752{
752 struct nfsd3_writeres *resp = rqstp->rq_resp; 753 struct nfsd3_writeres *resp = rqstp->rq_resp;
753 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 754 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
755 __be32 verf[2];
754 756
755 p = encode_wcc_data(rqstp, p, &resp->fh); 757 p = encode_wcc_data(rqstp, p, &resp->fh);
756 if (resp->status == 0) { 758 if (resp->status == 0) {
757 *p++ = htonl(resp->count); 759 *p++ = htonl(resp->count);
758 *p++ = htonl(resp->committed); 760 *p++ = htonl(resp->committed);
759 /* unique identifier, y2038 overflow can be ignored */ 761 /* unique identifier, y2038 overflow can be ignored */
760 *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); 762 nfsd_copy_boot_verifier(verf, nn);
761 *p++ = htonl(nn->nfssvc_boot.tv_nsec); 763 *p++ = verf[0];
764 *p++ = verf[1];
762 } 765 }
763 return xdr_ressize_check(rqstp, p); 766 return xdr_ressize_check(rqstp, p);
764} 767}
@@ -1125,13 +1128,15 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
1125{ 1128{
1126 struct nfsd3_commitres *resp = rqstp->rq_resp; 1129 struct nfsd3_commitres *resp = rqstp->rq_resp;
1127 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 1130 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1131 __be32 verf[2];
1128 1132
1129 p = encode_wcc_data(rqstp, p, &resp->fh); 1133 p = encode_wcc_data(rqstp, p, &resp->fh);
1130 /* Write verifier */ 1134 /* Write verifier */
1131 if (resp->status == 0) { 1135 if (resp->status == 0) {
1132 /* unique identifier, y2038 overflow can be ignored */ 1136 /* unique identifier, y2038 overflow can be ignored */
1133 *p++ = htonl((u32)nn->nfssvc_boot.tv_sec); 1137 nfsd_copy_boot_verifier(verf, nn);
1134 *p++ = htonl(nn->nfssvc_boot.tv_nsec); 1138 *p++ = verf[0];
1139 *p++ = verf[1];
1135 } 1140 }
1136 return xdr_ressize_check(rqstp, p); 1141 return xdr_ressize_check(rqstp, p);
1137} 1142}
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index cb51893ec1cd..4e3e77b76411 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -568,17 +568,11 @@ nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
568 568
569static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) 569static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
570{ 570{
571 __be32 verf[2]; 571 __be32 *verf = (__be32 *)verifier->data;
572 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
573 572
574 /* 573 BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data));
575 * This is opaque to client, so no need to byte-swap. Use 574
576 * __force to keep sparse happy. y2038 time_t overflow is 575 nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id));
577 * irrelevant in this usage.
578 */
579 verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec;
580 verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec;
581 memcpy(verifier->data, verf, sizeof(verifier->data));
582} 576}
583 577
584static __be32 578static __be32
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 3cf4f6aa48d6..33cbe2e5d937 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1477,6 +1477,7 @@ static __net_init int nfsd_init_net(struct net *net)
1477 1477
1478 atomic_set(&nn->ntf_refcnt, 0); 1478 atomic_set(&nn->ntf_refcnt, 0);
1479 init_waitqueue_head(&nn->ntf_wq); 1479 init_waitqueue_head(&nn->ntf_wq);
1480 seqlock_init(&nn->boot_lock);
1480 1481
1481 mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL); 1482 mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL);
1482 if (IS_ERR(mnt)) { 1483 if (IS_ERR(mnt)) {
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index b944553c6927..3caaf5675259 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -344,6 +344,35 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn)
344 return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); 344 return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST);
345} 345}
346 346
347void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn)
348{
349 int seq = 0;
350
351 do {
352 read_seqbegin_or_lock(&nn->boot_lock, &seq);
353 /*
354 * This is opaque to client, so no need to byte-swap. Use
355 * __force to keep sparse happy. y2038 time_t overflow is
356 * irrelevant in this usage
357 */
358 verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec;
359 verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec;
360 } while (need_seqretry(&nn->boot_lock, seq));
361 done_seqretry(&nn->boot_lock, seq);
362}
363
364void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn)
365{
366 ktime_get_real_ts64(&nn->nfssvc_boot);
367}
368
369void nfsd_reset_boot_verifier(struct nfsd_net *nn)
370{
371 write_seqlock(&nn->boot_lock);
372 nfsd_reset_boot_verifier_locked(nn);
373 write_sequnlock(&nn->boot_lock);
374}
375
347static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred) 376static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred)
348{ 377{
349 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 378 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -596,7 +625,7 @@ int nfsd_create_serv(struct net *net)
596#endif 625#endif
597 } 626 }
598 atomic_inc(&nn->ntf_refcnt); 627 atomic_inc(&nn->ntf_refcnt);
599 ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */ 628 nfsd_reset_boot_verifier(nn);
600 return 0; 629 return 0;
601} 630}
602 631