Skip to content

Commit

Permalink
nfsd: Support the server resetting the boot verifier
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Trond Myklebust authored and J. Bruce Fields committed Sep 10, 2019
1 parent 5e11322 commit 27c438f
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 15 deletions.
4 changes: 4 additions & 0 deletions fs/nfsd/netns.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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__ */
13 changes: 9 additions & 4 deletions fs/nfsd/nfs3xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ static u32 nfs3_ftypes[] = {
NF3SOCK, NF3BAD, NF3LNK, NF3BAD,
};


/*
* XDR functions for basic NFS types
*/
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
14 changes: 4 additions & 10 deletions fs/nfsd/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/nfsctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
31 changes: 30 additions & 1 deletion fs/nfsd/nfssvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 27c438f

Please sign in to comment.