diff --git a/sys/vfs/hammer/hammer.h b/sys/vfs/hammer/hammer.h
index 415a4b5..48dd4d0 100644
--- a/sys/vfs/hammer/hammer.h
+++ b/sys/vfs/hammer/hammer.h
@@ -118,6 +118,7 @@ typedef struct hammer_transaction *hammer_transaction_t;
 
 #define HAMMER_TRANSF_NEWINODE	0x0001
 #define HAMMER_TRANSF_DIDIO	0x0002
+#define HAMMER_TRANSF_CRCDOM	0x0004	/* EDOM on CRC error, less critical */
 
 /*
  * HAMMER locks
@@ -587,6 +588,9 @@ struct hammer_node {
 #define HAMMER_NODE_CRCGOOD	0x0004
 #define HAMMER_NODE_NEEDSCRC	0x0008
 #define HAMMER_NODE_NEEDSMIRROR	0x0010
+#define HAMMER_NODE_CRCBAD	0x0020
+
+#define HAMMER_NODE_CRCANY	(HAMMER_NODE_CRCGOOD | HAMMER_NODE_CRCBAD)
 
 typedef struct hammer_node	*hammer_node_t;
 
@@ -1028,7 +1032,7 @@ int		hammer_vfs_export(struct mount *mp, int op,
 hammer_node_t	hammer_get_node(hammer_transaction_t trans,
 			hammer_off_t node_offset, int isnew, int *errorp);
 void		hammer_ref_node(hammer_node_t node);
-hammer_node_t	hammer_ref_node_safe(struct hammer_mount *hmp,
+hammer_node_t	hammer_ref_node_safe(hammer_transaction_t trans,
 			hammer_node_cache_t cache, int *errorp);
 void		hammer_rel_node(hammer_node_t node);
 void		hammer_delete_node(hammer_transaction_t trans,
@@ -1245,12 +1249,14 @@ hammer_lock_ex(struct hammer_lock *lock)
 static __inline void
 hammer_modify_node_noundo(hammer_transaction_t trans, hammer_node_t node)
 {
+	KKASSERT((node->flags & HAMMER_NODE_CRCBAD) == 0);
 	hammer_modify_buffer(trans, node->buffer, NULL, 0);
 }
 
 static __inline void
 hammer_modify_node_all(hammer_transaction_t trans, struct hammer_node *node)
 {
+	KKASSERT((node->flags & HAMMER_NODE_CRCBAD) == 0);
 	hammer_modify_buffer(trans, node->buffer,
 			     node->ondisk, sizeof(*node->ondisk));
 }
@@ -1264,6 +1270,7 @@ hammer_modify_node(hammer_transaction_t trans, hammer_node_t node,
 	KKASSERT((char *)base >= (char *)node->ondisk &&
 		 (char *)base + len <=
 		    (char *)node->ondisk + sizeof(*node->ondisk));
+	KKASSERT((node->flags & HAMMER_NODE_CRCBAD) == 0);
 	hammer_modify_buffer(trans, node->buffer, base, len);
 	crcptr = &node->ondisk->crc;
 	hammer_modify_buffer(trans, node->buffer, crcptr, sizeof(hammer_crc_t));
diff --git a/sys/vfs/hammer/hammer_btree.c b/sys/vfs/hammer/hammer_btree.c
index e51f7f7..56a4b34 100644
--- a/sys/vfs/hammer/hammer_btree.c
+++ b/sys/vfs/hammer/hammer_btree.c
@@ -710,7 +710,12 @@ hammer_btree_extract(hammer_cursor_t cursor, int flags)
 	if (hammer_crc_test_leaf(cursor->data, &elm->leaf) == 0) {
 		kprintf("CRC DATA @ %016llx/%d FAILED\n",
 			elm->leaf.data_offset, elm->leaf.data_len);
-		Debugger("CRC FAILED: DATA");
+		if (hammer_debug_debug & 0x0001)
+			Debugger("CRC FAILED: DATA");
+		if (cursor->trans->flags & HAMMER_TRANSF_CRCDOM)
+			error = EDOM;	/* less critical (mirroring) */
+		else
+			error = EIO;	/* critical */
 	}
 	return(error);
 }
diff --git a/sys/vfs/hammer/hammer_cursor.c b/sys/vfs/hammer/hammer_cursor.c
index 7b340bf..679eceb 100644
--- a/sys/vfs/hammer/hammer_cursor.c
+++ b/sys/vfs/hammer/hammer_cursor.c
@@ -73,7 +73,7 @@ hammer_init_cursor(hammer_transaction_t trans, hammer_cursor_t cursor,
 	 * Step 1 - acquire a locked node from the cache if possible
 	 */
 	if (cache && cache->node) {
-		node = hammer_ref_node_safe(trans->hmp, cache, &error);
+		node = hammer_ref_node_safe(trans, cache, &error);
 		if (error == 0) {
 			hammer_lock_sh(&node->lock);
 			if (node->flags & HAMMER_NODE_DELETED) {
diff --git a/sys/vfs/hammer/hammer_inode.c b/sys/vfs/hammer/hammer_inode.c
index 73c75de..abe6dc1 100644
--- a/sys/vfs/hammer/hammer_inode.c
+++ b/sys/vfs/hammer/hammer_inode.c
@@ -2508,7 +2508,7 @@ hammer_sync_inode(hammer_transaction_t trans, hammer_inode_t ip)
 	 * out from under us.
 	 */
 	if (error == 0) {
-		tmp_node = hammer_ref_node_safe(ip->hmp, &ip->cache[0], &error);
+		tmp_node = hammer_ref_node_safe(trans, &ip->cache[0], &error);
 		if (tmp_node) {
 			hammer_cursor_downgrade(&cursor);
 			hammer_lock_sh(&tmp_node->lock);
diff --git a/sys/vfs/hammer/hammer_ioctl.h b/sys/vfs/hammer/hammer_ioctl.h
index 73ab091..137d422 100644
--- a/sys/vfs/hammer/hammer_ioctl.h
+++ b/sys/vfs/hammer/hammer_ioctl.h
@@ -324,6 +324,13 @@ union hammer_ioc_mrecord_any {
 
 typedef union hammer_ioc_mrecord_any *hammer_ioc_mrecord_any_t;
 
+/*
+ * MREC types.  Flags are in the upper 16 bits but some are also included
+ * in the type mask to force them into any switch() on the type.
+ *
+ * NOTE: Any record whos data is CRC-errored will have HAMMER_MRECF_CRC set,
+ *	 and the bit is also part of the type mask.
+ */
 #define HAMMER_MREC_TYPE_RESERVED	0
 #define HAMMER_MREC_TYPE_REC		1	/* record w/ data */
 #define HAMMER_MREC_TYPE_PFSD		2	/* (userland only) */
@@ -334,6 +341,14 @@ typedef union hammer_ioc_mrecord_any *hammer_ioc_mrecord_any_t;
 #define HAMMER_MREC_TYPE_TERM		7	/* (userland only) */
 #define HAMMER_MREC_TYPE_IDLE		8	/* (userland only) */
 
+#define HAMMER_MREC_TYPE_REC_BADCRC	(HAMMER_MREC_TYPE_REC | \
+					 HAMMER_MRECF_CRC_ERROR)
+
+#define HAMMER_MRECF_TYPE_MASK		0x800000FF
+#define HAMMER_MRECF_CRC_ERROR		0x80000000
+#define HAMMER_MRECF_DATA_CRC_BAD	0x40000000
+#define HAMMER_MRECF_RECD_CRC_BAD	0x20000000
+
 #define HAMMER_MREC_CRCOFF	(offsetof(struct hammer_ioc_mrecord_head, rec_size))
 #define HAMMER_MREC_HEADSIZE	sizeof(struct hammer_ioc_mrecord_head)
 
diff --git a/sys/vfs/hammer/hammer_mirror.c b/sys/vfs/hammer/hammer_mirror.c
index 6eaf126..4d054c1 100644
--- a/sys/vfs/hammer/hammer_mirror.c
+++ b/sys/vfs/hammer/hammer_mirror.c
@@ -89,6 +89,7 @@ hammer_ioc_mirror_read(hammer_transaction_t trans, hammer_inode_t ip,
 	int data_len;
 	int bytes;
 	int eatdisk;
+	int mrec_flags;
 	u_int32_t localization;
 	u_int32_t rec_crc;
 
@@ -107,6 +108,12 @@ hammer_ioc_mirror_read(hammer_transaction_t trans, hammer_inode_t ip,
 	bzero(&mrec, sizeof(mrec));
 	bzero(&cmirror, sizeof(cmirror));
 
+	/*
+	 * Make CRC errors non-fatal (at least on data), causing an EDOM
+	 * error instead of EIO.
+	 */
+	trans->flags |= HAMMER_TRANSF_CRCDOM;
+
 retry:
 	error = hammer_init_cursor(trans, &cursor, NULL, NULL);
 	if (error) {
@@ -224,13 +231,21 @@ retry:
 
 		/*
 		 * The core code exports the data to userland.
+		 *
+		 * CRC errors on data are reported but passed through,
+		 * but the data must be washed by the user program.
 		 */
+		mrec_flags = 0;
 		data_len = (elm->data_offset) ? elm->data_len : 0;
 		if (data_len) {
 			error = hammer_btree_extract(&cursor,
 						     HAMMER_CURSOR_GET_DATA);
-			if (error)
-				break;
+			if (error) {
+				if (error != EDOM)
+					break;
+				mrec_flags |= HAMMER_MRECF_CRC_ERROR |
+					      HAMMER_MRECF_DATA_CRC_BAD;
+			}
 		}
 
 		bytes = sizeof(mrec.rec) + data_len;
@@ -246,9 +261,10 @@ retry:
 		 * userland and delete_tid is cleared.
 		 */
 		mrec.head.signature = HAMMER_IOC_MIRROR_SIGNATURE;
-		mrec.head.type = HAMMER_MREC_TYPE_REC;
+		mrec.head.type = HAMMER_MREC_TYPE_REC | mrec_flags;
 		mrec.head.rec_size = bytes;
 		mrec.rec.leaf = *elm;
+
 		if (elm->base.delete_tid > mirror->tid_end)
 			mrec.rec.leaf.base.delete_tid = 0;
 		rec_crc = crc32(&mrec.head.rec_size,
diff --git a/sys/vfs/hammer/hammer_object.c b/sys/vfs/hammer/hammer_object.c
index aca7a29..ee30f33 100644
--- a/sys/vfs/hammer/hammer_object.c
+++ b/sys/vfs/hammer/hammer_object.c
@@ -703,7 +703,8 @@ failed:
  * cursor must be seeked to the directory entry record being deleted.
  *
  * The related inode should be share-locked by the caller.  The caller is
- * on the frontend.
+ * on the frontend.  It could also be NULL indicating that the directory
+ * entry being removed has no related inode.
  *
  * This function can return EDEADLK requiring the caller to terminate
  * the cursor, any locks, wait on the returned record, and retry.
@@ -749,9 +750,18 @@ hammer_ip_del_directory(struct hammer_transaction *trans,
 		record->type = HAMMER_MEM_RECORD_DEL;
 		record->leaf.base = cursor->leaf->base;
 
+		/*
+		 * ip may be NULL, indicating the deletion of a directory
+		 * entry which has no related inode.
+		 */
 		record->target_ip = ip;
-		record->flush_state = HAMMER_FST_SETUP;
-		TAILQ_INSERT_TAIL(&ip->target_list, record, target_entry);
+		if (ip) {
+			record->flush_state = HAMMER_FST_SETUP;
+			TAILQ_INSERT_TAIL(&ip->target_list, record,
+					  target_entry);
+		} else {
+			record->flush_state = HAMMER_FST_IDLE;
+		}
 
 		/*
 		 * The inode now has a dependancy and must be taken out of
@@ -762,7 +772,7 @@ hammer_ip_del_directory(struct hammer_transaction *trans,
 		 * reflush when the dependancies are disposed of if someone
 		 * is waiting on the inode.
 		 */
-		if (ip->flush_state == HAMMER_FST_IDLE) {
+		if (ip && ip->flush_state == HAMMER_FST_IDLE) {
 			hammer_ref(&ip->lock);
 			ip->flush_state = HAMMER_FST_SETUP;
 			if (ip->flags & HAMMER_INODE_FLUSHW)
@@ -786,15 +796,18 @@ hammer_ip_del_directory(struct hammer_transaction *trans,
 	 * on-media until we unmount.
 	 */
 	if (error == 0) {
-		--ip->ino_data.nlinks;
+		if (ip)
+			--ip->ino_data.nlinks;	/* do before we might block */
 		dip->ino_data.mtime = trans->time;
 		hammer_modify_inode(dip, HAMMER_INODE_MTIME);
-		hammer_modify_inode(ip, HAMMER_INODE_DDIRTY);
-		if (ip->ino_data.nlinks == 0 &&
-		    (ip->vp == NULL || (ip->vp->v_flag & VINACTIVE))) {
-			hammer_done_cursor(cursor);
-			hammer_inode_unloadable_check(ip, 1);
-			hammer_flush_inode(ip, 0);
+		if (ip) {
+			hammer_modify_inode(ip, HAMMER_INODE_DDIRTY);
+			if (ip->ino_data.nlinks == 0 &&
+			    (ip->vp == NULL || (ip->vp->v_flag & VINACTIVE))) {
+				hammer_done_cursor(cursor);
+				hammer_inode_unloadable_check(ip, 1);
+				hammer_flush_inode(ip, 0);
+			}
 		}
 
 	}
diff --git a/sys/vfs/hammer/hammer_ondisk.c b/sys/vfs/hammer/hammer_ondisk.c
index 214e1ff..cc1bf08 100644
--- a/sys/vfs/hammer/hammer_ondisk.c
+++ b/sys/vfs/hammer/hammer_ondisk.c
@@ -48,7 +48,8 @@
 static void hammer_free_volume(hammer_volume_t volume);
 static int hammer_load_volume(hammer_volume_t volume);
 static int hammer_load_buffer(hammer_buffer_t buffer, int isnew);
-static int hammer_load_node(hammer_node_t node, int isnew);
+static int hammer_load_node(hammer_transaction_t trans,
+				hammer_node_t node, int isnew);
 
 static int
 hammer_vol_rb_compare(hammer_volume_t vol1, hammer_volume_t vol2)
@@ -1109,7 +1110,7 @@ again:
 	if (node->ondisk) {
 		*errorp = 0;
 	} else {
-		*errorp = hammer_load_node(node, isnew);
+		*errorp = hammer_load_node(trans, node, isnew);
 		trans->flags |= HAMMER_TRANSF_DIDIO;
 	}
 	if (*errorp) {
@@ -1133,7 +1134,7 @@ hammer_ref_node(hammer_node_t node)
  * Load a node's on-disk data reference.
  */
 static int
-hammer_load_node(hammer_node_t node, int isnew)
+hammer_load_node(hammer_transaction_t trans, hammer_node_t node, int isnew)
 {
 	hammer_buffer_t buffer;
 	hammer_off_t buf_offset;
@@ -1175,13 +1176,28 @@ hammer_load_node(hammer_node_t node, int isnew)
 			goto failed;
 		node->ondisk = (void *)((char *)buffer->ondisk +
 				        (node->node_offset & HAMMER_BUFMASK));
+
+		/*
+		 * Check CRC.  NOTE: Neither flag is set and the CRC is not
+		 * generated on new B-Tree nodes.
+		 */
 		if (isnew == 0 && 
-		    (node->flags & HAMMER_NODE_CRCGOOD) == 0) {
-			if (hammer_crc_test_btree(node->ondisk) == 0)
-				Debugger("CRC FAILED: B-TREE NODE");
-			node->flags |= HAMMER_NODE_CRCGOOD;
+		    (node->flags & HAMMER_NODE_CRCANY) == 0) {
+			if (hammer_crc_test_btree(node->ondisk) == 0) {
+				if (hammer_debug_debug & 0x0002)
+					Debugger("CRC FAILED: B-TREE NODE");
+				node->flags |= HAMMER_NODE_CRCBAD;
+			} else {
+				node->flags |= HAMMER_NODE_CRCGOOD;
+			}
 		}
 	}
+	if (node->flags & HAMMER_NODE_CRCBAD) {
+		if (trans->flags & HAMMER_TRANSF_CRCDOM)
+			error = EDOM;
+		else
+			error = EIO;
+	}
 failed:
 	--node->loading;
 	hammer_unlock(&node->lock);
@@ -1192,7 +1208,7 @@ failed:
  * Safely reference a node, interlock against flushes via the IO subsystem.
  */
 hammer_node_t
-hammer_ref_node_safe(struct hammer_mount *hmp, hammer_node_cache_t cache,
+hammer_ref_node_safe(hammer_transaction_t trans, hammer_node_cache_t cache,
 		     int *errorp)
 {
 	hammer_node_t node;
@@ -1200,10 +1216,18 @@ hammer_ref_node_safe(struct hammer_mount *hmp, hammer_node_cache_t cache,
 	node = cache->node;
 	if (node != NULL) {
 		hammer_ref(&node->lock);
-		if (node->ondisk)
-			*errorp = 0;
-		else
-			*errorp = hammer_load_node(node, 0);
+		if (node->ondisk) {
+			if (node->flags & HAMMER_NODE_CRCBAD) {
+				if (trans->flags & HAMMER_TRANSF_CRCDOM)
+					*errorp = EDOM;
+				else
+					*errorp = EIO;
+			} else {
+				*errorp = 0;
+			}
+		} else {
+			*errorp = hammer_load_node(trans, node, 0);
+		}
 		if (*errorp) {
 			hammer_rel_node(node);
 			node = NULL;
diff --git a/sys/vfs/hammer/hammer_vnops.c b/sys/vfs/hammer/hammer_vnops.c
index c2abe5f..e39a69c 100644
--- a/sys/vfs/hammer/hammer_vnops.c
+++ b/sys/vfs/hammer/hammer_vnops.c
@@ -1298,6 +1298,10 @@ hammer_vop_readdir(struct vop_readdir_args *ap)
 
 	/*
 	 * Handle artificial entries
+	 *
+	 * It should be noted that the minimum value for a directory
+	 * hash key on-media is 0x0000000100000000, so we can use anything
+	 * less then that to represent our 'special' key space.
 	 */
 	error = 0;
 	if (saveoff == 0) {
@@ -2811,15 +2815,17 @@ retry:
 				      0, &error);
 		hammer_lock_sh(&cursor.ip->lock);
 		if (error == ENOENT) {
-			kprintf("obj_id %016llx\n", cursor.data->entry.obj_id);
-			Debugger("ENOENT unlinking object that should exist");
+			kprintf("HAMMER: Warning: Removing directory entry"
+				" whos inode does not exist: %016llx\n",
+				(long long)cursor.data->entry.obj_id);
+			error = 0;
 		}
 
 		/*
 		 * If isdir >= 0 we validate that the entry is or is not a
 		 * directory.  If isdir < 0 we don't care.
 		 */
-		if (error == 0 && isdir >= 0) {
+		if (error == 0 && isdir >= 0 && ip) {
 			if (isdir &&
 			    ip->ino_data.obj_type != HAMMER_OBJTYPE_DIRECTORY) {
 				error = ENOTDIR;
@@ -2841,8 +2847,8 @@ retry:
 		 * If any changes whatsoever have been made to the cursor
 		 * set EDEADLK and retry.
 		 */
-		if (error == 0 && ip->ino_data.obj_type ==
-				  HAMMER_OBJTYPE_DIRECTORY) {
+		if (error == 0 && ip && ip->ino_data.obj_type ==
+				        HAMMER_OBJTYPE_DIRECTORY) {
 			hammer_unlock_cursor(&cursor);
 			error = hammer_ip_check_directory_empty(trans, ip);
 			hammer_lock_cursor(&cursor);
@@ -2870,7 +2876,7 @@ retry:
 			cache_setunresolved(nch);
 			cache_setvp(nch, NULL);
 			/* XXX locking */
-			if (ip->vp) {
+			if (ip && ip->vp) {
 				hammer_knote(ip->vp, NOTE_DELETE);
 				cache_inval_vp(ip->vp, CINV_DESTROY);
 			}
diff --git a/sys/vm/vm_contig.c b/sys/vm/vm_contig.c
index f45ad0f..4de57af 100644
--- a/sys/vm/vm_contig.c
+++ b/sys/vm/vm_contig.c
@@ -474,7 +474,10 @@ contigmalloc_map(
 
 	index = vm_contig_pg_alloc(size, low, high, alignment, boundary, flags);
 	if (index < 0) {
-		kprintf("contigmalloc_map: failed in index < 0 case!\n");
+		kprintf("contigmalloc_map: failed size %lu low=%llx "
+			"high=%llx align=%lu boundary=%lu flags=%08x\n",
+			size, (long long)low, (long long)high,
+			alignment, boundary, flags);
 		return NULL;
 	}
 
