]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfs_vfsutils.c
xnu-201.19.3.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_vfsutils.c
index 29dab58567de51a129b8481eba09fead409eaffe..e6cfc9684cb4db7c6bf246e13f1e000124cc363d 100644 (file)
@@ -812,28 +812,6 @@ short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, str
        dev_t                           dev;
        short                           retval;
 
-#if HFS_DIAGNOSTIC
-       DBG_ASSERT(vcb != NULL);
-       DBG_ASSERT(catInfo != NULL);
-       DBG_ASSERT(vpp != NULL);
-       DBG_ASSERT((forkType == kDirectory) || (forkType == kDataFork) || (forkType == kRsrcFork));
-       if (catInfo->nodeData.cnd_type == kCatalogFolderNode) {
-                       DBG_ASSERT(forkType == kDirectory);
-       } else {
-                       DBG_ASSERT(forkType != kDirectory);
-       }
-#endif
-
-    if ( ! ((forkType == kDirectory) || (forkType == kDataFork) || (forkType == kRsrcFork)))
-        panic("Bad fork type");
-       if (catInfo->nodeData.cnd_type == kCatalogFolderNode) {
-                       if (forkType != kDirectory)
-                           panic("non directory type");
-       } else {
-                       if (forkType != kDataFork && forkType != kRsrcFork)
-                           panic("non fork type");
-       }
-        
        hfsmp   = VCBTOHFS(vcb);
        mp              = HFSTOVFS(hfsmp);
        dev             = hfsmp->hfs_raw_dev;
@@ -863,47 +841,58 @@ short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, str
                }
        }
 
-       /* Must malloc() here, since getnewvnode() can sleep */
        MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
        bzero((caddr_t)hp, sizeof(struct hfsnode));
-       
-       /*
-        * Set that this node is in the process of being allocated
-        * Set it as soon as possible, so context switches well always hit upon it.
-        * if this is set then wakeup() MUST be called on hp after the flag is cleared
-        * DO NOT exit without clearing and waking up !!!!
-        */
-       hp->h_nodeflags |= IN_ALLOCATING;                               /* Mark this as being allocating */
+       hp->h_nodeflags |= IN_ALLOCATING;
        lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
-
-
-       /* getnewvnode() does a VREF() on the vnode */
-       /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
-       if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) {
-               wakeup(hp);                             /* Shouldnt happen, but just to make sure */
-               FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
-               *vpp = NULL;
-               return (retval);
-       };
+       H_FORKTYPE(hp) = forkType;
+       rl_init(&hp->h_invalidranges);
 
        /*
-        * Set the essentials before locking it down
+        * There were several blocking points since we first
+        * checked the hash. Now that we're through blocking,
+        * check the hash again in case we're racing for the
+        * same hnode.
         */
-       hp->h_vp = vp;                                                                  /* Make HFSTOV work */
-       vp->v_data = hp;                                                                /* Make VTOH work */
-       H_FORKTYPE(hp) = forkType;
-       rl_init(&hp->h_invalidranges);
-       fm = NULL;
-       
+       vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, forkType);
+       if (vp != NULL) {
+               /* We lost the race, use the winner's vnode */
+               FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
+               *vpp = vp;
+               UBCINFOCHECK("hfs_vcreate", vp);
+               return (0);
+       }
+
        /*
-        * Lock the hfsnode and insert the hfsnode into the hash queue, also if meta exists
+        * Insert the hfsnode into the hash queue, also if meta exists
         * add to sibling list and return the meta address
         */
+       fm = NULL;
        if  (SIBLING_FORKTYPE(forkType))
                hfs_vhashins_sibling(dev, catInfo->nodeData.cnd_nodeID, hp, &fm);
        else
                hfs_vhashins(dev, catInfo->nodeData.cnd_nodeID, hp);
 
+       /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
+       if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) {
+               hfs_vhashrem(hp);
+               if (hp->h_nodeflags & IN_WANT) {
+                       hp->h_nodeflags &= ~IN_WANT;
+                       wakeup(hp);
+               }
+               FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
+               *vpp = NULL;
+               return (retval);
+       }
+       hp->h_vp = vp;
+       vp->v_data = hp;
+
+       hp->h_nodeflags &= ~IN_ALLOCATING;
+       if (hp->h_nodeflags & IN_WANT) {
+               hp->h_nodeflags &= ~IN_WANT;
+               wakeup((caddr_t)hp);
+       }
+
        /*
         * If needed allocate and init the object meta data:
         */
@@ -937,7 +926,6 @@ short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, str
        };
        fm->h_usecount++;
 
-
        /*
         * Init the File Control Block.
         */
@@ -957,48 +945,24 @@ short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, str
                ubc_info_init(vp);
        }
 
-    /*
+       /*
         * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
         * Note that the underlying vnode may have changed.
         */
        if ((retval = hfs_vinit(mp, hfs_specop_p, hfs_fifoop_p, &vp))) {
-               wakeup((caddr_t)hp);
                vput(vp);
                *vpp = NULL;
                return (retval);
        }
 
-    /*
-     * Finish inode initialization now that aliasing has been resolved.
-     */
-    hp->h_meta->h_devvp = hfsmp->hfs_devvp;
-    VREF(hp->h_meta->h_devvp);
+       /*
+        * Finish inode initialization now that aliasing has been resolved.
+        */
+       hp->h_meta->h_devvp = hfsmp->hfs_devvp;
+       VREF(hp->h_meta->h_devvp);
     
-#if HFS_DIAGNOSTIC
-       hp->h_valid = HFS_VNODE_MAGIC;
-#endif
-       hp->h_nodeflags &= ~IN_ALLOCATING;                              /* vnode is completely initialized */
-
-       /* Wake up anybody waiting for us to finish..see hfs_vhash.c */
-       wakeup((caddr_t)hp);
-
-#if HFS_DIAGNOSTIC
-
-       /* Lets do some testing here */
-       DBG_ASSERT(hp->h_meta);
-       DBG_ASSERT(VTOH(vp)==hp);
-       DBG_ASSERT(HTOV(hp)==vp);
-       DBG_ASSERT(hp->h_meta->h_usecount>=1 && hp->h_meta->h_usecount<=2);
-       if (catInfo->nodeData.cnd_type == kCatalogFolderNode) {
-               DBG_ASSERT(vp->v_type == VDIR);
-               DBG_ASSERT(H_FORKTYPE(VTOH(vp)) == kDirectory);
-       }
-#endif // HFS_DIAGNOSTIC
-
-
        *vpp = vp;
        return 0;
-
 }
 
 void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm)