changeset 4312:4fef416ca8cb

6523336 panic dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN, file: ../../ common/fs/zfs/dbuf.c line: 2195 6549634 dn_dbfs_mtx should be held when calling list_link_active() in dbuf_destroy()
author gw25295
date Thu, 24 May 2007 12:18:14 -0700
parents 27c974ce5d7f
children ce5fb9ac11f5
files usr/src/uts/common/fs/zfs/dbuf.c usr/src/uts/common/fs/zfs/dnode_sync.c
diffstat 2 files changed, 20 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/fs/zfs/dbuf.c	Thu May 24 12:17:11 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dbuf.c	Thu May 24 12:18:14 2007 -0700
@@ -1471,17 +1471,23 @@
 
 	if (db->db_blkid != DB_BONUS_BLKID) {
 		dnode_t *dn = db->db_dnode;
+		boolean_t need_mutex = !MUTEX_HELD(&dn->dn_dbufs_mtx);
+
+		if (need_mutex)
+			mutex_enter(&dn->dn_dbufs_mtx);
 
 		/*
 		 * If this dbuf is still on the dn_dbufs list,
 		 * remove it from that list.
 		 */
 		if (list_link_active(&db->db_link)) {
-			mutex_enter(&dn->dn_dbufs_mtx);
+			ASSERT(need_mutex);
 			list_remove(&dn->dn_dbufs, db);
 			mutex_exit(&dn->dn_dbufs_mtx);
 
 			dnode_rele(dn, db);
+		} else if (need_mutex) {
+			mutex_exit(&dn->dn_dbufs_mtx);
 		}
 		dbuf_hash_remove(db);
 	}
@@ -1489,6 +1495,7 @@
 	db->db_dnode = NULL;
 	db->db_buf = NULL;
 
+	ASSERT(!list_link_active(&db->db_link));
 	ASSERT(db->db.db_data == NULL);
 	ASSERT(db->db_hash_next == NULL);
 	ASSERT(db->db_blkptr == NULL);
@@ -1939,6 +1946,14 @@
 	}
 
 	/*
+	 * This function may have dropped the db_mtx lock allowing a dmu_sync
+	 * operation to sneak in. As a result, we need to ensure that we
+	 * don't check the dr_override_state until we have returned from
+	 * dbuf_check_blkptr.
+	 */
+	dbuf_check_blkptr(dn, db);
+
+	/*
 	 * If this buffer is in the middle of an immdiate write,
 	 * wait for the synchronous IO to complete.
 	 */
@@ -1948,8 +1963,6 @@
 		ASSERT(dr->dt.dl.dr_override_state != DR_NOT_OVERRIDDEN);
 	}
 
-	dbuf_check_blkptr(dn, db);
-
 	/*
 	 * If this dbuf has already been written out via an immediate write,
 	 * just complete the write by copying over the new block pointer and
--- a/usr/src/uts/common/fs/zfs/dnode_sync.c	Thu May 24 12:17:11 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dnode_sync.c	Thu May 24 12:18:14 2007 -0700
@@ -55,9 +55,8 @@
 	ASSERT(db != NULL);
 
 	dn->dn_phys->dn_nlevels = new_level;
-	dprintf("os=%p obj=%llu, increase to %d\n",
-		dn->dn_objset, dn->dn_object,
-		dn->dn_phys->dn_nlevels);
+	dprintf("os=%p obj=%llu, increase to %d\n", dn->dn_objset,
+	    dn->dn_object, dn->dn_phys->dn_nlevels);
 
 	/* check for existing blkptrs in the dnode */
 	for (i = 0; i < nblkptr; i++)
@@ -160,7 +159,7 @@
 
 		rw_enter(&db->db_dnode->dn_struct_rwlock, RW_READER);
 		err = dbuf_hold_impl(db->db_dnode, db->db_level-1,
-			(db->db_blkid << epbs) + i, TRUE, FTAG, &child);
+		    (db->db_blkid << epbs) + i, TRUE, FTAG, &child);
 		rw_exit(&db->db_dnode->dn_struct_rwlock);
 		if (err == ENOENT)
 			continue;
@@ -367,6 +366,7 @@
 		for (; db != &marker; db = list_head(&dn->dn_dbufs)) {
 			list_remove(&dn->dn_dbufs, db);
 			list_insert_tail(&dn->dn_dbufs, db);
+			ASSERT3P(db->db_dnode, ==, dn);
 
 			mutex_enter(&db->db_mtx);
 			if (db->db_state == DB_EVICTING) {