Author: trasz
Date: Sat Mar 12 07:54:42 2016
New Revision: 296715
URL: https://svnweb.freebsd.org/changeset/base/296715

Log:
  Fix autofs triggering problem.  Assume you have an NFS server,
  192.168.1.1, with share "share". This commit fixes a problem
  where "mkdir /net/192.168.1.1/share/meh" would return spurious
  error instead of creating the directory if the target filesystem
  wasn't mounted yet; subsequent attempts would work correctly.
  
  The failure scenario is kind of complicated to explain, but it all
  boils down to calling VOP_MKDIR() for the target filesystem (NFS)
  with wrong dvp - the autofs vnode instead of the filesystem root
  mounted over it.
  
  Reviewed by:  kib@
  MFC after:    1 month
  Sponsored by: The FreeBSD Foundation
  Differential Revision:        https://reviews.freebsd.org/D5442

Modified:
  head/sys/fs/autofs/autofs_vnops.c
  head/sys/kern/vfs_lookup.c
  head/sys/sys/errno.h

Modified: head/sys/fs/autofs/autofs_vnops.c
==============================================================================
--- head/sys/fs/autofs/autofs_vnops.c   Sat Mar 12 07:13:20 2016        
(r296714)
+++ head/sys/fs/autofs/autofs_vnops.c   Sat Mar 12 07:54:42 2016        
(r296715)
@@ -214,7 +214,7 @@ autofs_lookup(struct vop_lookup_args *ap
        struct autofs_mount *amp;
        struct autofs_node *anp, *child;
        struct componentname *cnp;
-       int error, lock_flags;
+       int error;
 
        dvp = ap->a_dvp;
        vpp = ap->a_vpp;
@@ -257,23 +257,13 @@ autofs_lookup(struct vop_lookup_args *ap
                        return (error);
 
                if (newvp != NULL) {
-                       error = VOP_LOOKUP(newvp, ap->a_vpp, ap->a_cnp);
-
                        /*
-                        * Instead of figuring out whether our vnode should
-                        * be locked or not given the error and cnp flags,
-                        * just "copy" the lock status from vnode returned
-                        * by mounted filesystem's VOP_LOOKUP().  Get rid
-                        * of that new vnode afterwards.
+                        * The target filesystem got automounted.
+                        * Let the lookup(9) go around with the same
+                        * path component.
                         */
-                       lock_flags = VOP_ISLOCKED(newvp);
-                       if (lock_flags == 0) {
-                               VOP_UNLOCK(dvp, 0);
-                               vrele(newvp);
-                       } else {
-                               vput(newvp);
-                       }
-                       return (error);
+                       vput(newvp);
+                       return (ERELOOKUP);
                }
        }
 

Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c  Sat Mar 12 07:13:20 2016        (r296714)
+++ head/sys/kern/vfs_lookup.c  Sat Mar 12 07:54:42 2016        (r296715)
@@ -495,6 +495,7 @@ lookup(struct nameidata *ndp)
        int rdonly;                     /* lookup read-only flag bit */
        int error = 0;
        int dpunlocked = 0;             /* dp has already been unlocked */
+       int relookup = 0;               /* do not consume the path component */
        struct componentname *cnp = &ndp->ni_cnd;
        int lkflags_save;
        int ni_dvp_unlocked;
@@ -745,6 +746,14 @@ unionlookup:
                        goto unionlookup;
                }
 
+               if (error == ERELOOKUP) {
+                       vref(dp);
+                       ndp->ni_vp = dp;
+                       error = 0;
+                       relookup = 1;
+                       goto good;
+               }
+
                if (error != EJUSTRETURN)
                        goto bad;
                /*
@@ -777,6 +786,8 @@ unionlookup:
                goto success;
        } else
                cnp->cn_lkflags = lkflags_save;
+
+good:
 #ifdef NAMEI_DIAGNOSTIC
        printf("found\n");
 #endif
@@ -856,6 +867,14 @@ nextname:
         */
        KASSERT((cnp->cn_flags & ISLASTCN) || *ndp->ni_next == '/',
            ("lookup: invalid path state."));
+       if (relookup) {
+               relookup = 0;
+               if (ndp->ni_dvp != dp)
+                       vput(ndp->ni_dvp);
+               else
+                       vrele(ndp->ni_dvp);
+               goto dirloop;
+       }
        if (*ndp->ni_next == '/') {
                cnp->cn_nameptr = ndp->ni_next;
                while (*cnp->cn_nameptr == '/') {

Modified: head/sys/sys/errno.h
==============================================================================
--- head/sys/sys/errno.h        Sat Mar 12 07:13:20 2016        (r296714)
+++ head/sys/sys/errno.h        Sat Mar 12 07:54:42 2016        (r296715)
@@ -190,6 +190,7 @@ __END_DECLS
 #define        EJUSTRETURN     (-2)            /* don't modify regs, just 
return */
 #define        ENOIOCTL        (-3)            /* ioctl not handled by this 
layer */
 #define        EDIRIOCTL       (-4)            /* do direct ioctl in GEOM */
+#define        ERELOOKUP       (-5)            /* retry the directory lookup */
 #endif
 
 #endif
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to