+ retval = hfs_getnewvnode(hfsmp, dvp, cnp, &desc, 0, &attr, &fork, &tvp, &newvnode_flags);
+
+ if (retval) {
+ /*
+ * If this was a create/rename operation lookup, then by this point
+ * we expected to see the item returned from hfs_getnewvnode above.
+ * In the create case, it would probably eventually bubble out an EEXIST
+ * because the item existed when we were trying to create it. In the
+ * rename case, it would let us know that we need to go ahead and
+ * delete it as part of the rename. However, if we hit the condition below
+ * then it means that we found the element during cat_lookup above, but
+ * it is now no longer there. We simply behave as though we never found
+ * the element at all and return EJUSTRETURN.
+ */
+ if ((retval == ENOENT) &&
+ ((cnp->cn_nameiop == CREATE) || (cnp->cn_nameiop == RENAME)) &&
+ (flags & ISLASTCN)) {
+ retval = EJUSTRETURN;
+ }
+
+ /*
+ * If this was a straight lookup operation, we may need to redrive the entire
+ * lookup starting from cat_lookup if the element was deleted as the result of
+ * a rename operation. Since rename is supposed to guarantee atomicity, then
+ * lookups cannot fail because the underlying element is deleted as a result of
+ * the rename call -- either they returned the looked up element prior to rename
+ * or return the newer element. If we are in this region, then all we can do is add
+ * workarounds to guarantee the latter case. The element has already been deleted, so
+ * we just re-try the lookup to ensure the caller gets the most recent element.
+ */
+ if ((retval == ENOENT) && (cnp->cn_nameiop == LOOKUP) &&
+ (newvnode_flags & (GNV_CHASH_RENAMED | GNV_CAT_DELETED))) {
+ if (dcp) {
+ hfs_unlock (dcp);
+ }
+ /* get rid of any name buffers that may have lingered from the cat_lookup call */
+ cat_releasedesc (&desc);
+ goto retry;
+ }
+
+ /* Also, re-drive the lookup if the item we looked up was a hardlink, and the number
+ * or name of hardlinks has changed in the interim between the cat_lookup above, and
+ * our call to hfs_getnewvnode. hfs_getnewvnode will validate the cattr we passed it
+ * against what is actually in the catalog after the cnode is created. If there were
+ * any issues, it will bubble out ERECYCLE, which we need to swallow and use as the
+ * key to redrive as well. We need to special case this below because in this case,
+ * it needs to occur regardless of the type of lookup we're doing here.
+ */
+ if ((retval == ERECYCLE) && (newvnode_flags & GNV_CAT_ATTRCHANGED)) {
+ if (dcp) {
+ hfs_unlock (dcp);
+ }
+ /* get rid of any name buffers that may have lingered from the cat_lookup call */
+ cat_releasedesc (&desc);
+ retval = 0;
+ goto retry;
+ }
+
+ /* skip to the error-handling code if we can't retry */