From f30c5a953d60af1850a2e625adcdcdc0d8580e38 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Sat, 30 Apr 2016 09:41:25 +0200 Subject: [PATCH 228/257] ZFS: Make dmu_tx_delay() immune to zfs_dirty_data_max_internal changes while it's running as it can result in underflows and possible deadlocks Obtained from: ElectroBSD --- sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c index 691a651c8ef7..bc006edc0f95 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c @@ -1107,10 +1107,11 @@ static void dmu_tx_delay(dmu_tx_t *tx, uint64_t dirty) { dsl_pool_t *dp = tx->tx_pool; - uint64_t delay_min_bytes = - zfs_dirty_data_max_internal * zfs_delay_min_dirty_percent / 100; + uint64_t delay_min_bytes; hrtime_t wakeup, min_tx_time, now; + uint64_t dirty_data_max = zfs_dirty_data_max_internal; + delay_min_bytes = dirty_data_max * zfs_delay_min_dirty_percent / 100; if (dirty <= delay_min_bytes) return; @@ -1120,15 +1121,15 @@ dmu_tx_delay(dmu_tx_t *tx, uint64_t dirty) * have to handle the case of it being >= the max, which could * cause a divide-by-zero if it's == the max. */ - ASSERT3U(dirty, <, zfs_dirty_data_max_internal); + ASSERT3U(dirty, <, dirty_data_max); now = gethrtime(); - if (dirty >= zfs_dirty_data_max_internal) {/* No scaling if overcommitted */ + if (dirty >= dirty_data_max) {/* No scaling if overcommitted */ min_tx_time = zfs_delay_scale * (dirty - delay_min_bytes); } else { min_tx_time = zfs_delay_scale * - (dirty - delay_min_bytes) / (zfs_dirty_data_max_internal - dirty); + (dirty - delay_min_bytes) / (dirty_data_max - dirty); } if (now > tx->tx_start + min_tx_time) return; -- 2.11.0