mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +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
@ -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…
Reference in New Issue
Block a user