diff options
author | Trond Myklebust <trondmy@gmail.com> | 2019-09-02 13:02:56 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2019-09-10 09:23:41 -0400 |
commit | 27c438f53e79b81dc8805a81f6cd74824ba57290 (patch) | |
tree | 58165481c4ed3f51742526143c7e4db3f273338b | |
parent | 5e113224c17e2fb156b785ddbbc48a0209fddb0c (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.h | 4 | ||||
-rw-r--r-- | fs/nfsd/nfs3xdr.c | 13 | ||||
-rw-r--r-- | fs/nfsd/nfs4proc.c | 14 | ||||
-rw-r--r-- | fs/nfsd/nfsctl.c | 1 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 31 |
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 { | |||
179 | extern void nfsd_netns_free_versions(struct nfsd_net *nn); | 180 | extern void nfsd_netns_free_versions(struct nfsd_net *nn); |
180 | 181 | ||
181 | extern unsigned int nfsd_net_id; | 182 | extern unsigned int nfsd_net_id; |
183 | |||
184 | void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn); | ||
185 | void 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 | ||
569 | static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) | 569 | static 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 | ||
584 | static __be32 | 578 | static __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 | ||
347 | void 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 | |||
364 | void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) | ||
365 | { | ||
366 | ktime_get_real_ts64(&nn->nfssvc_boot); | ||
367 | } | ||
368 | |||
369 | void 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 | |||
347 | static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred) | 376 | static 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 | ||