@@ -543,13 +543,50 @@ dbuf_verify(dmu_buf_impl_t *db)
543
543
* If the blkptr isn't set but they have nonzero data,
544
544
* it had better be dirty, otherwise we'll lose that
545
545
* data when we evict this buffer.
546
+ *
547
+ * There is an exception to this rule for indirect blocks; in
548
+ * this case, if the indirect block is a hole, we fill in a few
549
+ * fields on each of the child blocks (importantly, birth time)
550
+ * to prevent hole birth times from being lost when you
551
+ * partially fill in a hole.
546
552
*/
547
553
if (db -> db_dirtycnt == 0 ) {
548
- ASSERTV (uint64_t * buf = db -> db .db_data );
549
- int i ;
554
+ if (db -> db_level == 0 ) {
555
+ uint64_t * buf = db -> db .db_data ;
556
+ int i ;
550
557
551
- for (i = 0 ; i < db -> db .db_size >> 3 ; i ++ ) {
552
- ASSERT (buf [i ] == 0 );
558
+ for (i = 0 ; i < db -> db .db_size >> 3 ; i ++ ) {
559
+ ASSERT (buf [i ] == 0 );
560
+ }
561
+ } else {
562
+ int i ;
563
+ blkptr_t * bps = db -> db .db_data ;
564
+ ASSERT3U (1 << DB_DNODE (db )-> dn_indblkshift , = = ,
565
+ db -> db .db_size );
566
+ /*
567
+ * We want to verify that all the blkptrs in the
568
+ * indirect block are holes, but we may have
569
+ * automatically set up a few fields for them.
570
+ * We iterate through each blkptr and verify
571
+ * they only have those fields set.
572
+ */
573
+ for (i = 0 ;
574
+ i < db -> db .db_size / sizeof (blkptr_t );
575
+ i ++ ) {
576
+ blkptr_t * bp = & bps [i ];
577
+ ASSERT (ZIO_CHECKSUM_IS_ZERO (
578
+ & bp -> blk_cksum ));
579
+ ASSERT (
580
+ DVA_IS_EMPTY (& bp -> blk_dva [0 ]) &&
581
+ DVA_IS_EMPTY (& bp -> blk_dva [1 ]) &&
582
+ DVA_IS_EMPTY (& bp -> blk_dva [2 ]));
583
+ ASSERT0 (bp -> blk_fill );
584
+ ASSERT0 (bp -> blk_pad [0 ]);
585
+ ASSERT0 (bp -> blk_pad [1 ]);
586
+ ASSERT (!BP_IS_EMBEDDED (bp ));
587
+ ASSERT (BP_IS_HOLE (bp ));
588
+ ASSERT0 (bp -> blk_phys_birth );
589
+ }
553
590
}
554
591
}
555
592
}
@@ -718,10 +755,32 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags)
718
755
BP_IS_HOLE (db -> db_blkptr )))) {
719
756
arc_buf_contents_t type = DBUF_GET_BUFC_TYPE (db );
720
757
721
- DB_DNODE_EXIT (db );
722
758
dbuf_set_data (db , arc_buf_alloc (db -> db_objset -> os_spa ,
723
759
db -> db .db_size , db , type ));
724
760
bzero (db -> db .db_data , db -> db .db_size );
761
+
762
+ if (db -> db_blkptr != NULL && db -> db_level > 0 &&
763
+ BP_IS_HOLE (db -> db_blkptr ) &&
764
+ db -> db_blkptr -> blk_birth != 0 ) {
765
+ blkptr_t * bps = db -> db .db_data ;
766
+ int i ;
767
+ for (i = 0 ; i < ((1 <<
768
+ DB_DNODE (db )-> dn_indblkshift ) / sizeof (blkptr_t ));
769
+ i ++ ) {
770
+ blkptr_t * bp = & bps [i ];
771
+ ASSERT3U (BP_GET_LSIZE (db -> db_blkptr ), = = ,
772
+ 1 << dn -> dn_indblkshift );
773
+ BP_SET_LSIZE (bp ,
774
+ BP_GET_LEVEL (db -> db_blkptr ) == 1 ?
775
+ dn -> dn_datablksz :
776
+ BP_GET_LSIZE (db -> db_blkptr ));
777
+ BP_SET_TYPE (bp , BP_GET_TYPE (db -> db_blkptr ));
778
+ BP_SET_LEVEL (bp ,
779
+ BP_GET_LEVEL (db -> db_blkptr ) - 1 );
780
+ BP_SET_BIRTH (bp , db -> db_blkptr -> blk_birth , 0 );
781
+ }
782
+ }
783
+ DB_DNODE_EXIT (db );
725
784
db -> db_state = DB_CACHED ;
726
785
mutex_exit (& db -> db_mtx );
727
786
return (0 );
@@ -3094,6 +3153,45 @@ dbuf_write_ready(zio_t *zio, arc_buf_t *buf, void *vdb)
3094
3153
rw_exit (& dn -> dn_struct_rwlock );
3095
3154
}
3096
3155
3156
+ /* ARGSUSED */
3157
+ /*
3158
+ * This function gets called just prior to running through the compression
3159
+ * stage of the zio pipeline. If we're an indirect block comprised of only
3160
+ * holes, then we want this indirect to be compressed away to a hole. In
3161
+ * order to do that we must zero out any information about the holes that
3162
+ * this indirect points to prior to before we try to compress it.
3163
+ */
3164
+ static void
3165
+ dbuf_write_children_ready (zio_t * zio , arc_buf_t * buf , void * vdb )
3166
+ {
3167
+ dmu_buf_impl_t * db = vdb ;
3168
+ dnode_t * dn ;
3169
+ blkptr_t * bp ;
3170
+ uint64_t i ;
3171
+ int epbs ;
3172
+
3173
+ ASSERT3U (db -> db_level , > , 0 );
3174
+ DB_DNODE_ENTER (db );
3175
+ dn = DB_DNODE (db );
3176
+ epbs = dn -> dn_phys -> dn_indblkshift - SPA_BLKPTRSHIFT ;
3177
+
3178
+ /* Determine if all our children are holes */
3179
+ for (i = 0 , bp = db -> db .db_data ; i < 1 << epbs ; i ++ , bp ++ ) {
3180
+ if (!BP_IS_HOLE (bp ))
3181
+ break ;
3182
+ }
3183
+
3184
+ /*
3185
+ * If all the children are holes, then zero them all out so that
3186
+ * we may get compressed away.
3187
+ */
3188
+ if (i == 1 << epbs ) {
3189
+ /* didn't find any non-holes */
3190
+ bzero (db -> db .db_data , db -> db .db_size );
3191
+ }
3192
+ DB_DNODE_EXIT (db );
3193
+ }
3194
+
3097
3195
/*
3098
3196
* The SPA will call this callback several times for each zio - once
3099
3197
* for every physical child i/o (zio->io_phys_children times). This
@@ -3348,7 +3446,8 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
3348
3446
3349
3447
dr -> dr_zio = zio_write (zio , os -> os_spa , txg ,
3350
3448
& dr -> dr_bp_copy , contents , db -> db .db_size , & zp ,
3351
- dbuf_write_override_ready , NULL , dbuf_write_override_done ,
3449
+ dbuf_write_override_ready , NULL , NULL ,
3450
+ dbuf_write_override_done ,
3352
3451
dr , ZIO_PRIORITY_ASYNC_WRITE , ZIO_FLAG_MUSTSUCCEED , & zb );
3353
3452
mutex_enter (& db -> db_mtx );
3354
3453
dr -> dt .dl .dr_override_state = DR_NOT_OVERRIDDEN ;
@@ -3359,14 +3458,26 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
3359
3458
ASSERT (zp .zp_checksum == ZIO_CHECKSUM_OFF );
3360
3459
dr -> dr_zio = zio_write (zio , os -> os_spa , txg ,
3361
3460
& dr -> dr_bp_copy , NULL , db -> db .db_size , & zp ,
3362
- dbuf_write_nofill_ready , NULL , dbuf_write_nofill_done , db ,
3461
+ dbuf_write_nofill_ready , NULL , NULL ,
3462
+ dbuf_write_nofill_done , db ,
3363
3463
ZIO_PRIORITY_ASYNC_WRITE ,
3364
3464
ZIO_FLAG_MUSTSUCCEED | ZIO_FLAG_NODATA , & zb );
3365
3465
} else {
3466
+ arc_done_func_t * children_ready_cb = NULL ;
3366
3467
ASSERT (arc_released (data ));
3468
+
3469
+ /*
3470
+ * For indirect blocks, we want to setup the children
3471
+ * ready callback so that we can properly handle an indirect
3472
+ * block that only contains holes.
3473
+ */
3474
+ if (db -> db_level != 0 )
3475
+ children_ready_cb = dbuf_write_children_ready ;
3476
+
3367
3477
dr -> dr_zio = arc_write (zio , os -> os_spa , txg ,
3368
3478
& dr -> dr_bp_copy , data , DBUF_IS_L2CACHEABLE (db ),
3369
3479
DBUF_IS_L2COMPRESSIBLE (db ), & zp , dbuf_write_ready ,
3480
+ children_ready_cb ,
3370
3481
dbuf_write_physdone , dbuf_write_done , db ,
3371
3482
ZIO_PRIORITY_ASYNC_WRITE , ZIO_FLAG_MUSTSUCCEED , & zb );
3372
3483
}
0 commit comments