summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2020-02-05 13:42:36 -0600
committerDavid Teigland <teigland@redhat.com>2020-02-05 13:42:36 -0600
commitab4efab8568804b73492e3c719834b196de3fb0e (patch)
treef3bfcb5640fe79294b765d6ef418fa1ceeb60c09
parent2a6078f96168e860474b42c42b1924fc353c4558 (diff)
downloadlvm2-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.h6
-rw-r--r--tools/command-lines.in14
-rw-r--r--tools/lvconvert.c230
-rw-r--r--tools/lvmcmdline.c2
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 },