nfsd: fix NFS server for ERELOOKUP
r367672 modified UFS such that certain VOPs, such as VOP_CREATE() will intermittently return ERELOOKUP. When this happens, the entire system call, or NFS operation in the case of the NFS server, must be redone. This patch adds that support to the NFS server by rolling back the state of the NFS request arguments and NFS reply arguments mbuf lists to the condition they were in before the operation and then redoing the operation. Tested by: pho Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D27875
This commit is contained in:
parent
fb6bc290fb
commit
774a36851e
@ -753,6 +753,8 @@ int nfsvno_rmxattr(struct nfsrv_descript *, struct vnode *, char *,
|
||||
struct ucred *, struct thread *);
|
||||
int nfsvno_listxattr(struct vnode *, uint64_t, struct ucred *, struct thread *,
|
||||
u_char **, uint32_t *, bool *);
|
||||
void nfsm_trimtrailing(struct nfsrv_descript *, struct mbuf *, char *, int,
|
||||
int);
|
||||
|
||||
/* nfs_commonkrpc.c */
|
||||
int newnfs_nmcancelreqs(struct nfsmount *);
|
||||
|
@ -146,8 +146,6 @@ static int nfsrv_dsremove(struct vnode *, char *, struct ucred *, NFSPROC_T *);
|
||||
static int nfsrv_dssetacl(struct vnode *, struct acl *, struct ucred *,
|
||||
NFSPROC_T *);
|
||||
static int nfsrv_pnfsstatfs(struct statfs *, struct mount *);
|
||||
static void nfsm_trimtrailing(struct nfsrv_descript *, struct mbuf *,
|
||||
char *, int, int);
|
||||
|
||||
int nfs_pnfsio(task_fn_t *, void *);
|
||||
|
||||
@ -6564,7 +6562,7 @@ nfsvno_listxattr(struct vnode *vp, uint64_t cookie, struct ucred *cred,
|
||||
/*
|
||||
* Trim trailing data off the mbuf list being built.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
nfsm_trimtrailing(struct nfsrv_descript *nd, struct mbuf *mb, char *bpos,
|
||||
int bextpg, int bextpgsiz)
|
||||
{
|
||||
|
@ -534,9 +534,21 @@ nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
|
||||
{
|
||||
int error = 0, lktype;
|
||||
vnode_t vp;
|
||||
mount_t mp = NULL;
|
||||
mount_t mp;
|
||||
struct nfsrvfh fh;
|
||||
struct nfsexstuff nes;
|
||||
struct mbuf *md;
|
||||
char *dpos;
|
||||
|
||||
/*
|
||||
* Save the current position in the request mbuf list so
|
||||
* that a rollback to this location can be done upon an
|
||||
* ERELOOKUP error return from an RPC function.
|
||||
*/
|
||||
md = nd->nd_md;
|
||||
dpos = nd->nd_dpos;
|
||||
tryagain:
|
||||
mp = NULL;
|
||||
|
||||
/*
|
||||
* Get a locked vnode for the first file handle
|
||||
@ -634,6 +646,21 @@ nfsrvd_dorpc(struct nfsrv_descript *nd, int isdgram, u_char *tag, int taglen,
|
||||
if (mp != NULL && nfsrv_writerpc[nd->nd_procnum] != 0)
|
||||
vn_finished_write(mp);
|
||||
|
||||
if (error == 0 && nd->nd_repstat == ERELOOKUP) {
|
||||
/*
|
||||
* Roll back to the beginning of the RPC request
|
||||
* arguments.
|
||||
*/
|
||||
nd->nd_md = md;
|
||||
nd->nd_dpos = dpos;
|
||||
|
||||
/* Free the junk RPC reply and redo the RPC. */
|
||||
m_freem(nd->nd_mreq);
|
||||
nd->nd_mreq = nd->nd_mb = NULL;
|
||||
nd->nd_repstat = 0;
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
nfsrvd_statend(nfsv3to4op[nd->nd_procnum], /*bytes*/ 0,
|
||||
/*now*/ NULL, /*then*/ &start_time);
|
||||
}
|
||||
@ -691,6 +718,9 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
static u_int64_t compref = 0;
|
||||
struct bintime start_time;
|
||||
struct thread *p;
|
||||
struct mbuf *mb, *md;
|
||||
char *bpos, *dpos;
|
||||
int bextpg, bextpgsiz;
|
||||
|
||||
p = curthread;
|
||||
|
||||
@ -1045,6 +1075,20 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the current positions in the mbuf lists so
|
||||
* that a rollback to this location can be done upon a
|
||||
* redo due to a ERELOOKUP return for a operation.
|
||||
*/
|
||||
mb = nd->nd_mb;
|
||||
bpos = nd->nd_bpos;
|
||||
bextpg = nd->nd_bextpg;
|
||||
bextpgsiz = nd->nd_bextpgsiz;
|
||||
md = nd->nd_md;
|
||||
dpos = nd->nd_dpos;
|
||||
tryagain:
|
||||
|
||||
if (nfsv4_opflag[op].retfh == 1) {
|
||||
if (!vp) {
|
||||
nd->nd_repstat = NFSERR_NOFILEHANDLE;
|
||||
@ -1154,6 +1198,23 @@ nfsrvd_compound(struct nfsrv_descript *nd, int isdgram, u_char *tag,
|
||||
error = 0;
|
||||
}
|
||||
|
||||
if (nd->nd_repstat == ERELOOKUP) {
|
||||
/*
|
||||
* Roll back to the beginning of the operation
|
||||
* arguments.
|
||||
*/
|
||||
nd->nd_md = md;
|
||||
nd->nd_dpos = dpos;
|
||||
|
||||
/*
|
||||
* Trim off the bogus reply for this operation
|
||||
* and redo the operation.
|
||||
*/
|
||||
nfsm_trimtrailing(nd, mb, bpos, bextpg, bextpgsiz);
|
||||
nd->nd_repstat = 0;
|
||||
goto tryagain;
|
||||
}
|
||||
|
||||
if (statsinprog != 0) {
|
||||
nfsrvd_statend(op, /*bytes*/ 0, /*now*/ NULL,
|
||||
/*then*/ &start_time);
|
||||
|
Loading…
Reference in New Issue
Block a user