+ return err;
+}
+
+
+/*
+ * hfs_cnode_teardown
+ *
+ * This is an internal function that is invoked from both hfs_vnop_inactive
+ * and hfs_vnop_reclaim. As VNOP_INACTIVE is not necessarily called from vnodes
+ * being recycled and reclaimed, it is important that we do any post-processing
+ * necessary for the cnode in both places. Important tasks include things such as
+ * releasing the blocks from an open-unlinked file when all references to it have dropped,
+ * and handling resource forks separately from data forks.
+ *
+ * Note that we take only the vnode as an argument here (rather than the cnode).
+ * Recall that each cnode supports two forks (rsrc/data), and we can always get the right
+ * cnode from either of the vnodes, but the reverse is not true -- we can't determine which
+ * vnode we need to reclaim if only the cnode is supplied.
+ *
+ * This function is idempotent and safe to call from both hfs_vnop_inactive and hfs_vnop_reclaim
+ * if both are invoked right after the other. In the second call, most of this function's if()
+ * conditions will fail, since they apply generally to cnodes still marked with C_DELETED.
+ * As a quick check to see if this function is necessary, determine if the cnode is already
+ * marked C_NOEXISTS. If it is, then it is safe to skip this function. The only tasks that
+ * remain for cnodes marked in such a fashion is to teardown their fork references and
+ * release all directory hints and hardlink origins. However, both of those are done
+ * in hfs_vnop_reclaim. hfs_update, by definition, is not necessary if the cnode's catalog
+ * entry is no longer there.
+ *
+ * 'reclaim' argument specifies whether or not we were called from hfs_vnop_reclaim. If we are
+ * invoked from hfs_vnop_reclaim, we can not call functions that cluster_push since the UBC info
+ * is totally gone by that point.
+ *
+ * Assumes that both truncate and cnode locks for 'cp' are held.
+ */
+static
+int hfs_cnode_teardown (struct vnode *vp, vfs_context_t ctx, int reclaim) {
+
+ int forkcount = 0;
+ enum vtype v_type;
+ struct cnode *cp;
+ int error = 0;
+ int started_tr = 0;
+ struct hfsmount *hfsmp = VTOHFS(vp);
+ struct proc *p = vfs_context_proc(ctx);
+ int truncated = 0;
+ cat_cookie_t cookie;
+ int cat_reserve = 0;
+ int lockflags;
+ int ea_error = 0;
+
+ v_type = vnode_vtype(vp);
+ cp = VTOC(vp);
+
+ if (cp->c_datafork) {
+ ++forkcount;
+ }
+ if (cp->c_rsrcfork) {
+ ++forkcount;
+ }
+
+
+ /*
+ * Skip the call to ubc_setsize if we're being invoked on behalf of reclaim.
+ * The dirty regions would have already been synced to disk, so informing UBC
+ * that they can toss the pages doesn't help anyone at this point.
+ *
+ * Note that this is a performance problem if the vnode goes straight to reclaim
+ * (and skips inactive), since there would be no way for anyone to notify the UBC
+ * that all pages in this file are basically useless.
+ */
+ if (reclaim == 0) {
+ /*
+ * Check whether we are tearing down a cnode with only one remaining fork.
+ * If there are blocks in its filefork, then we need to unlock the cnode
+ * before calling ubc_setsize. The cluster layer may re-enter the filesystem
+ * (i.e. VNOP_BLOCKMAP), and if we retain the cnode lock, we could double-lock
+ * panic.
+ */
+
+ if ((v_type == VREG || v_type == VLNK) &&
+ (cp->c_flag & C_DELETED) &&
+ (VTOF(vp)->ff_blocks != 0) && (forkcount == 1)) {
+ hfs_unlock(cp);
+ /* ubc_setsize just fails if we were to call this from VNOP_RECLAIM */
+ ubc_setsize(vp, 0);
+ (void) hfs_lock(cp, HFS_FORCE_LOCK);
+ }
+ }
+
+ /*
+ * Push file data out for normal files that haven't been evicted from
+ * the namespace. We only do this if this function was not called from reclaim,
+ * because by that point the UBC information has been totally torn down.
+ *
+ * There should also be no way that a normal file that has NOT been deleted from
+ * the namespace to skip INACTIVE and go straight to RECLAIM. That race only happens
+ * when the file becomes open-unlinked.
+ */
+ if ((v_type == VREG) &&
+ (!ISSET(cp->c_flag, C_DELETED)) &&
+ (!ISSET(cp->c_flag, C_NOEXISTS)) &&
+ (VTOF(vp)->ff_blocks) &&
+ (reclaim == 0)) {
+ hfs_filedone(vp, ctx);