56
56
*/
57
57
int zfs_nopwrite_enabled = 1 ;
58
58
59
+ /*
60
+ * Tunable to control percentage of dirtied blocks from frees in one TXG.
61
+ * After this threshold is crossed, additional dirty blocks from frees
62
+ * wait until the next TXG.
63
+ * A value of zero will disable this throttle.
64
+ */
65
+ uint32_t zfs_per_txg_dirty_frees_percent = 30 ;
66
+
59
67
const dmu_object_type_info_t dmu_ot [DMU_OT_NUMTYPES ] = {
60
68
{ DMU_BSWAP_UINT8 , TRUE, "unallocated" },
61
69
{ DMU_BSWAP_ZAP , TRUE, "object directory" },
@@ -717,15 +725,25 @@ dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
717
725
{
718
726
uint64_t object_size = (dn -> dn_maxblkid + 1 ) * dn -> dn_datablksz ;
719
727
int err ;
728
+ uint64_t dirty_frees_threshold ;
729
+ dsl_pool_t * dp = dmu_objset_pool (os );
720
730
721
731
if (offset >= object_size )
722
732
return (0 );
723
733
734
+ if (zfs_per_txg_dirty_frees_percent <= 100 )
735
+ dirty_frees_threshold =
736
+ zfs_per_txg_dirty_frees_percent * zfs_dirty_data_max / 100 ;
737
+ else
738
+ dirty_frees_threshold = zfs_dirty_data_max / 4 ;
739
+
724
740
if (length == DMU_OBJECT_END || offset + length > object_size )
725
741
length = object_size - offset ;
726
742
727
743
while (length != 0 ) {
728
- uint64_t chunk_end , chunk_begin ;
744
+ uint64_t chunk_end , chunk_begin , chunk_len ;
745
+ uint64_t long_free_dirty_all_txgs = 0 ;
746
+ dmu_tx_t * tx ;
729
747
730
748
if (dmu_objset_zfs_unmounting (dn -> dn_objset ))
731
749
return (SET_ERROR (EINTR ));
@@ -739,9 +757,28 @@ dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
739
757
ASSERT3U (chunk_begin , >=, offset );
740
758
ASSERT3U (chunk_begin , <=, chunk_end );
741
759
742
- dmu_tx_t * tx = dmu_tx_create (os );
743
- dmu_tx_hold_free (tx , dn -> dn_object ,
744
- chunk_begin , chunk_end - chunk_begin );
760
+ chunk_len = chunk_end - chunk_begin ;
761
+
762
+ mutex_enter (& dp -> dp_lock );
763
+ for (int t = 0 ; t < TXG_SIZE ; t ++ ) {
764
+ long_free_dirty_all_txgs +=
765
+ dp -> dp_long_free_dirty_pertxg [t ];
766
+ }
767
+ mutex_exit (& dp -> dp_lock );
768
+
769
+ /*
770
+ * To avoid filling up a TXG with just frees wait for
771
+ * the next TXG to open before freeing more chunks if
772
+ * we have reached the threshold of frees
773
+ */
774
+ if (dirty_frees_threshold != 0 &&
775
+ long_free_dirty_all_txgs >= dirty_frees_threshold ) {
776
+ txg_wait_open (dp , 0 );
777
+ continue ;
778
+ }
779
+
780
+ tx = dmu_tx_create (os );
781
+ dmu_tx_hold_free (tx , dn -> dn_object , chunk_begin , chunk_len );
745
782
746
783
/*
747
784
* Mark this transaction as typically resulting in a net
@@ -753,10 +790,18 @@ dmu_free_long_range_impl(objset_t *os, dnode_t *dn, uint64_t offset,
753
790
dmu_tx_abort (tx );
754
791
return (err );
755
792
}
756
- dnode_free_range (dn , chunk_begin , chunk_end - chunk_begin , tx );
793
+
794
+ mutex_enter (& dp -> dp_lock );
795
+ dp -> dp_long_free_dirty_pertxg [dmu_tx_get_txg (tx ) & TXG_MASK ] +=
796
+ chunk_len ;
797
+ mutex_exit (& dp -> dp_lock );
798
+ DTRACE_PROBE3 (free__long__range ,
799
+ uint64_t , long_free_dirty_all_txgs , uint64_t , chunk_len ,
800
+ uint64_t , dmu_tx_get_txg (tx ));
801
+ dnode_free_range (dn , chunk_begin , chunk_len , tx );
757
802
dmu_tx_commit (tx );
758
803
759
- length -= chunk_end - chunk_begin ;
804
+ length -= chunk_len ;
760
805
}
761
806
return (0 );
762
807
}
0 commit comments