diff options
author | Matthew Ahrens <[email protected]> | 2018-02-26 15:33:55 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2018-05-24 10:18:07 -0700 |
commit | 0dc2f70c5cece6ef2474e14552111ae098d9f5b4 (patch) | |
tree | 8414edcb42c28aecbc4e9422eb02d15d7e98d035 /module/zfs/vdev_indirect.c | |
parent | ba863d0be4cbfbea938b10e49fb6ff459ac9ec20 (diff) |
OpenZFS 9486 - reduce memory used by device removal on fragmented pools
Device removal allocates a new location for each allocated segment on
the disk that's being removed. Each allocation results in one entry in
the mapping table, which maps from old location + length to new
location. When a fragmented disk is removed, this can result in a large
number of mapping entries, and thus a large amount of memory consumed by
the mapping table. In the worst real-world cases, we've seen around 1GB
of RAM per 1TB of storage removed.
We can improve on this situation by allocating larger segments, which
span across both allocated and free regions of the device being removed.
By including free regions in the allocation (and thus mapping), we
reduce the number of mapping entries. For example, if we have a 4K
allocation followed by 1K free and then 4K allocated, we would allocate
4+1+4 = 9KB, and then move the entire region (including allocated and
free parts). In this case we used one mapping where previously we would
have used two, but often the ratio is much higher (up to 20:1 in
real-world use). We then need to mark the regions that were free on the
removing device as free in the new locations, and also obsolete in the
mapping entry.
This method preserves the fragmentation of the removing device, rather
than consolidating its allocated space into a small number of chunks
where possible. But it results in drastic reduction of memory used by
the mapping table - around 20x in the most-fragmented cases.
In the most fragmented real-world cases, this reduces memory used by the
mapping from ~1GB to ~50MB of RAM per 1TB of storage removed. Less
fragmented cases will typically also see around 50-100MB of RAM per 1TB
of storage.
Porting notes:
* Add the following as module parameters:
* zfs_condense_indirect_vdevs_enable
* zfs_condense_max_obsolete_bytes
* Document the following module parameters:
* zfs_condense_indirect_vdevs_enable
* zfs_condense_max_obsolete_bytes
* zfs_condense_min_mapping_bytes
Authored by: Matthew Ahrens <[email protected]>
Reviewed by: Brian Behlendorf <[email protected]>
Ported-by: Tim Chase <[email protected]>
Signed-off-by: Tim Chase <[email protected]>
OpenZFS-issue: https://illumos.org/issues/9486
OpenZFS-commit: https://github.com/ahrens/illumos/commit/07152e142e44c
External-issue: DLPX-57962
Closes #7536
Diffstat (limited to 'module/zfs/vdev_indirect.c')
-rw-r--r-- | module/zfs/vdev_indirect.c | 13 |
1 files changed, 11 insertions, 2 deletions
diff --git a/module/zfs/vdev_indirect.c b/module/zfs/vdev_indirect.c index 0a42f5196..ff0968384 100644 --- a/module/zfs/vdev_indirect.c +++ b/module/zfs/vdev_indirect.c @@ -171,7 +171,7 @@ * object. */ -boolean_t zfs_condense_indirect_vdevs_enable = B_TRUE; +int zfs_condense_indirect_vdevs_enable = B_TRUE; /* * Condense if at least this percent of the bytes in the mapping is @@ -188,7 +188,7 @@ int zfs_indirect_condense_obsolete_pct = 25; * consumed by the obsolete space map; the default of 1GB is small enough * that we typically don't mind "wasting" it. */ -uint64_t zfs_condense_max_obsolete_bytes = 1024 * 1024 * 1024; +unsigned long zfs_condense_max_obsolete_bytes = 1024 * 1024 * 1024; /* * Don't bother condensing if the mapping uses less than this amount of @@ -1700,11 +1700,20 @@ EXPORT_SYMBOL(vdev_indirect_sync_obsolete); EXPORT_SYMBOL(vdev_obsolete_counts_are_precise); EXPORT_SYMBOL(vdev_obsolete_sm_object); +module_param(zfs_condense_indirect_vdevs_enable, int, 0644); +MODULE_PARM_DESC(zfs_condense_indirect_vdevs_enable, + "Whether to attempt condensing indirect vdev mappings"); + /* CSTYLED */ module_param(zfs_condense_min_mapping_bytes, ulong, 0644); MODULE_PARM_DESC(zfs_condense_min_mapping_bytes, "Minimum size of vdev mapping to condense"); +/* CSTYLED */ +module_param(zfs_condense_max_obsolete_bytes, ulong, 0644); +MODULE_PARM_DESC(zfs_condense_max_obsolete_bytes, + "Minimum size obsolete spacemap to attempt condensing"); + module_param(zfs_condense_indirect_commit_entry_delay_ms, int, 0644); MODULE_PARM_DESC(zfs_condense_indirect_commit_entry_delay_ms, "Delay while condensing vdev mapping"); |