From fb14661532fcbe89327cad6b5b1d24c7386f211f Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Wed, 27 Apr 2016 10:48:23 +0200 Subject: [PATCH 230/257] ZFS: Make the dynamic write buffer more effective for memory-constrained systems - Remove the previously hardcoded 256 MB lower limit which is far too much for systems with 2 GB of RAM or less. - Prevent an integer underflow if the free count is below the free target. The vm seems to treat vm_cnt.v_free_target more like a guide line than a rule, and it's unsafe to assume that it will always be below the vm_cnt.v_free_count. (kgdb) p zfs_dirty_data_max_internal $8 = 10000000 (kgdb) p vm_cnt.v_free_count - vm_cnt.v_free_target $9 = 18446744073709546294 (kgdb) p vm_cnt.v_free_count $10 = 2 (kgdb) p vm_cnt.v_free_target $11 = 5324 If the free count is below the target, use half the free count as limit instead. There is probably a more appropriate limit, but for now this has to do. Obtained from: ElectroBSD --- .../contrib/opensolaris/uts/common/fs/zfs/dmu_tx.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 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 bc006edc0f95..f1a0688cb1b3 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 @@ -1350,16 +1350,16 @@ dmu_tx_assign(dmu_tx_t *tx, txg_how_t txg_how) #ifdef _KERNEL /* - * KD 2014-09-22 * If UMA is enabled it can only return a previously-used block - * of identical size to what it had out before. If it's not the + * of identical size to what it had out before. If it's not the * same size it will allocate a new one. This is a problem because * dirty_data_max is the total dirty write data allowed out at any * given time, but with UMA on that can multiply by the number of * different block sizes (!!) requested in terms of free RAM that * is left allocated but unused. For this reason never allow * dirty_data_max to exceed the difference between the paging - * threshold and the current free memory, with a minimum of 256MB. + * threshold and the current free memory. + * * This throttles "burst" allocations and prevents the system from * choking during times of high write I/O demand. * @@ -1368,13 +1368,17 @@ dmu_tx_assign(dmu_tx_t *tx, txg_how_t txg_how) * * Note that we work on the zfs_dirty_data_max_internal variable, * because the user may set zfs_dirty_data_max himself and we must - * must honor that as a hard cap so it remains a usable tunable value. + * honor that as a hard cap so it remains a usable tunable value. */ if (zio_use_uma && zfs_dynamic_write_buffer) { - zfs_dirty_data_max_internal = 1 << 28; - zfs_dirty_data_max_internal = MAX(zfs_dirty_data_max_internal, ptob(vm_cnt.v_free_count - vm_cnt.v_free_target)); - zfs_dirty_data_max_internal = MIN(zfs_dirty_data_max_internal, zfs_dirty_data_max); - zfs_dirty_data_max_internal = MIN(zfs_dirty_data_max_internal, zfs_dirty_data_max_max); + zfs_dirty_data_max_internal = MIN(zfs_dirty_data_max, zfs_dirty_data_max_max); + if (vm_cnt.v_free_count > vm_cnt.v_free_target) { + zfs_dirty_data_max_internal = MIN(zfs_dirty_data_max_internal, + ptob(vm_cnt.v_free_count - vm_cnt.v_free_target)); + } else { + zfs_dirty_data_max_internal = MIN(zfs_dirty_data_max_internal, + ptob(vm_cnt.v_free_count / 2)); + } if (last_max != (zfs_dirty_data_max_internal / (1024 * 1024))) { last_max = zfs_dirty_data_max_internal / (1024 * 1024); DTRACE_PROBE1(dmu__tx_dirty, uint64_t, last_max); -- 2.11.0