Shut down the TCP connection to a DS in the pNFS client when Renew fails.

When a NFSv4.1 client mount using pNFS detects a failure trying to do a
Renew (actually just a Sequence operation), the code would simply try
again and again and again every 30sec.
This would tie up the "nfscl" thread, which should also be doing other
things like Renews on other DSs and the MDS.
This patch adds code which closes down the TCP connection and marks it
defunct when Renew detects an failure to communicate with the DS, so
further Renews will not be attempted until a new working TCP connection to
the DS is established.
It also makes the call to nfscl_cancelreqs() unconditional, since
nfscl_cancelreqs() checks the NFSCLDS_SAMECONN flag and does so while holding
the lock.
This fix only applies to the NFSv4.1 client whne using pNFS and without it
the only effect would have been an "nfscl" thread busy doing Renew attempts
on an unresponsive DS.

MFC after:	2 weeks
This commit is contained in:
Rick Macklem 2018-07-15 18:54:44 +00:00
parent ba06b626d1
commit 5da3882447
3 changed files with 10 additions and 6 deletions

View File

@ -603,6 +603,7 @@ struct nfscllayout *nfscl_getlayout(struct nfsclclient *, uint8_t *, int,
uint64_t, struct nfsclflayout **, int *);
void nfscl_dserr(uint32_t, uint32_t, struct nfscldevinfo *,
struct nfscllayout *, struct nfsclds *);
void nfscl_cancelreqs(struct nfsclds *);
void nfscl_rellayout(struct nfscllayout *, int);
struct nfscldevinfo *nfscl_getdevinfo(struct nfsclclient *, uint8_t *,
struct nfscldevinfo *);

View File

@ -4408,9 +4408,12 @@ nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
if (dsp == NULL)
error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
else
else {
error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
if (error == ENXIO)
nfscl_cancelreqs(dsp);
}
if (error)
return (error);
error = nd->nd_repstat;

View File

@ -125,7 +125,6 @@ static struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *,
static void nfscl_retoncloselayout(vnode_t, struct nfsclclient *, uint8_t *,
int, struct nfsclrecalllayout **);
static void nfscl_reldevinfo_locked(struct nfscldevinfo *);
static void nfscl_cancelreqs(struct nfsclds *);
static struct nfscllayout *nfscl_findlayout(struct nfsclclient *, u_int8_t *,
int);
static struct nfscldevinfo *nfscl_finddevinfo(struct nfsclclient *, uint8_t *);
@ -5001,16 +5000,17 @@ nfscl_dserr(uint32_t op, uint32_t stat, struct nfscldevinfo *dp,
free(recallp, M_NFSLAYRECALL);
}
/* If the connection isn't used for other DSs, we can shut it down. */
if ((dsp->nfsclds_flags & NFSCLDS_SAMECONN) == 0)
nfscl_cancelreqs(dsp);
/* And shut the TCP connection down. */
nfscl_cancelreqs(dsp);
}
/*
* Cancel all RPCs for this "dsp" by closing the connection.
* Also, mark the session as defunct.
* If NFSCLDS_SAMECONN is set, the connection is shared with other DSs and
* cannot be shut down.
*/
static void
APPLESTATIC void
nfscl_cancelreqs(struct nfsclds *dsp)
{
struct __rpc_client *cl;