Date: Fri, 1 Jan 2021 22:00:35 GMT From: Rick Macklem <rmacklem@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: 774a36851e0e - main - nfsd: fix NFS server for ERELOOKUP Message-ID: <202101012200.101M0ZEE059055@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=774a36851e0e562a6428e5ac45fbfb2b23f3f58c commit 774a36851e0e562a6428e5ac45fbfb2b23f3f58c Author: Rick Macklem <rmacklem@FreeBSD.org> AuthorDate: 2021-01-01 21:55:51 +0000 Commit: Rick Macklem <rmacklem@FreeBSD.org> CommitDate: 2021-01-01 21:55:51 +0000 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 --- sys/fs/nfs/nfs_var.h | 2 ++ sys/fs/nfsserver/nfs_nfsdport.c | 4 +-- sys/fs/nfsserver/nfs_nfsdsocket.c | 63 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index a3c53e80ace3..0a1fe3ce053d 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -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 *); diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index e867ecc350b4..e9a9443dc08c 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -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 @@ out: /* * 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) { diff --git a/sys/fs/nfsserver/nfs_nfsdsocket.c b/sys/fs/nfsserver/nfs_nfsdsocket.c index a9fdc7fa8be3..1a54914fc9dc 100644 --- a/sys/fs/nfsserver/nfs_nfsdsocket.c +++ b/sys/fs/nfsserver/nfs_nfsdsocket.c @@ -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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202101012200.101M0ZEE059055>