+ 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;
+ }