The branch main has been updated by rmacklem:

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

commit ded5f2954e1a1bb7748646888938af767ee6257a
Author:     Rick Macklem <rmack...@freebsd.org>
AuthorDate: 2023-02-08 21:06:07 +0000
Commit:     Rick Macklem <rmack...@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:      i...@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:

Reply via email to