changeset 3713:00e75dc8b749

6527325 want more assertions in space map code
author ahrens
date Sun, 25 Feb 2007 23:16:16 -0800
parents 881021ac3355
children dce229b9418d
files usr/src/lib/libzpool/common/kernel.c usr/src/lib/libzpool/common/sys/zfs_context.h usr/src/uts/common/fs/zfs/dmu.c usr/src/uts/common/fs/zfs/metaslab.c usr/src/uts/common/fs/zfs/spa_misc.c usr/src/uts/common/fs/zfs/space_map.c usr/src/uts/common/fs/zfs/sys/zfs_debug.h usr/src/uts/common/fs/zfs/zfs_dir.c
diffstat 8 files changed, 105 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/libzpool/common/kernel.c	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/lib/libzpool/common/kernel.c	Sun Feb 25 23:16:16 2007 -0800
@@ -567,6 +567,18 @@
 	va_end(adx);
 }
 
+void
+vcmn_err(int ce, const char *fmt, va_list adx)
+{
+	if (ce == CE_PANIC)
+		vpanic(fmt, adx);
+	if (ce != CE_NOTE) {	/* suppress noise in userland stress testing */
+		(void) fprintf(stderr, "%s", ce_prefix[ce]);
+		(void) vfprintf(stderr, fmt, adx);
+		(void) fprintf(stderr, "%s", ce_suffix[ce]);
+	}
+}
+
 /*PRINTFLIKE2*/
 void
 cmn_err(int ce, const char *fmt, ...)
@@ -574,13 +586,7 @@
 	va_list adx;
 
 	va_start(adx, fmt);
-	if (ce == CE_PANIC)
-		vpanic(fmt, adx);
-	if (ce != CE_NOTE) {	/* suppress noise in userland stress testing */
-		(void) fprintf(stderr, "%s", ce_prefix[ce]);
-		(void) vfprintf(stderr, fmt, adx);
-		(void) fprintf(stderr, "%s", ce_suffix[ce]);
-	}
+	vcmn_err(ce, fmt, adx);
 	va_end(adx);
 }
 
--- a/usr/src/lib/libzpool/common/sys/zfs_context.h	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/lib/libzpool/common/sys/zfs_context.h	Sun Feb 25 23:16:16 2007 -0800
@@ -96,6 +96,7 @@
 #endif /* ZFS_DEBUG */
 
 extern void cmn_err(int, const char *, ...);
+extern void vcmn_err(int, const char *, __va_list);
 extern void panic(const char *, ...);
 extern void vpanic(const char *, __va_list);
 
--- a/usr/src/uts/common/fs/zfs/dmu.c	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/dmu.c	Sun Feb 25 23:16:16 2007 -0800
@@ -181,7 +181,15 @@
 		nblks = (P2ROUNDUP(offset+length, 1ULL<<blkshift) -
 			P2ALIGN(offset, 1ULL<<blkshift)) >> blkshift;
 	} else {
-		ASSERT3U(offset + length, <=, dn->dn_datablksz);
+		if (offset + length > dn->dn_datablksz) {
+			zfs_panic_recover("zfs: accessing past end of object "
+			    "%llx/%llx (size=%u access=%llu+%llu)",
+			    (longlong_t)dn->dn_objset->
+			    os_dsl_dataset->ds_object,
+			    (longlong_t)dn->dn_object, dn->dn_datablksz,
+			    (longlong_t)offset, (longlong_t)length);
+			return (EIO);
+		}
 		nblks = 1;
 	}
 	dbp = kmem_zalloc(sizeof (dmu_buf_t *) * nblks, KM_SLEEP);
--- a/usr/src/uts/common/fs/zfs/metaslab.c	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/metaslab.c	Sun Feb 25 23:16:16 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -592,6 +592,7 @@
 	 * future allocations have synced.  (If we unloaded it now and then
 	 * loaded a moment later, the map wouldn't reflect those allocations.)
 	 */
+#ifndef ZFS_DEBUG
 	if (sm->sm_loaded && (msp->ms_weight & METASLAB_ACTIVE_MASK) == 0) {
 		int evictable = 1;
 
@@ -602,6 +603,7 @@
 		if (evictable)
 			space_map_unload(sm);
 	}
+#endif
 
 	metaslab_group_sort(mg, msp, metaslab_weight(msp));
 
@@ -868,6 +870,43 @@
 		if (msp->ms_freemap[txg & TXG_MASK].sm_space == 0)
 			vdev_dirty(vd, VDD_METASLAB, msp, txg);
 		space_map_add(&msp->ms_freemap[txg & TXG_MASK], offset, size);
+
+		/*
+		 * verify that this region is actually allocated in
+		 * either a ms_allocmap or the ms_map
+		 */
+#ifdef ZFS_DEBUG
+		(void) space_map_load(&msp->ms_map, &metaslab_ff_ops,
+		    SM_FREE, &msp->ms_smo,
+		    msp->ms_group->mg_vd->vdev_spa->spa_meta_objset);
+#endif
+		if (msp->ms_map.sm_loaded) {
+			boolean_t allocd = B_FALSE;
+			int i;
+
+			if (!space_map_contains(&msp->ms_map, offset, size)) {
+				allocd = B_TRUE;
+			} else {
+				for (i = 0; i < TXG_CONCURRENT_STATES; i++) {
+					space_map_t *sm = &msp->ms_allocmap
+					    [(txg - i) & TXG_MASK];
+					if (space_map_contains(sm,
+					    offset, size)) {
+						allocd = B_TRUE;
+						break;
+					}
+				}
+			}
+
+			if (!allocd) {
+				zfs_panic_recover("freeing free segment "
+				    "(vdev=%llu offset=%llx size=%llx)",
+				    (longlong_t)vdev, (longlong_t)offset,
+				    (longlong_t)size);
+			}
+		}
+
+
 	}
 
 	mutex_exit(&msp->ms_lock);
--- a/usr/src/uts/common/fs/zfs/spa_misc.c	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/spa_misc.c	Sun Feb 25 23:16:16 2007 -0800
@@ -187,6 +187,13 @@
 int zfs_flags = 0;
 #endif
 
+/*
+ * zfs_recover can be set to nonzero to attempt to recover from
+ * otherwise-fatal errors, typically caused by on-disk corruption.  When
+ * set, calls to zfs_panic_recover() will turn into warning messages.
+ */
+int zfs_recover = 0;
+
 #define	SPA_MINREF	5	/* spa_refcnt for an open-but-idle pool */
 
 /*
@@ -840,6 +847,16 @@
 		txg_wait_synced(spa_get_dsl(spa), freeze_txg);
 }
 
+void
+zfs_panic_recover(const char *fmt, ...)
+{
+	va_list adx;
+
+	va_start(adx, fmt);
+	vcmn_err(zfs_recover ? CE_WARN : CE_PANIC, fmt, adx);
+	va_end(adx);
+}
+
 /*
  * ==========================================================================
  * Accessor functions
--- a/usr/src/uts/common/fs/zfs/space_map.c	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/space_map.c	Sun Feb 25 23:16:16 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -97,6 +97,13 @@
 	ssearch.ss_end = end;
 	ss = avl_find(&sm->sm_root, &ssearch, &where);
 
+	if (ss != NULL && ss->ss_start <= start && ss->ss_end >= end) {
+		zfs_panic_recover("zfs: allocating allocated segment"
+		    "(offset=%llu size=%llu)\n",
+		    (longlong_t)start, (longlong_t)size);
+		return;
+	}
+
 	/* Make sure we don't overlap with either of our neighbors */
 	VERIFY(ss == NULL);
 
@@ -142,7 +149,12 @@
 	ss = avl_find(&sm->sm_root, &ssearch, &where);
 
 	/* Make sure we completely overlap with someone */
-	VERIFY(ss != NULL);
+	if (ss == NULL) {
+		zfs_panic_recover("zfs: freeing free segment "
+		    "(offset=%llu size=%llu)",
+		    (longlong_t)start, (longlong_t)size);
+		return;
+	}
 	VERIFY3U(ss->ss_start, <=, start);
 	VERIFY3U(ss->ss_end, >=, end);
 	VERIFY(sm->sm_space - size <= sm->sm_size);
--- a/usr/src/uts/common/fs/zfs/sys/zfs_debug.h	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_debug.h	Sun Feb 25 23:16:16 2007 -0800
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -66,6 +66,8 @@
 #define	dprintf(...) ((void)0)
 #endif /* ZFS_DEBUG */
 
+extern void zfs_panic_recover(const char *fmt, ...);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/fs/zfs/zfs_dir.c	Sun Feb 25 14:16:28 2007 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_dir.c	Sun Feb 25 23:16:16 2007 -0800
@@ -591,7 +591,14 @@
 			vn_vfsunlock(vp);
 			return (EEXIST);
 		}
-		ASSERT(zp->z_phys->zp_links > zp_is_dir);
+		if (zp->z_phys->zp_links <= zp_is_dir) {
+			zfs_panic_recover("zfs: link count on %s is %u, "
+			    "should be at least %u",
+			    zp->z_vnode->v_path ? zp->z_vnode->v_path :
+			    "<unknown>", (int)zp->z_phys->zp_links,
+			    zp_is_dir + 1);
+			zp->z_phys->zp_links = zp_is_dir + 1;
+		}
 		if (--zp->z_phys->zp_links == zp_is_dir) {
 			zp->z_unlinked = B_TRUE;
 			zp->z_phys->zp_links = 0;