git: ded5f2954e1a - main - nfsd: Fix handling of the error case for nfsvno_open

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Wed, 08 Feb 2023 21:09:46 UTC
The branch main has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=ded5f2954e1a1bb7748646888938af767ee6257a

commit ded5f2954e1a1bb7748646888938af767ee6257a
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2023-02-08 21:06:07 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2023-02-08 21:08:51 +0000

    nfsd: Fix handling of the error case for nfsvno_open
    
    Using done_namei instead of ni_startdir did not
    fix the crashes reported in the PR. Upon looking
    more closely at the code, the only case where the
    code near the end of nfsvno_open() needs to be
    executed is when nfsvno_namei() has succeeded,
    but a subsequent error was detected.
    
    This patch uses done_namei to indicate this case.
    
    Also, nfsvno_relpathbuf() should only be called for
    this case and not whenever nfsvno_open() is called
    with nd_repstat != 0. A bug was introduced here when
    the HASBUF flag was deleted.
    
    Reviewed by:    mjg
    PR:     268971
    Tested by:      ish@amail.plala.or.jp
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D38430
---
 sys/fs/nfsserver/nfs_nfsdport.c | 22 +++++++++++++---------
 sys/fs/nfsserver/nfs_nfsdserv.c | 10 +++++-----
 2 files changed, 18 insertions(+), 14 deletions(-)

diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index d02653823857..7305ae6a84fe 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -1916,16 +1916,20 @@ nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp,
 				    stateidp, stp, vp, nd, p, nd->nd_repstat);
 			}
 		}
-	} else {
+	} else if (done_namei) {
+		/*
+		 * done_namei is set when nfsvno_namei() has completed
+		 * successfully, but a subsequent error was set in
+		 * nd_repstat.  As such, cleanup of the nfsvno_namei()
+		 * results is required.
+		 */
 		nfsvno_relpathbuf(ndp);
-		if (done_namei && create == NFSV4OPEN_CREATE) {
-			if (ndp->ni_dvp == ndp->ni_vp)
-				vrele(ndp->ni_dvp);
-			else
-				vput(ndp->ni_dvp);
-			if (ndp->ni_vp)
-				vput(ndp->ni_vp);
-		}
+		if (ndp->ni_dvp == ndp->ni_vp)
+			vrele(ndp->ni_dvp);
+		else
+			vput(ndp->ni_dvp);
+		if (ndp->ni_vp)
+			vput(ndp->ni_vp);
 	}
 	*vpp = vp;
 
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 0433e9cda656..569ddc9141bb 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -3043,7 +3043,6 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 		if (!nd->nd_repstat) {
 			nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
 			    &dirp);
-			done_namei = true;
 		} else {
 			vrele(dp);
 			nfsvno_relpathbuf(&named);
@@ -3051,7 +3050,7 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 		if (create == NFSV4OPEN_CREATE) {
 		    switch (how) {
 		    case NFSCREATE_UNCHECKED:
-			if (done_namei && named.ni_vp != NULL) {
+			if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
 				/*
 				 * Clear the setable attribute bits, except
 				 * for Size, if it is being truncated.
@@ -3063,13 +3062,14 @@ nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 			}
 			break;
 		    case NFSCREATE_GUARDED:
-			if (done_namei && named.ni_vp != NULL &&
-			    nd->nd_repstat == 0)
+			if (nd->nd_repstat == 0 && named.ni_vp != NULL) {
 				nd->nd_repstat = EEXIST;
+				done_namei = true;
+			}
 			break;
 		    case NFSCREATE_EXCLUSIVE:
 			exclusive_flag = 1;
-			if (done_namei && named.ni_vp == NULL)
+			if (nd->nd_repstat == 0 && named.ni_vp == NULL)
 				nva.na_mode = 0;
 			break;
 		    case NFSCREATE_EXCLUSIVE41: