6343073 buf[i] == 0 assertion failure when running zvol_pstress
6357699 Panic assertion failed: db->db_blkptr != 0
--- 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;