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;
}
}
- /* 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:
*/
};
fm->h_usecount++;
-
/*
* Init the File Control Block.
*/
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)