From owner-dev-commits-src-main@freebsd.org Fri Jan 1 22:00:36 2021 Return-Path: Delivered-To: dev-commits-src-main@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 156E04D5347; Fri, 1 Jan 2021 22:00:36 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4D6zVD08ggz3tyg; Fri, 1 Jan 2021 22:00:36 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id EC785197E; Fri, 1 Jan 2021 22:00:35 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 101M0Z4i059056; Fri, 1 Jan 2021 22:00:35 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 101M0ZEE059055; Fri, 1 Jan 2021 22:00:35 GMT (envelope-from git) Date: Fri, 1 Jan 2021 22:00:35 GMT Message-Id: <202101012200.101M0ZEE059055@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: 774a36851e0e - main - nfsd: fix NFS server for ERELOOKUP MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 774a36851e0e562a6428e5ac45fbfb2b23f3f58c Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-main@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for the main branch of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 01 Jan 2021 22:00:36 -0000 The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=774a36851e0e562a6428e5ac45fbfb2b23f3f58c commit 774a36851e0e562a6428e5ac45fbfb2b23f3f58c Author: Rick Macklem AuthorDate: 2021-01-01 21:55:51 +0000 Commit: Rick Macklem 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);