diff options
author | David Teigland <teigland@redhat.com> | 2020-02-05 13:42:36 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2020-02-05 13:42:36 -0600 |
commit | ab4efab8568804b73492e3c719834b196de3fb0e (patch) | |
tree | f3bfcb5640fe79294b765d6ef418fa1ceeb60c09 | |
parent | 2a6078f96168e860474b42c42b1924fc353c4558 (diff) | |
download | lvm2-dev-dct-lvconvert-cache.tar.gz |
lvconvert: single step cachevol creation and attachmentdev-dct-lvconvert-cache
To add a cache or writecache to a main LV with a single command, run:
$ lvconvert --type cache|writecache --cachedevice /dev/ssd vg/main
-rw-r--r-- | tools/args.h | 6 | ||||
-rw-r--r-- | tools/command-lines.in | 14 | ||||
-rw-r--r-- | tools/lvconvert.c | 230 | ||||
-rw-r--r-- | tools/lvmcmdline.c | 2 |
4 files changed, 201 insertions, 51 deletions
diff --git a/tools/args.h b/tools/args.h index 999d891f7..96cb68a24 100644 --- a/tools/args.h +++ b/tools/args.h @@ -126,6 +126,12 @@ arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0, arg(cachevol_ARG, '\0', "cachevol", lv_VAL, 0, 0, "The name of a cache volume.\n") +arg(cachedevice_ARG, '\0', "cachedevice", pv_VAL, 0, 0, + "The name of a device to use for a cache.\n") + +arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0, + "The size of cache to use.\n") + arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0, "The command profile to use for command configuration.\n" "See \\fBlvm.conf\\fP(5) for more information about profiles.\n") diff --git a/tools/command-lines.in b/tools/command-lines.in index 37a01cb55..6ff00c2e6 100644 --- a/tools/command-lines.in +++ b/tools/command-lines.in @@ -492,6 +492,20 @@ FLAGS: SECONDARY_SYNTAX --- +lvconvert --type writecache --cachedevice PV LV +OO: OO_LVCONVERT, --cachesize SizeMB, --cachesettings String +ID: lvconvert_to_writecache_with_device +DESC: Add a writecache to an LV, using a specified fast device. +RULE: all and lv_is_visible + +lvconvert --type cache --cachedevice PV LV +OO: OO_LVCONVERT, --cachesize SizeMB, --cachesettings String +ID: lvconvert_to_cache_with_device +DESC: Add a read-write cache to an LV, using a specified fast device. +RULE: all and lv_is_visible + +--- + lvconvert --type thin-pool LV_linear_striped_raid_cache OO: --stripes_long Number, --stripesize SizeKB, --discards Discards, OO_LVCONVERT_POOL, OO_LVCONVERT diff --git a/tools/lvconvert.c b/tools/lvconvert.c index f6a329b22..3c86c5c8d 100644 --- a/tools/lvconvert.c +++ b/tools/lvconvert.c @@ -4219,46 +4219,153 @@ int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv) NULL, NULL, &_lvconvert_to_pool_single); } +static int _lv_create_cachevol(struct cmd_context *cmd, + struct volume_group *vg, + struct logical_volume *lv, + const char *dev_name, + struct logical_volume **cachevol_lv) +{ + char cvname[NAME_LEN]; + struct device *dev_fast; + struct dm_list *use_pvh; + uint64_t cache_size_sectors; + struct logical_volume *cachevol; + struct pv_list *pvl; + struct lvcreate_params lp = { + .activate = CHANGE_AN, + .alloc = ALLOC_INHERIT, + .major = -1, + .minor = -1, + .permission = LVM_READ | LVM_WRITE, + .pvh = &vg->pvs, + .read_ahead = DM_READ_AHEAD_NONE, + .stripes = 1, + .vg_name = vg->name, + .zero = 0, + .wipe_signatures = 0, + .suppress_zero_warn = 1, + }; + + if (dm_snprintf(cvname, NAME_LEN, "%s_cache", lv->name) < 0) { + log_error("Failed to create cachevol LV name."); + return 0; + } + + if (!(dev_fast = dev_cache_get(cmd, dev_name, cmd->filter))) { + log_error("Device %s not found.", dev_name); + return 0; + } + + if (!(pvl = find_pv_in_vg(vg, dev_name))) { + log_error("PV %s not found in VG.", dev_name); + return 0; + } + + /* + * If fast_dev is used in the VG, then require a cachesize to allocate + * from it. If fast_dev is not used in the VG, then prompt asking if + * the entire dev should be used. + */ + if (!(cache_size_sectors = arg_uint64_value(cmd, cachesize_ARG, 0))) { + if (pvl->pv->pe_alloc_count) { + log_error("PV %s is in use, --cachesize is required.", dev_name); + return 0; + } + + cache_size_sectors = (pvl->pv->pe_count * vg->extent_size); + + if (!arg_is_set(cmd, yes_ARG) && + yes_no_prompt("Use all %s from %s for cache? [y/n]: ", + display_size(cmd, cache_size_sectors), dev_name) == 'n') { + log_error("Conversion aborted."); + return 0; + } + } + + if (!(use_pvh = create_pv_list(cmd->mem, vg, 1, (char **)&dev_name, 1))) { + log_error("cachedevice not found in VG %s.", dev_name); + return 0; + } + + lp.lv_name = cvname; + lp.pvh = use_pvh; + lp.extents = cache_size_sectors / vg->extent_size; + + log_print("Creating cachevol LV %s with size %s.", + cvname, display_size(cmd, cache_size_sectors)); + + dm_list_init(&lp.tags); + + if (!(lp.segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED))) + return_0; + + if (!(cachevol = lv_create_single(vg, &lp))) { + log_error("Failed to create cachevol LV"); + return 0; + } + + *cachevol_lv = cachevol; + return 1; +} + static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd, struct logical_volume *lv, struct processing_handle *handle) { struct volume_group *vg = lv->vg; - struct logical_volume *cachevol_lv; - const char *cachevol_name; + struct logical_volume *lv_fast; + const char *fast_name, *dev_name; - if (!(cachevol_name = arg_str_value(cmd, cachevol_ARG, NULL))) - goto_out; + fast_name = arg_str_value(cmd, cachevol_ARG, NULL); + dev_name = arg_str_value(cmd, cachedevice_ARG, NULL); - if (!validate_lvname_param(cmd, &vg->name, &cachevol_name)) - goto_out; + if (!fast_name && !dev_name) + goto_bad; - if (!(cachevol_lv = find_lv(vg, cachevol_name))) { - log_error("Cache single %s not found.", cachevol_name); - goto out; - } + if (fast_name && dev_name) + goto_bad; - /* Ensure the LV is not active elsewhere. */ - if (!lockd_lv(cmd, lv, "ex", 0)) - goto_out; + /* + * User specifies an existing cachevol to use. + */ + if (fast_name) { + if (!validate_lvname_param(cmd, &vg->name, &fast_name)) + goto_bad; - if (!dm_list_empty(&cachevol_lv->segs_using_this_lv)) { - log_error("LV %s is already in use.", display_lvname(cachevol_lv)); - goto out; + if (!(lv_fast = find_lv(vg, fast_name))) { + log_error("LV %s not found.", fast_name); + goto bad; + } + + if (!dm_list_empty(&lv_fast->segs_using_this_lv)) { + log_error("LV %s is already in use.", display_lvname(lv_fast)); + goto bad; + } + + if (!arg_is_set(cmd, yes_ARG) && + yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') { + log_error("Conversion aborted."); + goto bad; + } + + if (!lockd_lv(cmd, lv_fast, "ex", 0)) + goto_bad; } - if (!arg_is_set(cmd, yes_ARG) && - yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(cachevol_lv)) == 'n') { - log_error("Conversion aborted."); - goto out; + /* + * User specifies a device and lvm creates a cachevol on it. + */ + if (dev_name) { + if (!_lv_create_cachevol(cmd, vg, lv, dev_name, &lv_fast)) + goto_bad; } /* Ensure the LV is not active elsewhere. */ - if (!lockd_lv(cmd, cachevol_lv, "ex", LDLV_PERSISTENT)) - goto_out; + if (!lockd_lv(cmd, lv, "ex", 0)) + goto_bad; - if (!wipe_cache_pool(cachevol_lv)) - goto_out; + if (!wipe_cache_pool(lv_fast)) + goto_bad; /* When the lv arg is a thinpool, redirect command to data sub lv. */ @@ -4268,17 +4375,17 @@ static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd, } if (_raid_split_image_conversion(lv)) - goto_out; + goto_bad; /* Attach the cache to the main LV. */ - if (!_cache_vol_attach(cmd, lv, cachevol_lv)) - goto_out; + if (!_cache_vol_attach(cmd, lv, lv_fast)) + goto_bad; log_print_unless_silent("Logical volume %s is now cached.", display_lvname(lv)); return ECMD_PROCESSED; - out: + bad: return ECMD_FAILED; } @@ -5564,29 +5671,58 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd, struct logical_volume *lv_wcorig; struct logical_volume *lv_fast; struct writecache_settings settings; - const char *fast_name; + const char *fast_name, *dev_name; uint32_t block_size_sectors; char *lockd_fast_args = NULL; char *lockd_fast_name = NULL; struct id lockd_fast_id; char cvol_name[NAME_LEN]; - fast_name = arg_str_value(cmd, cachevol_ARG, ""); + fast_name = arg_str_value(cmd, cachevol_ARG, NULL); + dev_name = arg_str_value(cmd, cachedevice_ARG, NULL); - if (!(lv_fast = find_lv(vg, fast_name))) { - log_error("LV %s not found.", fast_name); - goto bad; - } + if (!fast_name && !dev_name) + goto_bad; - if (!seg_is_linear(first_seg(lv_fast))) { - log_error("LV %s must be linear to use as a writecache.", display_lvname(lv_fast)); - return 0; + /* + * User specifies an existing cachevol to use. + */ + if (fast_name) { + if (!validate_lvname_param(cmd, &vg->name, &fast_name)) + goto_bad; + + if (!(lv_fast = find_lv(vg, fast_name))) { + log_error("LV %s not found.", fast_name); + goto_bad; + } + + if (!seg_is_linear(first_seg(lv_fast))) { + log_error("LV %s must be linear to use as a writecache.", display_lvname(lv_fast)); + goto_bad; + } + + /* fast LV shouldn't generally be active by itself, but just in case. */ + if (lv_info(cmd, lv_fast, 1, NULL, 0, 0)) { + log_error("LV %s must be inactive to attach.", display_lvname(lv_fast)); + goto_bad; + } + + if (!arg_is_set(cmd, yes_ARG) && + yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') { + log_error("Conversion aborted."); + goto_bad; + } + + if (!lockd_lv(cmd, lv_fast, "ex", 0)) + goto_bad; } - /* fast LV shouldn't generally be active by itself, but just in case. */ - if (lv_info(cmd, lv_fast, 1, NULL, 0, 0)) { - log_error("LV %s must be inactive to attach.", display_lvname(lv_fast)); - return 0; + /* + * User specifies a device and lvm creates a cachevol on it. + */ + if (dev_name) { + if (!_lv_create_cachevol(cmd, vg, lv, dev_name, &lv_fast)) + goto_bad; } memset(&settings, 0, sizeof(settings)); @@ -5594,20 +5730,12 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd, if (!_get_writecache_settings(cmd, &settings, &block_size_sectors)) { log_error("Invalid writecache settings."); - return 0; - } - - if (!arg_is_set(cmd, yes_ARG) && - yes_no_prompt("Erase all existing data on %s? [y/n]: ", display_lvname(lv_fast)) == 'n') { - log_error("Conversion aborted."); - return 0; + goto_bad; } - /* Ensure the two LVs are not active elsewhere. */ + /* Ensure the LV is not active elsewhere. */ if (!lockd_lv(cmd, lv, "ex", 0)) goto_bad; - if (!lockd_lv(cmd, lv_fast, "ex", 0)) - goto_bad; if (!archive(vg)) goto_bad; diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index f147be39c..ada4c80ad 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -124,8 +124,10 @@ static const struct command_function _command_functions[CMD_COUNT] = { { lvconvert_to_cachepool_CMD, lvconvert_to_pool_cmd }, { lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_cmd }, { lvconvert_to_cache_with_cachevol_CMD, lvconvert_to_cache_with_cachevol_cmd }, + { lvconvert_to_cache_with_device_CMD, lvconvert_to_cache_with_cachevol_cmd }, { lvconvert_to_cache_with_cachepool_CMD, lvconvert_to_cache_with_cachepool_cmd }, { lvconvert_to_writecache_CMD, lvconvert_to_writecache_cmd }, + { lvconvert_to_writecache_with_device_CMD, lvconvert_to_writecache_cmd }, { lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_cmd }, { lvconvert_to_thinpool_or_swap_metadata_CMD, lvconvert_to_pool_or_swap_metadata_cmd }, { lvconvert_to_cachepool_or_swap_metadata_CMD, lvconvert_to_pool_or_swap_metadata_cmd }, |