]> sourceware.org Git - lvm2.git/commitdiff
thin: calculate thin pool chunk size based on device IO hints
authorPeter Rajnoha <prajnoha@redhat.com>
Wed, 25 Sep 2013 14:01:47 +0000 (16:01 +0200)
committerPeter Rajnoha <prajnoha@redhat.com>
Wed, 25 Sep 2013 14:06:38 +0000 (16:06 +0200)
If "default" thin pool chunk size calculation method is selected,
use minimum_io_size, otherwise optimal_io_size for "performance"
device hint exposed in sysfs. If there appear to be PVs with
different hints presented, use their least common multiple.

If the hint is less than the default value defined for the
calculation method, use the default value instead.

lib/metadata/lv_manip.c

index d1ec4cda567c8f1fe01b18f3264c4e1bad293562..f945b7924e4090cb990904d6d166d07f63d209a6 100644 (file)
@@ -5510,6 +5510,72 @@ int lv_activation_skip(struct logical_volume *lv, activation_change_t activate,
        return (lv->status & LV_ACTIVATION_SKIP) ? 1 : 0;
 }
 
+/* Greatest common divisor */
+static unsigned long _gcd(unsigned long n1, unsigned long n2)
+{
+       unsigned long remainder;
+
+       do {
+               remainder = n1 % n2;
+               n1 = n2;
+               n2 = remainder;
+       } while (n2);
+
+       return n1;
+}
+
+/* Least common multiple */
+static unsigned long _lcm(unsigned long n1, unsigned long n2)
+{
+       if (!n1 || !n2)
+               return 0;
+       return (n1 * n2) / _gcd(n1, n2);
+}
+
+static int _recalculate_thin_pool_chunk_size_with_dev_hints(struct lvcreate_params *lp,
+                                                           struct logical_volume *pool_lv)
+{
+       struct logical_volume *pool_data_lv;
+       struct lv_segment *seg;
+       struct physical_volume *pv;
+       struct cmd_context *cmd = pool_lv->vg->cmd;
+       unsigned long previous_hint = 0, hint;
+       uint32_t chunk_size = lp->chunk_size;
+       uint32_t default_chunk_size = lp->thin_chunk_size_calc_method == THIN_CHUNK_SIZE_CALC_METHOD_PERFORMANCE ?
+                                       DEFAULT_THIN_POOL_CHUNK_SIZE_PERFORMANCE*2 : DEFAULT_THIN_POOL_CHUNK_SIZE*2;
+
+       if (lp->passed_args & PASS_ARG_CHUNK_SIZE ||
+           find_config_tree_int(cmd, allocation_thin_pool_chunk_size_CFG, NULL))
+               goto out;
+
+       pool_data_lv = seg_lv(first_seg(pool_lv), 0);
+
+       dm_list_iterate_items(seg, &pool_data_lv->segments) {
+               pv = seg_pv(seg, 0);
+               if (lp->thin_chunk_size_calc_method == THIN_CHUNK_SIZE_CALC_METHOD_PERFORMANCE)
+                       hint = dev_optimal_io_size(cmd->dev_types, pv_dev(pv));
+               else
+                       hint = dev_minimum_io_size(cmd->dev_types, pv_dev(pv));
+
+               if (!hint)
+                       continue;
+               if (previous_hint)
+                       hint = _lcm(previous_hint, hint);
+               previous_hint = hint;
+       }
+
+       if (hint < DM_THIN_MIN_DATA_BLOCK_SIZE ||
+           hint > DM_THIN_MAX_DATA_BLOCK_SIZE) {
+               log_debug_alloc("Calculated value of %ld sectors for thin pool "
+                               "chunk size is out of allowed range (%d-%d).",
+                               hint, DM_THIN_MIN_DATA_BLOCK_SIZE, DM_THIN_MAX_DATA_BLOCK_SIZE);
+       } else
+               chunk_size = hint >= default_chunk_size ? hint : default_chunk_size;
+out:
+       first_seg(pool_lv)->chunk_size = chunk_size;
+       return 1;
+}
+
 /* Thin notes:
  * If lp->thin OR lp->activate is AY*, activate the pool if not already active.
  * If lp->thin, create thin LV within the pool - as a snapshot if lp->snapshot.
@@ -5808,8 +5874,9 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
                return_NULL;
 
        if (seg_is_thin_pool(lp)) {
+               if (!_recalculate_thin_pool_chunk_size_with_dev_hints(lp, lv))
+                       return_NULL;
                first_seg(lv)->zero_new_blocks = lp->zero ? 1 : 0;
-               first_seg(lv)->chunk_size = lp->chunk_size;
                first_seg(lv)->discards = lp->discards;
                /* FIXME: use lowwatermark  via lvm.conf global for all thinpools ? */
                first_seg(lv)->low_water_mark = 0;
This page took 0.0534 seconds and 5 git commands to generate.