6343073 buf[i] == 0 assertion failure when running zvol_pstress
authormaybee
Wed, 21 Dec 2005 11:56:52 -0800
changeset 1163 4ba797920cc2
parent 1162 38b998160113
child 1164 3e8915c47756
6343073 buf[i] == 0 assertion failure when running zvol_pstress 6357699 Panic assertion failed: db->db_blkptr != 0
usr/src/uts/common/fs/zfs/dbuf.c
usr/src/uts/common/fs/zfs/dnode_sync.c
--- a/usr/src/uts/common/fs/zfs/dbuf.c	Wed Dec 21 11:46:49 2005 -0800
+++ b/usr/src/uts/common/fs/zfs/dbuf.c	Wed Dec 21 11:56:52 2005 -0800
@@ -1611,6 +1611,7 @@
 	uint64_t txg = tx->tx_txg;
 	dnode_t *dn = db->db_dnode;
 	objset_impl_t *os = dn->dn_objset;
+	int epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
 	int blksz;
 
 	ASSERT(dmu_tx_is_syncing(tx));
@@ -1751,7 +1752,6 @@
 		mutex_exit(&db->db_mtx);
 	} else if (db->db_blkptr == NULL) {
 		dmu_buf_impl_t *parent = db->db_parent;
-		int epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
 
 		mutex_exit(&db->db_mtx);
 		ASSERT(dn->dn_phys->dn_nlevels > 1);
@@ -1771,9 +1771,42 @@
 
 	ASSERT(IS_DNODE_DNODE(dn->dn_object) || db->db_parent != NULL);
 
+	if (db->db_level > 0 &&
+	    db->db_blkid > dn->dn_phys->dn_maxblkid >> (db->db_level * epbs)) {
+		/*
+		 * Don't write indirect blocks past EOF.
+		 * We get these when we truncate a file *after* dirtying
+		 * blocks in the truncate range (we undirty the level 0
+		 * blocks in dbuf_free_range(), but not the indirects).
+		 */
+#ifdef ZFS_DEBUG
+		/*
+		 * Verify that this indirect block is empty.
+		 */
+		blkptr_t *bplist;
+		int i;
+
+		mutex_enter(&db->db_mtx);
+		bplist = db->db.db_data;
+		for (i = 0; i < (1 << epbs); i++) {
+			if (!BP_IS_HOLE(&bplist[i])) {
+				panic("data past EOF: "
+				    "db=%p level=%d id=%lld i=%d\n",
+				    db, db->db_level, db->db_blkid, i);
+			}
+		}
+		mutex_exit(&db->db_mtx);
+#endif
+		ASSERT(db->db_blkptr == NULL || BP_IS_HOLE(db->db_blkptr));
+		mutex_enter(&db->db_mtx);
+		db->db_dirtycnt -= 1;
+		mutex_exit(&db->db_mtx);
+		dbuf_remove_ref(db, (void *)(uintptr_t)txg);
+		return;
+	}
+
 	if (db->db_parent != dn->dn_dbuf) {
 		dmu_buf_impl_t *parent = db->db_parent;
-		int epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
 
 		mutex_enter(&db->db_mtx);
 		ASSERT(db->db_level == parent->db_level-1);
@@ -1967,9 +2000,13 @@
 		blkptr_t *bp = db->db.db_data;
 		ASSERT3U(db->db.db_size, ==, 1<<dn->dn_phys->dn_indblkshift);
 		if (!BP_IS_HOLE(db->db_blkptr)) {
+			int epbs =
+			    dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT;
 			ASSERT3U(BP_GET_LSIZE(zio->io_bp), ==, db->db.db_size);
 			ASSERT3U(BP_GET_LSIZE(db->db_blkptr), ==,
 			    db->db.db_size);
+			ASSERT3U(dn->dn_phys->dn_maxblkid
+			    >> (db->db_level * epbs), >=, db->db_blkid);
 		}
 		for (i = db->db.db_size >> SPA_BLKPTRSHIFT; i > 0; i--, bp++) {
 			if (BP_IS_HOLE(bp))
--- a/usr/src/uts/common/fs/zfs/dnode_sync.c	Wed Dec 21 11:46:49 2005 -0800
+++ b/usr/src/uts/common/fs/zfs/dnode_sync.c	Wed Dec 21 11:56:52 2005 -0800
@@ -208,7 +208,7 @@
 	dmu_buf_impl_t *subdb;
 	uint64_t start, end, dbstart, dbend, i;
 	int epbs, shift, err;
-	int txg_index = tx->tx_txg&TXG_MASK;
+	int txgoff = tx->tx_txg & TXG_MASK;
 	int all = TRUE;
 
 	dbuf_read(db);
@@ -236,7 +236,7 @@
 	if (db->db_level == 1) {
 		FREE_VERIFY(db, start, end, tx);
 		free_blocks(dn, bp, end-start+1, tx);
-		ASSERT(all || list_link_active(&db->db_dirty_node[txg_index]));
+		ASSERT(all || list_link_active(&db->db_dirty_node[txgoff]));
 		return (all);
 	}
 
@@ -251,6 +251,8 @@
 		if (free_children(subdb, blkid, nblks, trunc, tx)) {
 			ASSERT3P(subdb->db_blkptr, ==, bp);
 			free_blocks(dn, bp, 1, tx);
+		} else {
+			all = FALSE;
 		}
 		dbuf_remove_ref(subdb, FTAG);
 	}
@@ -264,7 +266,7 @@
 		ASSERT3U(bp->blk_birth, ==, 0);
 	}
 #endif
-	ASSERT(all || list_link_active(&db->db_dirty_node[txg_index]));
+	ASSERT(all || list_link_active(&db->db_dirty_node[txgoff]));
 	return (all);
 }
 
@@ -478,8 +480,8 @@
 
 	/* process all the "freed" ranges in the file */
 	if (dn->dn_free_txg == 0 || dn->dn_free_txg > tx->tx_txg) {
-		for (rp = avl_first(&dn->dn_ranges[txgoff]); rp != NULL;
-		    rp = AVL_NEXT(&dn->dn_ranges[txgoff], rp))
+		for (rp = avl_last(&dn->dn_ranges[txgoff]); rp != NULL;
+		    rp = AVL_PREV(&dn->dn_ranges[txgoff], rp))
 			dnode_sync_free_range(dn,
 			    rp->fr_blkid, rp->fr_nblks, tx);
 	}
@@ -523,9 +525,10 @@
 		 * so only bother if there are multiple blocks and thus
 		 * it can't be changing.
 		 */
-		ASSERT(off < dn->dn_phys->dn_maxblkid ||
+		if (!(off < dn->dn_phys->dn_maxblkid ||
 		    dn->dn_phys->dn_maxblkid == 0 ||
-		    dnode_next_offset(dn, FALSE, &off, 1, 1) == ESRCH);
+		    dnode_next_offset(dn, FALSE, &off, 1, 1) == ESRCH))
+			panic("data after EOF: off=%lld\n", off);
 
 		dn->dn_dirtyblksz[txgoff] = 0;