+
+ /*
+ * Under normal circumstances, we would want to return ENOENT if a cnode is in
+ * the hash and it is marked C_NOEXISTS or C_DELETED. However, if the CNID
+ * namespace has wrapped around, then we have the possibility of collisions.
+ * In that case, we may use this function to validate whether or not we
+ * should trust the nextCNID value in the hfs mount point.
+ *
+ * If we didn't do this, then it would be possible for a cnode that is no longer backed
+ * by anything on-disk (C_NOEXISTS) to still exist in the hash along with its
+ * vnode. The cat_create routine could then create a new entry in the catalog
+ * re-using that CNID. Then subsequent hfs_getnewvnode calls will repeatedly fail
+ * trying to look it up/validate it because it is marked C_NOEXISTS. So we want
+ * to prevent that from happening as much as possible.
+ */
+ if (existence_only) {
+ result = 0;
+ break;
+ }
+
+ /* Skip cnodes that have been removed from the catalog */
+ if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
+ break;
+ }
+ /* Skip cnodes being created or reclaimed. */
+ if (!ISSET(cp->c_hflag, H_ALLOC | H_TRANSIT | H_ATTACH)) {
+ result = callout(&cp->c_desc, &cp->c_attr, arg);
+ }
+ break;
+ }
+ hfs_chash_unlock(hfsmp);
+
+ return (result);
+}
+
+
+/*
+ * Use the device, fileid pair to find the incore cnode.
+ * If no cnode if found one is created
+ *
+ * If it is in core, but locked, wait for it.
+ *
+ * If the cnode is C_DELETED, then return NULL since that
+ * inum is no longer valid for lookups (open-unlinked file).
+ *
+ * If the cnode is C_DELETED but also marked C_RENAMED, then that means
+ * the cnode was renamed over and a new entry exists in its place. The caller
+ * should re-drive the lookup to get the newer entry. In that case, we'll still
+ * return NULL for the cnode, but also return GNV_CHASH_RENAMED in the output flags
+ * of this function to indicate the caller that they should re-drive.
+ */
+struct cnode *
+hfs_chash_getcnode(struct hfsmount *hfsmp, ino_t inum, struct vnode **vpp,
+ int wantrsrc, int skiplock, int *out_flags, int *hflags)
+{
+ struct cnode *cp;
+ struct cnode *ncp = NULL;
+ vnode_t vp;
+ u_int32_t vid;
+
+ /*
+ * Go through the hash list
+ * If a cnode is in the process of being cleaned out or being
+ * allocated, wait for it to be finished and then try again.
+ */
+loop:
+ hfs_chash_lock_spin(hfsmp);