summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--module/zfs/metaslab.c36
1 files changed, 25 insertions, 11 deletions
diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c
index 7ff1a4f5a..86bf3c197 100644
--- a/module/zfs/metaslab.c
+++ b/module/zfs/metaslab.c
@@ -2335,28 +2335,42 @@ top:
* figure out whether the corresponding vdev is
* over- or under-used relative to the pool,
* and set an allocation bias to even it out.
+ *
+ * Bias is also used to compensate for unequally
+ * sized vdevs so that space is allocated fairly.
*/
if (mc->mc_aliquot == 0 && metaslab_bias_enabled) {
vdev_stat_t *vs = &vd->vdev_stat;
- int64_t vu, cu;
-
- vu = (vs->vs_alloc * 100) / (vs->vs_space + 1);
- cu = (mc->mc_alloc * 100) / (mc->mc_space + 1);
+ int64_t vs_free = vs->vs_space - vs->vs_alloc;
+ int64_t mc_free = mc->mc_space - mc->mc_alloc;
+ int64_t ratio;
/*
* Calculate how much more or less we should
* try to allocate from this device during
* this iteration around the rotor.
- * For example, if a device is 80% full
- * and the pool is 20% full then we should
- * reduce allocations by 60% on this device.
*
- * mg_bias = (20 - 80) * 512K / 100 = -307K
+ * This basically introduces a zero-centered
+ * bias towards the devices with the most
+ * free space, while compensating for vdev
+ * size differences.
+ *
+ * Examples:
+ * vdev V1 = 16M/128M
+ * vdev V2 = 16M/128M
+ * ratio(V1) = 100% ratio(V2) = 100%
+ *
+ * vdev V1 = 16M/128M
+ * vdev V2 = 64M/128M
+ * ratio(V1) = 127% ratio(V2) = 72%
*
- * This reduces allocations by 307K for this
- * iteration.
+ * vdev V1 = 16M/128M
+ * vdev V2 = 64M/512M
+ * ratio(V1) = 40% ratio(V2) = 160%
*/
- mg->mg_bias = ((cu - vu) *
+ ratio = (vs_free * mc->mc_alloc_groups * 100) /
+ (mc_free + 1);
+ mg->mg_bias = ((ratio - 100) *
(int64_t)mg->mg_aliquot) / 100;
} else if (!metaslab_bias_enabled) {
mg->mg_bias = 0;