Print this page
6267 dn_bonus evicted too early
Reviewed by: Richard Yao <ryao@gentoo.org>
Reviewed by: Xin LI <delphij@freebsd.org>
Reviewed by: Matthew Ahrens <mahrens@delphix.com>
Approved by: Richard Lowe <richlowe@richlowe.net>


 407 #ifdef  DEBUG
 408                 DB_DNODE_ENTER(db);
 409                 ASSERT3P(DB_DNODE(db), ==, dn);
 410                 DB_DNODE_EXIT(db);
 411 #endif  /* DEBUG */
 412 
 413                 mutex_enter(&db->db_mtx);
 414                 if (db->db_state != DB_EVICTING &&
 415                     refcount_is_zero(&db->db_holds)) {
 416                         db_marker.db_level = db->db_level;
 417                         db_marker.db_blkid = db->db_blkid;
 418                         db_marker.db_state = DB_SEARCH;
 419                         avl_insert_here(&dn->dn_dbufs, &db_marker, db,
 420                             AVL_BEFORE);
 421 
 422                         dbuf_clear(db);
 423 
 424                         db_next = AVL_NEXT(&dn->dn_dbufs, &db_marker);
 425                         avl_remove(&dn->dn_dbufs, &db_marker);
 426                 } else {

 427                         mutex_exit(&db->db_mtx);
 428                         db_next = AVL_NEXT(&dn->dn_dbufs, db);
 429                 }
 430         }
 431         mutex_exit(&dn->dn_dbufs_mtx);
 432 
 433         dnode_evict_bonus(dn);
 434 }
 435 
 436 void
 437 dnode_evict_bonus(dnode_t *dn)
 438 {
 439         rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
 440         if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) {

 441                 mutex_enter(&dn->dn_bonus->db_mtx);
 442                 dbuf_evict(dn->dn_bonus);
 443                 dn->dn_bonus = NULL;


 444         }

 445         rw_exit(&dn->dn_struct_rwlock);
 446 }
 447 
 448 static void
 449 dnode_undirty_dbufs(list_t *list)
 450 {
 451         dbuf_dirty_record_t *dr;
 452 
 453         while (dr = list_head(list)) {
 454                 dmu_buf_impl_t *db = dr->dr_dbuf;
 455                 uint64_t txg = dr->dr_txg;
 456 
 457                 if (db->db_level != 0)
 458                         dnode_undirty_dbufs(&dr->dt.di.dr_children);
 459 
 460                 mutex_enter(&db->db_mtx);
 461                 /* XXX - use dbuf_undirty()? */
 462                 list_remove(list, dr);
 463                 ASSERT(db->db_last_dirty == dr);
 464                 db->db_last_dirty = NULL;


 475                 dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg);
 476         }
 477 }
 478 
 479 static void
 480 dnode_sync_free(dnode_t *dn, dmu_tx_t *tx)
 481 {
 482         int txgoff = tx->tx_txg & TXG_MASK;
 483 
 484         ASSERT(dmu_tx_is_syncing(tx));
 485 
 486         /*
 487          * Our contents should have been freed in dnode_sync() by the
 488          * free range record inserted by the caller of dnode_free().
 489          */
 490         ASSERT0(DN_USED_BYTES(dn->dn_phys));
 491         ASSERT(BP_IS_HOLE(dn->dn_phys->dn_blkptr));
 492 
 493         dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]);
 494         dnode_evict_dbufs(dn);
 495         ASSERT(avl_is_empty(&dn->dn_dbufs));
 496 
 497         /*
 498          * XXX - It would be nice to assert this, but we may still
 499          * have residual holds from async evictions from the arc...
 500          *
 501          * zfs_obj_to_path() also depends on this being
 502          * commented out.
 503          *
 504          * ASSERT3U(refcount_count(&dn->dn_holds), ==, 1);
 505          */
 506 
 507         /* Undirty next bits */
 508         dn->dn_next_nlevels[txgoff] = 0;
 509         dn->dn_next_indblkshift[txgoff] = 0;
 510         dn->dn_next_blksz[txgoff] = 0;
 511 
 512         /* ASSERT(blkptrs are zero); */
 513         ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE);
 514         ASSERT(dn->dn_type != DMU_OT_NONE);
 515 




 407 #ifdef  DEBUG
 408                 DB_DNODE_ENTER(db);
 409                 ASSERT3P(DB_DNODE(db), ==, dn);
 410                 DB_DNODE_EXIT(db);
 411 #endif  /* DEBUG */
 412 
 413                 mutex_enter(&db->db_mtx);
 414                 if (db->db_state != DB_EVICTING &&
 415                     refcount_is_zero(&db->db_holds)) {
 416                         db_marker.db_level = db->db_level;
 417                         db_marker.db_blkid = db->db_blkid;
 418                         db_marker.db_state = DB_SEARCH;
 419                         avl_insert_here(&dn->dn_dbufs, &db_marker, db,
 420                             AVL_BEFORE);
 421 
 422                         dbuf_clear(db);
 423 
 424                         db_next = AVL_NEXT(&dn->dn_dbufs, &db_marker);
 425                         avl_remove(&dn->dn_dbufs, &db_marker);
 426                 } else {
 427                         db->db_pending_evict = TRUE;
 428                         mutex_exit(&db->db_mtx);
 429                         db_next = AVL_NEXT(&dn->dn_dbufs, db);
 430                 }
 431         }
 432         mutex_exit(&dn->dn_dbufs_mtx);
 433 
 434         dnode_evict_bonus(dn);
 435 }
 436 
 437 void
 438 dnode_evict_bonus(dnode_t *dn)
 439 {
 440         rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
 441         if (dn->dn_bonus != NULL) {
 442                 if (refcount_is_zero(&dn->dn_bonus->db_holds)) {
 443                         mutex_enter(&dn->dn_bonus->db_mtx);
 444                         dbuf_evict(dn->dn_bonus);
 445                         dn->dn_bonus = NULL;
 446                 } else {
 447                         dn->dn_bonus->db_pending_evict = TRUE;
 448                 }
 449         }
 450         rw_exit(&dn->dn_struct_rwlock);
 451 }
 452 
 453 static void
 454 dnode_undirty_dbufs(list_t *list)
 455 {
 456         dbuf_dirty_record_t *dr;
 457 
 458         while (dr = list_head(list)) {
 459                 dmu_buf_impl_t *db = dr->dr_dbuf;
 460                 uint64_t txg = dr->dr_txg;
 461 
 462                 if (db->db_level != 0)
 463                         dnode_undirty_dbufs(&dr->dt.di.dr_children);
 464 
 465                 mutex_enter(&db->db_mtx);
 466                 /* XXX - use dbuf_undirty()? */
 467                 list_remove(list, dr);
 468                 ASSERT(db->db_last_dirty == dr);
 469                 db->db_last_dirty = NULL;


 480                 dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg);
 481         }
 482 }
 483 
 484 static void
 485 dnode_sync_free(dnode_t *dn, dmu_tx_t *tx)
 486 {
 487         int txgoff = tx->tx_txg & TXG_MASK;
 488 
 489         ASSERT(dmu_tx_is_syncing(tx));
 490 
 491         /*
 492          * Our contents should have been freed in dnode_sync() by the
 493          * free range record inserted by the caller of dnode_free().
 494          */
 495         ASSERT0(DN_USED_BYTES(dn->dn_phys));
 496         ASSERT(BP_IS_HOLE(dn->dn_phys->dn_blkptr));
 497 
 498         dnode_undirty_dbufs(&dn->dn_dirty_records[txgoff]);
 499         dnode_evict_dbufs(dn);

 500 
 501         /*
 502          * XXX - It would be nice to assert this, but we may still
 503          * have residual holds from async evictions from the arc...
 504          *
 505          * zfs_obj_to_path() also depends on this being
 506          * commented out.
 507          *
 508          * ASSERT3U(refcount_count(&dn->dn_holds), ==, 1);
 509          */
 510 
 511         /* Undirty next bits */
 512         dn->dn_next_nlevels[txgoff] = 0;
 513         dn->dn_next_indblkshift[txgoff] = 0;
 514         dn->dn_next_blksz[txgoff] = 0;
 515 
 516         /* ASSERT(blkptrs are zero); */
 517         ASSERT(dn->dn_phys->dn_type != DMU_OT_NONE);
 518         ASSERT(dn->dn_type != DMU_OT_NONE);
 519