@@ -691,6 +691,14 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
691
691
if (!havepzio )
692
692
err = zio_wait (zio );
693
693
} else {
694
+ /*
695
+ * Another reader came in while the dbuf was in flight
696
+ * between UNCACHED and CACHED. Either a writer will finish
697
+ * writing the buffer (sending the dbuf to CACHED) or the
698
+ * first reader's request will reach the read_done callback
699
+ * and send the dbuf to CACHED. Otherwise, a failure
700
+ * occurred and the dbuf went to UNCACHED.
701
+ */
694
702
mutex_exit (& db -> db_mtx );
695
703
if (prefetch )
696
704
dmu_zfetch (& dn -> dn_zfetch , db -> db .db_offset ,
@@ -699,6 +707,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
699
707
rw_exit (& dn -> dn_struct_rwlock );
700
708
DB_DNODE_EXIT (db );
701
709
710
+ /* Skip the wait per the caller's request. */
702
711
mutex_enter (& db -> db_mtx );
703
712
if ((flags & DB_RF_NEVERWAIT ) == 0 ) {
704
713
while (db -> db_state == DB_READ ||
@@ -1313,7 +1322,8 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
1313
1322
}
1314
1323
1315
1324
/*
1316
- * Return TRUE if this evicted the dbuf.
1325
+ * Undirty a buffer in the transaction group referenced by the given
1326
+ * transaction. Return whether this evicted the dbuf.
1317
1327
*/
1318
1328
static boolean_t
1319
1329
dbuf_undirty (dmu_buf_impl_t * db , dmu_tx_t * tx )
@@ -2324,6 +2334,7 @@ dbuf_sync_indirect(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
2324
2334
ASSERT (db -> db_level > 0 );
2325
2335
DBUF_VERIFY (db );
2326
2336
2337
+ /* Read the block if it hasn't been read yet. */
2327
2338
if (db -> db_buf == NULL ) {
2328
2339
mutex_exit (& db -> db_mtx );
2329
2340
(void ) dbuf_read (db , NULL , DB_RF_MUST_SUCCEED );
@@ -2334,10 +2345,12 @@ dbuf_sync_indirect(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
2334
2345
2335
2346
DB_DNODE_ENTER (db );
2336
2347
dn = DB_DNODE (db );
2348
+ /* Indirect block size must match what the dnode thinks it is. */
2337
2349
ASSERT3U (db -> db .db_size , = = , 1 <<dn -> dn_phys -> dn_indblkshift );
2338
2350
dbuf_check_blkptr (dn , db );
2339
2351
DB_DNODE_EXIT (db );
2340
2352
2353
+ /* Provide the pending dirty record to child dbufs */
2341
2354
db -> db_data_pending = dr ;
2342
2355
2343
2356
mutex_exit (& db -> db_mtx );
@@ -2728,6 +2741,7 @@ dbuf_write_override_done(zio_t *zio)
2728
2741
dbuf_write_done (zio , NULL , db );
2729
2742
}
2730
2743
2744
+ /* Issue I/O to commit a dirty buffer to disk. */
2731
2745
static void
2732
2746
dbuf_write (dbuf_dirty_record_t * dr , arc_buf_t * data , dmu_tx_t * tx )
2733
2747
{
@@ -2762,11 +2776,19 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
2762
2776
}
2763
2777
2764
2778
if (parent != dn -> dn_dbuf ) {
2779
+ /* Our parent is an indirect block. */
2780
+ /* We have a dirty parent that has been scheduled for write. */
2765
2781
ASSERT (parent && parent -> db_data_pending );
2782
+ /* Our parent's buffer is one level closer to the dnode. */
2766
2783
ASSERT (db -> db_level == parent -> db_level - 1 );
2784
+ /*
2785
+ * We're about to modify our parent's db_data by modifying
2786
+ * our block pointer, so the parent must be released.
2787
+ */
2767
2788
ASSERT (arc_released (parent -> db_buf ));
2768
2789
zio = parent -> db_data_pending -> dr_zio ;
2769
2790
} else {
2791
+ /* Our parent is the dnode itself. */
2770
2792
ASSERT ((db -> db_level == dn -> dn_phys -> dn_nlevels - 1 &&
2771
2793
db -> db_blkid != DMU_SPILL_BLKID ) ||
2772
2794
(db -> db_blkid == DMU_SPILL_BLKID && db -> db_level == 0 ));
0 commit comments