summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2020-04-10 13:17:37 -0500
committerDavid Teigland <teigland@redhat.com>2020-05-21 17:18:57 -0500
commit1f4bdaedb855f17fe8e19ffaf0a641d80795650c (patch)
treeb5dbcfb72586befecd22922e847ca544ea95f5fb
parent86a9429c7f224696c1757e4ff42a71137bac180f (diff)
downloadlvm2-1f4bdaedb855f17fe8e19ffaf0a641d80795650c.tar.gz
lvcreate: new cache or writecache lv with single command
To create a new cache or writecache LV with a single command: lvcreate --type cache|writecache -n Name -L Size --cachedevice PVfast VG [PVslow ...] - A new main linear|striped LV is created as usual, using the specified -n Name and -L Size, and using the optionally specified PVslow devices. - Then, a new cachevol LV is created internally, using PVfast specified by the cachedevice option. - Then, the cachevol is attached to the main LV, converting the main LV to type cache|writecache. Include --cachesize Size to specify the size of cache|writecache to create from the specified --cachedevice PVs, otherwise the entire cachedevice PV is used. The --cachedevice option can be repeated to create the cache from multiple devices, or the cachedevice option can contain a tag name specifying a set of PVs to allocate the cache from. To create a new cache or writecache LV with a single command using an existing cachevol LV: lvcreate --type cache|writecache -n Name -L Size --cachevol LVfast VG [PVslow ...] - A new main linear|striped LV is created as usual, using the specified -n Name and -L Size, and using the optionally specified PVslow devices. - Then, the cachevol LVfast is attached to the main LV, converting the main LV to type cache|writecache. In cases where more advanced types (for the main LV or cachevol LV) are needed, they should be created independently and then combined with lvconvert. Example ------- user creates a new VG with one slow device and one fast device: $ vgcreate vg /dev/slow1 /dev/fast1 user creates a new 8G main LV on /dev/slow1 that uses all of /dev/fast1 as a writecache: $ lvcreate --type writecache --cachedevice /dev/fast1 -n main -L 8G vg /dev/slow1 Example ------- user creates a new VG with two slow devs and two fast devs: $ vgcreate vg /dev/slow1 /dev/slow2 /dev/fast1 /dev/fast2 user creates a new 8G main LV on /dev/slow1 and /dev/slow2 that uses all of /dev/fast1 and /dev/fast2 as a writecache: $ lvcreate --type writecache --cachedevice /dev/fast1 --cachedevice /dev/fast2 -n main -L 8G vg /dev/slow1 /dev/slow2 Example ------- A user has several slow devices and several fast devices in their VG, the slow devs have tag @slow, the fast devs have tag @fast. user creates a new 8G main LV on the slow devs with a 2G writecache on the fast devs: $ lvcreate --type writecache -n main -L 8G --cachedevice @fast --cachesize 2G vg @slow
-rw-r--r--lib/metadata/metadata-exported.h1
-rw-r--r--tools/args.h2
-rw-r--r--tools/command-lines.in126
-rw-r--r--tools/command.c3
-rw-r--r--tools/lvconvert.c166
-rw-r--r--tools/lvcreate.c153
-rw-r--r--tools/lvmcmdline.c6
-rw-r--r--tools/tools.h11
8 files changed, 341 insertions, 127 deletions
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 1fcb7224a..c4b086e5b 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -954,6 +954,7 @@ struct lvcreate_params {
int thin_chunk_size_calc_policy;
unsigned suppress_zero_warn : 1;
unsigned needs_lockd_init : 1;
+ unsigned ignore_type : 1;
const char *vg_name; /* only-used when VG is not yet opened (in /tools) */
const char *lv_name; /* all */
diff --git a/tools/args.h b/tools/args.h
index 3b672536a..2e5a73ddd 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -126,7 +126,7 @@ 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,
+arg(cachedevice_ARG, '\0', "cachedevice", pv_VAL, ARG_GROUPABLE, 0,
"The name of a device to use for a cache.\n")
arg(cachesize_ARG, '\0', "cachesize", sizemb_VAL, 0, 0,
diff --git a/tools/command-lines.in b/tools/command-lines.in
index a2829ab1e..c297249b9 100644
--- a/tools/command-lines.in
+++ b/tools/command-lines.in
@@ -1219,87 +1219,107 @@ lvcreate --type cache --size SizeMB --cachepool LV_cachepool VG
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin
-DESC: Create a cache LV, first creating a new origin LV,
-DESC: then combining it with the existing cache pool named
-DESC: by the --cachepool arg.
+ID: lvcreate_and_attach_cachepool
+DESC: Create a new LV, then attach the specified cachepool
+DESC: which converts the new LV to type cache.
# alternate form of lvcreate --type cache
+# (omits the --type cache option which is inferred)
lvcreate --size SizeMB --cachepool LV_cachepool VG
OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin
-DESC: Create a cache LV, first creating a new origin LV,
-DESC: then combining it with the existing cache pool named
-DESC: by the --cachepool arg (variant, infers --type cache).
+ID: lvcreate_and_attach_cachepool_v2
+DESC: Create a new LV, then attach the specified cachepool
+DESC: which converts the new LV to type cache
+DESC: (variant, infers --type cache.)
FLAGS: SECONDARY_SYNTAX
# alternate form of lvcreate --type cache
+# (moves cachepool from option arg to position arg,
+# dropping the normal VG position arg)
lvcreate --type cache --size SizeMB LV_cachepool
OO: --cache, OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin
-DESC: Create a cache LV, first creating a new origin LV,
-DESC: then combining it with the existing cache pool named
-DESC: in the first arg (variant, also use --cachepool).
+ID: lvcreate_and_attach_cachepool_v3
+DESC: Create a new LV, then attach the specified cachepool
+DESC: which converts the new LV to type cache.
+DESC: (variant, also use --cachepool).
FLAGS: SECONDARY_SYNTAX
-# This is a ridiculously crazy command which nobody could
-# understand. It should be be eliminated. It does two different
-# things depending on whether LV in pos 1 is a cachepool LV
-# or not. Both variations are unnecessary.
-#
-# 1. If LV is a cachepool, then it's an alternate form of
-# an already complicated command above.
-#
-# # alternate form for lvcreate_cache_vol_with_new_origin
-# lvcreate --cache --size SizeMB LV_cachepool
-# OO: --type cache, --cache, OO_LVCREATE_CACHE, OO_LVCREATE, --stripes Number, --stripesize SizeKB
-# OP: PV ...
-# ID: lvcreate_cache_vol_with_new_origin
-# DESC: Create a cache LV, first creating a new origin LV,
-# DESC: then combining it with the existing cache pool named
-# DESC: in the first arg (variant, infers --type cache,
-# DESC: also use --cachepool).
-#
-# 2. If LV is not a cachepool, then it's a disguised lvconvert.
-#
-# # FIXME: this should be done by lvconvert, and this command removed
-# lvcreate --type cache --size SizeMB LV
-# OO: OO_LVCREATE_POOL, OO_LVCREATE_CACHE, OO_LVCREATE
-# OP: PV ...
-# ID: lvcreate_convert_to_cache_vol_with_cachepool
-# DESC: Convert the specified LV to type cache after creating a new
-# DESC: cache pool LV to use (use lvconvert).
+# This command has two different meanings which ought to
+# have separate command defs, but since the syntax is the
+# same for both they have to share one command def with
+# an ambiguous meaning. Which command is performed depends
+# on whether the LV in the first arg position is a
+# cachepool or not (we can't have two different command
+# defs that differ only in the type of LV in the arg position
+# because when parsing commands we don't know the LV type.)
+#
+# 1. An alternate form of lvcreate_and_attach_cachepool_v3
+# this syntax: lvcreate --cache --size SizeMB LV_cachepool
+# is alternative for: lvcreate --type cache --size SizeMB LV_cachepool
+#
+# 2. An alternative to using lvconvert to convert LV to type cache,
+# but in this case the cachepool is created internally and
+# then attached to the LV arg.
#
# Note that stripes are accepted by the first and not by the
# second, but it's not possible to validate this until after
# the LV type is known.
-#
-# So, to define this syntax we have to combine both of
-# those variants, each crazy on it's own, into one
-# ridiculous command.
-# def1: alternate form of lvcreate --type cache, or
-# def2: it should be done by lvconvert.
lvcreate --cache --size SizeMB LV
OO: OO_LVCREATE_CACHE, OO_LVCREATE_POOL, OO_LVCREATE,
--stripes Number, --stripesize SizeKB
OP: PV ...
-ID: lvcreate_cache_vol_with_new_origin_or_convert_to_cache_vol_with_cachepool
-DESC: When LV is a cache pool, create a cache LV,
-DESC: first creating a new origin LV, then combining it with
-DESC: the existing cache pool named in the first arg
-DESC: (variant, infers --type cache, also use --cachepool).
-DESC: When LV is not a cache pool, convert the specified LV
-DESC: to type cache after creating a new cache pool LV to use
-DESC: (use lvconvert).
+ID: lvcreate_new_plus_old_cachepool_or_lvconvert_old_plus_new_cachepool
+DESC: When the LV arg is a cachepool, then create a new LV and
+DESC: attach the cachepool arg to it.
+DESC: (variant, use --type cache and --cachepool.)
+DESC: When the LV arg is not a cachepool, then create a new cachepool
+DESC: and attach it to the LV arg (alternative, use lvconvert.)
FLAGS: SECONDARY_SYNTAX
---
+# These all create a new origin LV, then forwards to lvconvert
+# which combines it with a cachevol (which already exists or
+# which needs to be created from cachedevice), converting
+# the new LV to type cache or writecache.
+
+lvcreate --type cache --size SizeMB --cachevol LV VG
+OO: OO_LVCREATE, OO_LVCREATE_CACHE, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachevol_for_cache
+DESC: Create a new LV, then attach the specified cachevol
+DESC: which converts the new LV to type cache.
+
+lvcreate --type cache --size SizeMB --cachedevice PV VG
+OO: OO_LVCREATE, OO_LVCREATE_CACHE, --cachesize SizeMB, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachedevice_for_cache
+DESC: Create a new LV, then attach a cachevol created from
+DESC: the specified cache device, which converts the
+DESC: new LV to type cache.
+
+lvcreate --type writecache --size SizeMB --cachevol LV VG
+OO: OO_LVCREATE, --cachesettings String, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachevol_for_writecache
+DESC: Create a new LV, then attach the specified cachevol
+DESC: which converts the new LV to type writecache.
+
+lvcreate --type writecache --size SizeMB --cachedevice PV VG
+OO: OO_LVCREATE, --cachesize SizeMB, --cachesettings String, --stripes Number, --stripesize SizeKB
+OP: PV ...
+ID: lvcreate_and_attach_cachedevice_for_writecache
+DESC: Create a new LV, then attach a cachevol created from
+DESC: the specified cache device, which converts the
+DESC: new LV to type writecache.
+
+---
+
lvdisplay
OO: --aligned, --all, --binary, --colon, --columns,
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
diff --git a/tools/command.c b/tools/command.c
index 511dda13d..2d0184941 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -1420,6 +1420,9 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name)
if (line[0] == '\n')
break;
+ if (!strcmp(line, "---") || !strcmp(line, "--"))
+ continue;
+
if ((n = strchr(line, '\n')))
*n = '\0';
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 9b63d5f65..56f69f3a4 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -4247,18 +4247,25 @@ int lvconvert_to_pool_cmd(struct cmd_context *cmd, int argc, char **argv)
NULL, NULL, &_lvconvert_to_pool_single);
}
+#define MAX_CACHEDEVS 8
+
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;
+ char *dev_name;
+ struct device *dev_fast;
+ char *dev_argv[MAX_CACHEDEVS];
+ int dev_argc = 0;
+ uint64_t cache_size_sectors = 0;
+ uint64_t full_size_sectors = 0;
+ uint64_t pv_size_sectors;
+ struct logical_volume *cachevol;
+ struct arg_value_group_list *group;
struct lvcreate_params lp = {
.activate = CHANGE_AN,
.alloc = ALLOC_INHERIT,
@@ -4274,48 +4281,86 @@ static int _lv_create_cachevol(struct cmd_context *cmd,
.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 cache size is not set, and all cachedevice's are unused,
+ * then the cache size is the sum of all cachedevice sizes.
+ */
+ cache_size_sectors = arg_uint64_value(cmd, cachesize_ARG, 0);
- if (!(dev_fast = dev_cache_get(cmd, dev_name, cmd->filter))) {
- log_error("Device %s not found.", dev_name);
- return 0;
- }
+ dm_list_iterate_items(group, &cmd->arg_value_groups) {
+ if (!grouped_arg_is_set(group->arg_values, cachedevice_ARG))
+ continue;
- if (!(pvl = find_pv_in_vg(vg, dev_name))) {
- log_error("PV %s not found in VG.", dev_name);
- return 0;
- }
+ if (!(dev_name = (char *)grouped_arg_str_value(group->arg_values, cachedevice_ARG, NULL)))
+ break;
- /*
- * 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) {
+ if (dev_name[0] == '@') {
+ if (!cache_size_sectors) {
+ log_error("With tag as cachedevice, --cachesize is required.");
+ return 0;
+ }
+ goto add_dev_arg;
+ }
+
+ 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 the dev is used in the VG, then require a cachesize to allocate
+ * from it. If it is not used in the VG, then prompt asking if the
+ * entire dev should be used.
+ */
+ if (!cache_size_sectors && 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 (!cache_size_sectors) {
+ pv_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_print("Use --cachesize SizeMB to use a part of the cachedevice.");
- log_error("Conversion aborted.");
+ if (!arg_is_set(cmd, yes_ARG) &&
+ yes_no_prompt("Use all %s from %s for cache? [y/n]: ",
+ display_size(cmd, pv_size_sectors), dev_name) == 'n') {
+ log_print("Use --cachesize SizeMB to use a part of the cachedevice.");
+ log_error("Conversion aborted.");
+ return 0;
+ }
+ full_size_sectors += pv_size_sectors;
+ }
+ add_dev_arg:
+ if (dev_argc >= MAX_CACHEDEVS) {
+ log_error("Cannot allocate from more than %u cache devices.", MAX_CACHEDEVS);
return 0;
}
+
+ dev_argv[dev_argc++] = dev_name;
+ }
+
+ if (!cache_size_sectors)
+ cache_size_sectors = full_size_sectors;
+
+ if (!dev_argc) {
+ log_error("No cachedevice specified to create a cachevol.");
+ return 0;
}
- if (!(use_pvh = create_pv_list(cmd->mem, vg, 1, (char **)&dev_name, 1))) {
+ if (!(use_pvh = create_pv_list(cmd->mem, vg, dev_argc, dev_argv, 1))) {
log_error("cachedevice not found in VG %s.", dev_name);
return 0;
}
+ if (dm_snprintf(cvname, NAME_LEN, "%s_cache", lv->name) < 0) {
+ log_error("Failed to create cachevol LV name.");
+ return 0;
+ }
+
lp.lv_name = cvname;
lp.pvh = use_pvh;
lp.extents = cache_size_sectors / vg->extent_size;
@@ -4337,27 +4382,19 @@ static int _lv_create_cachevol(struct cmd_context *cmd,
return 1;
}
-static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
- struct logical_volume *lv,
- struct processing_handle *handle)
+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 *lv_fast;
- const char *fast_name, *dev_name;
-
- fast_name = arg_str_value(cmd, cachevol_ARG, NULL);
- dev_name = arg_str_value(cmd, cachedevice_ARG, NULL);
-
- if (!fast_name && !dev_name)
- goto_bad;
-
- if (fast_name && dev_name)
- goto_bad;
+ const char *fast_name;
/*
- * User specifies an existing cachevol to use.
+ * User specifies an existing cachevol to use or a cachedevice
+ * to create a cachevol from.
*/
- if (fast_name) {
+ if ((fast_name = arg_str_value(cmd, cachevol_ARG, NULL))) {
if (!validate_lvname_param(cmd, &vg->name, &fast_name))
goto_bad;
@@ -4379,13 +4416,8 @@ static int _lvconvert_cachevol_attach_single(struct cmd_context *cmd,
if (!lockd_lv(cmd, lv_fast, "ex", 0))
goto_bad;
- }
-
- /*
- * 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))
+ } else {
+ if (!_lv_create_cachevol(cmd, vg, lv, &lv_fast))
goto_bad;
}
@@ -5949,7 +5981,7 @@ bad:
return 0;
}
-static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
+int lvconvert_writecache_attach_single(struct cmd_context *cmd,
struct logical_volume *lv,
struct processing_handle *handle)
{
@@ -5957,7 +5989,7 @@ 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, *dev_name;
+ const char *fast_name;
uint32_t block_size_sectors = 0;
char *lockd_fast_args = NULL;
char *lockd_fast_name = NULL;
@@ -5965,16 +5997,11 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
char cvol_name[NAME_LEN];
int is_active;
- fast_name = arg_str_value(cmd, cachevol_ARG, NULL);
- dev_name = arg_str_value(cmd, cachedevice_ARG, NULL);
-
- if (!fast_name && !dev_name)
- goto_bad;
-
/*
- * User specifies an existing cachevol to use.
+ * User specifies an existing cachevol to use or a cachedevice
+ * to create a cachevol from.
*/
- if (fast_name) {
+ if ((fast_name = arg_str_value(cmd, cachevol_ARG, NULL))) {
if (!validate_lvname_param(cmd, &vg->name, &fast_name))
goto_bad;
@@ -6004,13 +6031,8 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
log_error("Conversion aborted.");
goto bad;
}
- }
-
- /*
- * 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))
+ } else {
+ if (!_lv_create_cachevol(cmd, vg, lv, &lv_fast))
goto_bad;
}
@@ -6047,7 +6069,7 @@ static int _lvconvert_writecache_attach_single(struct cmd_context *cmd,
/* Ensure the LV is not active elsewhere. */
if (!lockd_lv(cmd, lv, "ex", 0))
goto_bad;
- if (!dev_name && !lockd_lv(cmd, lv_fast, "ex", 0))
+ if (fast_name && !lockd_lv(cmd, lv_fast, "ex", 0))
goto_bad;
if (!archive(vg))
@@ -6138,7 +6160,7 @@ int lvconvert_to_writecache_cmd(struct cmd_context *cmd, int argc, char **argv)
cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
- &_lvconvert_writecache_attach_single);
+ &lvconvert_writecache_attach_single);
destroy_processing_handle(cmd, handle);
@@ -6161,7 +6183,7 @@ int lvconvert_to_cache_with_cachevol_cmd(struct cmd_context *cmd, int argc, char
cmd->cname->flags &= ~GET_VGNAME_FROM_OPTIONS;
ret = process_each_lv(cmd, cmd->position_argc, cmd->position_argv, NULL, NULL, READ_FOR_UPDATE, handle, NULL,
- &_lvconvert_cachevol_attach_single);
+ &lvconvert_cachevol_attach_single);
destroy_processing_handle(cmd, handle);
diff --git a/tools/lvcreate.c b/tools/lvcreate.c
index 5c978b3cc..3357a08c5 100644
--- a/tools/lvcreate.c
+++ b/tools/lvcreate.c
@@ -766,7 +766,9 @@ static int _lvcreate_params(struct cmd_context *cmd,
*
* Ordering of following type tests is IMPORTANT
*/
- if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
+ if (lp->ignore_type) {
+ segtype_str = SEG_TYPE_NAME_STRIPED;
+ } else if ((segtype_str = arg_str_value(cmd, type_ARG, NULL))) {
lp->type = 1;
if (!strcmp(segtype_str, "linear")) {
segtype_str = "striped";
@@ -1799,3 +1801,152 @@ int lvcreate(struct cmd_context *cmd, int argc, char **argv)
destroy_processing_handle(cmd, handle);
return ret;
}
+
+static int _lvcreate_and_attach_writecache_single(struct cmd_context *cmd,
+ const char *vg_name, struct volume_group *vg, struct processing_handle *handle)
+{
+ struct processing_params *pp = (struct processing_params *) handle->custom_handle;
+ struct lvcreate_params *lp = pp->lp;
+ struct logical_volume *lv;
+ int ret;
+
+ ret = _lvcreate_single(cmd, vg_name, vg, handle);
+
+ if (ret == ECMD_FAILED)
+ return ret;
+
+ if (!(lv = find_lv(vg, lp->lv_name))) {
+ log_error("Failed to find LV %s to add writecache.", lp->lv_name);
+ return ECMD_FAILED;
+ }
+
+ ret = lvconvert_writecache_attach_single(cmd, lv, handle);
+
+ if (ret == ECMD_FAILED) {
+ log_error("Removing new LV after failing to add writecache.");
+ if (!deactivate_lv(cmd, lv))
+ log_error("Failed to deactivate new LV %s.", display_lvname(lv));
+ if (!lv_remove_with_dependencies(cmd, lv, 1, 0))
+ log_error("Failed to remove new LV %s.", display_lvname(lv));
+ return ECMD_FAILED;
+ }
+
+ return ECMD_PROCESSED;
+}
+
+int lvcreate_and_attach_writecache_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = NULL;
+ struct processing_params pp;
+ struct lvcreate_params lp = {
+ .major = -1,
+ .minor = -1,
+ };
+ struct lvcreate_cmdline_params lcp = { 0 };
+ int ret;
+
+ /*
+ * Tell lvcreate to ignore --type since we are using lvcreate
+ * to create a linear LV and using lvconvert to add cache.
+ * (Would be better if lvcreate code was split up so we could
+ * call a specific function that just created a linear/striped LV.)
+ */
+ lp.ignore_type = 1;
+
+ if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
+ stack;
+ return EINVALID_CMD_LINE;
+ }
+
+ pp.lp = &lp;
+ pp.lcp = &lcp;
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &pp;
+
+ ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
+ &_lvcreate_and_attach_writecache_single);
+
+ _destroy_lvcreate_params(&lp);
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+
+static int _lvcreate_and_attach_cache_single(struct cmd_context *cmd,
+ const char *vg_name, struct volume_group *vg, struct processing_handle *handle)
+{
+ struct processing_params *pp = (struct processing_params *) handle->custom_handle;
+ struct lvcreate_params *lp = pp->lp;
+ struct logical_volume *lv;
+ int ret;
+
+ ret = _lvcreate_single(cmd, vg_name, vg, handle);
+
+ if (ret == ECMD_FAILED)
+ return ret;
+
+ if (!(lv = find_lv(vg, lp->lv_name))) {
+ log_error("Failed to find LV %s to add cache.", lp->lv_name);
+ return ECMD_FAILED;
+ }
+
+ ret = lvconvert_cachevol_attach_single(cmd, lv, handle);
+
+ if (ret == ECMD_FAILED) {
+ log_error("Removing new LV after failing to add cache.");
+ if (!deactivate_lv(cmd, lv))
+ log_error("Failed to deactivate new LV %s.", display_lvname(lv));
+ if (!lv_remove_with_dependencies(cmd, lv, 1, 0))
+ log_error("Failed to remove new LV %s.", display_lvname(lv));
+ return ECMD_FAILED;
+ }
+
+ return ECMD_PROCESSED;
+}
+
+int lvcreate_and_attach_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
+{
+ struct processing_handle *handle = NULL;
+ struct processing_params pp;
+ struct lvcreate_params lp = {
+ .major = -1,
+ .minor = -1,
+ };
+ struct lvcreate_cmdline_params lcp = { 0 };
+ int ret;
+
+ /*
+ * Tell lvcreate to ignore --type since we are using lvcreate
+ * to create a linear LV and using lvconvert to add cache.
+ * (Would be better if lvcreate code was split up so we could
+ * call a specific function that just created a linear/striped LV.)
+ */
+ lp.ignore_type = 1;
+
+ if (!_lvcreate_params(cmd, argc, argv, &lp, &lcp)) {
+ stack;
+ return EINVALID_CMD_LINE;
+ }
+
+ pp.lp = &lp;
+ pp.lcp = &lcp;
+
+ if (!(handle = init_processing_handle(cmd, NULL))) {
+ log_error("Failed to initialize processing handle.");
+ return ECMD_FAILED;
+ }
+
+ handle->custom_handle = &pp;
+
+ ret = process_each_vg(cmd, 0, NULL, lp.vg_name, NULL, READ_FOR_UPDATE, 0, handle,
+ &_lvcreate_and_attach_cache_single);
+
+ _destroy_lvcreate_params(&lp);
+ destroy_processing_handle(cmd, handle);
+ return ret;
+}
+
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index 9c345bd99..7cf4e3ff0 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -154,6 +154,12 @@ static const struct command_function _command_functions[CMD_COUNT] = {
/* lvconvert for integrity */
{ lvconvert_integrity_CMD, lvconvert_integrity_cmd },
+ /* lvcreate */
+ { lvcreate_and_attach_cachevol_for_cache_CMD, lvcreate_and_attach_cache_cmd },
+ { lvcreate_and_attach_cachedevice_for_cache_CMD, lvcreate_and_attach_cache_cmd },
+ { lvcreate_and_attach_cachevol_for_writecache_CMD, lvcreate_and_attach_writecache_cmd },
+ { lvcreate_and_attach_cachedevice_for_writecache_CMD, lvcreate_and_attach_writecache_cmd },
+
{ pvscan_display_CMD, pvscan_display_cmd },
{ pvscan_cache_CMD, pvscan_cache_cmd },
};
diff --git a/tools/tools.h b/tools/tools.h
index 7f2434d06..c3d780d36 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -278,7 +278,18 @@ int lvconvert_to_vdopool_param_cmd(struct cmd_context *cmd, int argc, char **arg
int lvconvert_integrity_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvcreate_and_attach_writecache_cmd(struct cmd_context *cmd, int argc, char **argv);
+int lvcreate_and_attach_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
+
int pvscan_display_cmd(struct cmd_context *cmd, int argc, char **argv);
int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv);
+
+int lvconvert_writecache_attach_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle);
+int lvconvert_cachevol_attach_single(struct cmd_context *cmd,
+ struct logical_volume *lv,
+ struct processing_handle *handle);
+
#endif