Author: mjg
Date: Fri Oct  9 19:10:00 2020
New Revision: 366582
URL: https://svnweb.freebsd.org/changeset/base/366582

Log:
  cache: fix vexec panic when racing against vgone
  
  Use of dead_vnodeops would result in a panic instead of returning the intended
  EOPNOTSUPP error.
  
  While here make sure to abort, not just try to return a partial result.
  The former allows the regular lookup to restart from scratch, while the latter
  makes it stuck with an unusable vnode.
  
  Reported by:  kevans

Modified:
  head/sys/fs/deadfs/dead_vnops.c
  head/sys/kern/vfs_cache.c

Modified: head/sys/fs/deadfs/dead_vnops.c
==============================================================================
--- head/sys/fs/deadfs/dead_vnops.c     Fri Oct  9 18:30:49 2020        
(r366581)
+++ head/sys/fs/deadfs/dead_vnops.c     Fri Oct  9 19:10:00 2020        
(r366582)
@@ -79,6 +79,7 @@ struct vop_vector dead_vnodeops = {
        .vop_vptocnp =          VOP_EBADF,
        .vop_unset_text =       dead_unset_text,
        .vop_write =            dead_write,
+       .vop_fplookup_vexec =   VOP_EOPNOTSUPP,
 };
 VFS_VOP_VECTOR_REGISTER(dead_vnodeops);
 

Modified: head/sys/kern/vfs_cache.c
==============================================================================
--- head/sys/kern/vfs_cache.c   Fri Oct  9 18:30:49 2020        (r366581)
+++ head/sys/kern/vfs_cache.c   Fri Oct  9 19:10:00 2020        (r366582)
@@ -4040,32 +4040,46 @@ cache_fplookup_parse_advance(struct cache_fpl *fpl)
        }
 }
 
+/*
+ * See the API contract for VOP_FPLOOKUP_VEXEC.
+ */
 static int __noinline
 cache_fplookup_failed_vexec(struct cache_fpl *fpl, int error)
 {
+       struct vnode *dvp;
+       seqc_t dvp_seqc;
 
+       dvp = fpl->dvp;
+       dvp_seqc = fpl->dvp_seqc;
+
        /*
         * Hack: they may be looking up foo/bar, where foo is a
         * regular file. In such a case we need to turn ENOTDIR,
         * but we may happen to get here with a different error.
         */
-       if (fpl->dvp->v_type != VDIR) {
+       if (dvp->v_type != VDIR) {
+               /*
+                * The check here is predominantly to catch
+                * EOPNOTSUPP from dead_vnodeops. If the vnode
+                * gets doomed past this point it is going to
+                * fail seqc verification.
+                */
+               if (VN_IS_DOOMED(dvp)) {
+                       return (cache_fpl_aborted(fpl));
+               }
                error = ENOTDIR;
        }
 
        switch (error) {
        case EAGAIN:
-               /*
-                * Can happen when racing against vgone.
-                * */
-       case EOPNOTSUPP:
-               cache_fpl_partial(fpl);
+               if (!vn_seqc_consistent(dvp, dvp_seqc)) {
+                       error = cache_fpl_aborted(fpl);
+               } else {
+                       cache_fpl_partial(fpl);
+               }
                break;
        default:
-               /*
-                * See the API contract for VOP_FPLOOKUP_VEXEC.
-                */
-               if (!vn_seqc_consistent(fpl->dvp, fpl->dvp_seqc)) {
+               if (!vn_seqc_consistent(dvp, dvp_seqc)) {
                        error = cache_fpl_aborted(fpl);
                } else {
                        cache_fpl_smr_exit(fpl);
_______________________________________________
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