forked from Minki/linux
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 */
|
/* Time of server startup */
|
||||||
struct timespec64 nfssvc_boot;
|
struct timespec64 nfssvc_boot;
|
||||||
|
seqlock_t boot_lock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Max number of connections this nfsd container will allow. Defaults
|
* 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 void nfsd_netns_free_versions(struct nfsd_net *nn);
|
||||||
|
|
||||||
extern unsigned int nfsd_net_id;
|
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__ */
|
#endif /* __NFSD_NETNS_H__ */
|
||||||
|
@ -27,6 +27,7 @@ static u32 nfs3_ftypes[] = {
|
|||||||
NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
|
NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XDR functions for basic NFS types
|
* 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 nfsd3_writeres *resp = rqstp->rq_resp;
|
||||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||||
|
__be32 verf[2];
|
||||||
|
|
||||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||||
if (resp->status == 0) {
|
if (resp->status == 0) {
|
||||||
*p++ = htonl(resp->count);
|
*p++ = htonl(resp->count);
|
||||||
*p++ = htonl(resp->committed);
|
*p++ = htonl(resp->committed);
|
||||||
/* unique identifier, y2038 overflow can be ignored */
|
/* unique identifier, y2038 overflow can be ignored */
|
||||||
*p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
|
nfsd_copy_boot_verifier(verf, nn);
|
||||||
*p++ = htonl(nn->nfssvc_boot.tv_nsec);
|
*p++ = verf[0];
|
||||||
|
*p++ = verf[1];
|
||||||
}
|
}
|
||||||
return xdr_ressize_check(rqstp, p);
|
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 nfsd3_commitres *resp = rqstp->rq_resp;
|
||||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||||
|
__be32 verf[2];
|
||||||
|
|
||||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||||
/* Write verifier */
|
/* Write verifier */
|
||||||
if (resp->status == 0) {
|
if (resp->status == 0) {
|
||||||
/* unique identifier, y2038 overflow can be ignored */
|
/* unique identifier, y2038 overflow can be ignored */
|
||||||
*p++ = htonl((u32)nn->nfssvc_boot.tv_sec);
|
nfsd_copy_boot_verifier(verf, nn);
|
||||||
*p++ = htonl(nn->nfssvc_boot.tv_nsec);
|
*p++ = verf[0];
|
||||||
|
*p++ = verf[1];
|
||||||
}
|
}
|
||||||
return xdr_ressize_check(rqstp, p);
|
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)
|
static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
|
||||||
{
|
{
|
||||||
__be32 verf[2];
|
__be32 *verf = (__be32 *)verifier->data;
|
||||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
|
||||||
|
|
||||||
/*
|
BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data));
|
||||||
* This is opaque to client, so no need to byte-swap. Use
|
|
||||||
* __force to keep sparse happy. y2038 time_t overflow is
|
nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id));
|
||||||
* 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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static __be32
|
static __be32
|
||||||
|
@ -1477,6 +1477,7 @@ static __net_init int nfsd_init_net(struct net *net)
|
|||||||
|
|
||||||
atomic_set(&nn->ntf_refcnt, 0);
|
atomic_set(&nn->ntf_refcnt, 0);
|
||||||
init_waitqueue_head(&nn->ntf_wq);
|
init_waitqueue_head(&nn->ntf_wq);
|
||||||
|
seqlock_init(&nn->boot_lock);
|
||||||
|
|
||||||
mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL);
|
mnt = vfs_kern_mount(&nfsd_fs_type, SB_KERNMOUNT, "nfsd", NULL);
|
||||||
if (IS_ERR(mnt)) {
|
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);
|
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)
|
static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred)
|
||||||
{
|
{
|
||||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||||
@ -596,7 +625,7 @@ int nfsd_create_serv(struct net *net)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
atomic_inc(&nn->ntf_refcnt);
|
atomic_inc(&nn->ntf_refcnt);
|
||||||
ktime_get_real_ts64(&nn->nfssvc_boot); /* record boot time */
|
nfsd_reset_boot_verifier(nn);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user