mirror of
git://sourceware.org/git/lvm2.git
synced 2025-11-03 08:23:48 +03:00
Compare commits
1 Commits
dev-dct-cm
...
dev-dct-cm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4cfdebd2f |
@@ -94,6 +94,13 @@ struct cmd_context {
|
||||
struct arg_values *opt_arg_values;
|
||||
struct dm_list arg_value_groups;
|
||||
|
||||
/*
|
||||
* Position args remaining after command name
|
||||
* and --options are removed from original argc/argv.
|
||||
*/
|
||||
int position_argc;
|
||||
char **position_argv;
|
||||
|
||||
/*
|
||||
* Format handlers.
|
||||
*/
|
||||
|
||||
@@ -319,7 +319,6 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
|
||||
{
|
||||
int top_level = 0;
|
||||
unsigned snap_count;
|
||||
struct lv_segment *seg;
|
||||
|
||||
/* non-top-level LVs */
|
||||
if (lv_is_thin_pool_metadata(lv)) {
|
||||
@@ -353,7 +352,7 @@ static int _lv_layout_and_role_thin(struct dm_pool *mem,
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_MULTITHINORIGIN]))
|
||||
goto_bad;
|
||||
}
|
||||
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
|
||||
if (lv_is_thin_snapshot(lv))
|
||||
if (!str_list_add(mem, role, _lv_type_names[LV_TYPE_SNAPSHOT]) ||
|
||||
!str_list_add_no_dup_check(mem, role, _lv_type_names[LV_TYPE_THINSNAPSHOT]))
|
||||
goto_bad;
|
||||
|
||||
@@ -1066,9 +1066,16 @@ struct lv_segment *get_only_segment_using_this_lv(const struct logical_volume *l
|
||||
* Useful functions for managing snapshots.
|
||||
*/
|
||||
int lv_is_origin(const struct logical_volume *lv);
|
||||
#define lv_is_thick_origin lv_is_origin
|
||||
|
||||
int lv_is_thin_origin(const struct logical_volume *lv, unsigned *snap_count);
|
||||
int lv_is_cache_origin(const struct logical_volume *lv);
|
||||
int lv_is_thin_snapshot(const struct logical_volume *lv);
|
||||
|
||||
int lv_is_cow(const struct logical_volume *lv);
|
||||
#define lv_is_thick_snapshot lv_is_cow
|
||||
|
||||
int lv_is_cache_origin(const struct logical_volume *lv);
|
||||
|
||||
int lv_is_merging_cow(const struct logical_volume *cow);
|
||||
uint32_t cow_max_extents(const struct logical_volume *origin, uint32_t chunk_size);
|
||||
int cow_has_min_chunks(const struct volume_group *vg, uint32_t cow_extents, uint32_t chunk_size);
|
||||
|
||||
@@ -748,6 +748,19 @@ int lv_is_thin_origin(const struct logical_volume *lv, unsigned int *snap_count)
|
||||
return r;
|
||||
}
|
||||
|
||||
int lv_is_thin_snapshot(const struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
|
||||
if (!lv_is_thin_volume(lv))
|
||||
return 0;
|
||||
|
||||
if ((seg = first_seg(lv)) && (seg->origin || seg->external_lv))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Explict check of new thin pool for usability
|
||||
*
|
||||
|
||||
@@ -140,6 +140,13 @@ Makefile: Makefile.in
|
||||
*) echo "Creating $@" ; $(SED) -e "s+#VERSION#+$(LVM_VERSION)+;s+#DEFAULT_SYS_DIR#+$(DEFAULT_SYS_DIR)+;s+#DEFAULT_ARCHIVE_DIR#+$(DEFAULT_ARCHIVE_DIR)+;s+#DEFAULT_BACKUP_DIR#+$(DEFAULT_BACKUP_DIR)+;s+#DEFAULT_PROFILE_DIR#+$(DEFAULT_PROFILE_DIR)+;s+#DEFAULT_CACHE_DIR#+$(DEFAULT_CACHE_DIR)+;s+#DEFAULT_LOCK_DIR#+$(DEFAULT_LOCK_DIR)+;s+#CLVMD_PATH#+@CLVMD_PATH@+;s+#LVM_PATH#+@LVM_PATH@+;s+#DEFAULT_RUN_DIR#+@DEFAULT_RUN_DIR@+;s+#DEFAULT_PID_DIR#+@DEFAULT_PID_DIR@+;s+#SYSTEMD_GENERATOR_DIR#+$(SYSTEMD_GENERATOR_DIR)+;s+#DEFAULT_MANGLING#+$(DEFAULT_MANGLING)+;" $< > $@ ;; \
|
||||
esac
|
||||
|
||||
ccmd: ../tools/create-commands.c
|
||||
$(CC) ../tools/create-commands.c -o ccmd
|
||||
|
||||
generate: ccmd
|
||||
./ccmd --output man -s 0 -p 1 -c lvcreate ../tools/command-lines.in > lvcreate.8.a
|
||||
cat lvcreate.8.a lvcreate.8.b > lvcreate.8.in
|
||||
|
||||
install_man5: $(MAN5)
|
||||
$(INSTALL) -d $(MAN5DIR)
|
||||
$(INSTALL_DATA) $(MAN5) $(MAN5DIR)/
|
||||
|
||||
20
tools/args.h
20
tools/args.h
@@ -17,6 +17,8 @@
|
||||
* Put all long args that don't have a corresponding short option first.
|
||||
*/
|
||||
/* *INDENT-OFF* */
|
||||
arg(ARG_UNUSED, '-', "", 0, 0, 0) /* place holder for unused 0 value */
|
||||
|
||||
arg(abort_ARG, '\0', "abort", 0, 0, 0)
|
||||
arg(activationmode_ARG, '\0', "activationmode", activationmode_VAL, 0, 0)
|
||||
arg(addtag_ARG, '\0', "addtag", tag_VAL, ARG_GROUPABLE, 0)
|
||||
@@ -31,8 +33,8 @@ arg(cachemode_ARG, '\0', "cachemode", cachemode_VAL, 0, 0)
|
||||
arg(cachepool_ARG, '\0', "cachepool", lv_VAL, 0, 0)
|
||||
arg(commandprofile_ARG, '\0', "commandprofile", string_VAL, 0, 0)
|
||||
arg(config_ARG, '\0', "config", string_VAL, 0, 0)
|
||||
arg(configreport_ARG, '\0', "configreport", string_VAL, ARG_GROUPABLE, 1)
|
||||
arg(configtype_ARG, '\0', "typeconfig", string_VAL, 0, 0)
|
||||
arg(configreport_ARG, '\0', "configreport", configreport_VAL, ARG_GROUPABLE, 1)
|
||||
arg(configtype_ARG, '\0', "typeconfig", configtype_VAL, 0, 0)
|
||||
arg(corelog_ARG, '\0', "corelog", 0, 0, 0)
|
||||
arg(dataalignment_ARG, '\0', "dataalignment", sizekb_VAL, 0, 0)
|
||||
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", sizekb_VAL, 0, 0)
|
||||
@@ -81,26 +83,26 @@ arg(noudevsync_ARG, '\0', "noudevsync", 0, 0, 0)
|
||||
arg(originname_ARG, '\0', "originname", lv_VAL, 0, 0)
|
||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0)
|
||||
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0)
|
||||
arg(polloperation_ARG, '\0', "polloperation", string_VAL, 0, 0)
|
||||
arg(polloperation_ARG, '\0', "polloperation", polloperation_VAL, 0, 0)
|
||||
arg(pooldatasize_ARG, '\0', "pooldatasize", sizemb_VAL, 0, 0)
|
||||
arg(poolmetadata_ARG, '\0', "poolmetadata", lv_VAL, 0, 0)
|
||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", sizemb_VAL, 0, 0)
|
||||
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", bool_VAL, 0, 0)
|
||||
arg(profile_ARG, '\0', "profile", string_VAL, 0, 0)
|
||||
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", pvmetadatacopies_VAL, 0, 0)
|
||||
arg(raidrebuild_ARG, '\0', "raidrebuild", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(raidrebuild_ARG, '\0', "raidrebuild", pv_VAL, ARG_GROUPABLE, 0)
|
||||
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_VAL, 0, 0)
|
||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", syncaction_VAL, 0, 0)
|
||||
arg(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
|
||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", writemostly_VAL, ARG_GROUPABLE, 0)
|
||||
arg(readonly_ARG, '\0', "readonly", 0, 0, 0)
|
||||
arg(refresh_ARG, '\0', "refresh", 0, 0, 0)
|
||||
arg(removemissing_ARG, '\0', "removemissing", 0, 0, 0)
|
||||
arg(rebuild_ARG, '\0', "rebuild", pv_VAL, ARG_GROUPABLE, 0)
|
||||
arg(repair_ARG, '\0', "repair", 0, 0, 0)
|
||||
arg(replace_ARG, '\0', "replace", pv_VAL, ARG_GROUPABLE, 0)
|
||||
arg(reportformat_ARG, '\0', "reportformat", string_VAL, 0, 0)
|
||||
arg(reportformat_ARG, '\0', "reportformat", reportformat_VAL, 0, 0)
|
||||
arg(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
|
||||
arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
|
||||
arg(resync_ARG, '\0', "resync", 0, 0, 0)
|
||||
@@ -116,7 +118,7 @@ arg(splitsnapshot_ARG, '\0', "splitsnapshot", 0, 0, 0)
|
||||
arg(showdeprecated_ARG, '\0', "showdeprecated", 0, 0, 0)
|
||||
arg(showunsupported_ARG, '\0', "showunsupported", 0, 0, 0)
|
||||
arg(stripes_long_ARG, '\0', "stripes", number_VAL, 0, 0)
|
||||
arg(syncaction_ARG, '\0', "syncaction", string_VAL, 0, 0) /* FIXME Use custom VAL */
|
||||
arg(syncaction_ARG, '\0', "syncaction", syncaction_VAL, 0, 0)
|
||||
arg(sysinit_ARG, '\0', "sysinit", 0, 0, 0)
|
||||
arg(systemid_ARG, '\0', "systemid", string_VAL, 0, 0)
|
||||
arg(thinpool_ARG, '\0', "thinpool", lv_VAL, 0, 0)
|
||||
@@ -140,7 +142,7 @@ arg(withcomments_ARG, '\0', "withcomments", 0, 0, 0)
|
||||
arg(withspaces_ARG, '\0', "withspaces", 0, 0, 0)
|
||||
arg(withversions_ARG, '\0', "withversions", 0, 0, 0)
|
||||
arg(writebehind_ARG, '\0', "writebehind", number_VAL, 0, 0)
|
||||
arg(writemostly_ARG, '\0', "writemostly", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(writemostly_ARG, '\0', "writemostly", writemostly_VAL, ARG_GROUPABLE, 0)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)
|
||||
|
||||
@@ -83,6 +83,13 @@
|
||||
# Also, --thinpool VG/LV or --cachepool VG/LV can be used in
|
||||
# place of --name to provide the VG name instead of pos 1.
|
||||
#
|
||||
# Note that one the most difficult aspect of these definitions is
|
||||
# the variants of --thin / --type thin / --type thin-pool,
|
||||
# --cache / --type cache / --type cache-pool.
|
||||
# There are no consistent rules to follow and the behaviors are
|
||||
# unpredictable; each possible variation and combination needs
|
||||
# to be tested individually to see what it means.
|
||||
#
|
||||
# Some options have multiple names, but only one form of the name
|
||||
# is used in these definitions. Synonyms will be recognized when
|
||||
# matching a command to a command definition.
|
||||
@@ -99,6 +106,8 @@
|
||||
# maxrecoveryrate (raidmaxrecoveryrate)
|
||||
# writebehind (raidwritebehind)
|
||||
# virtualsize (virtualoriginsize)
|
||||
# vgmetadatacopies (metadatacopies)
|
||||
# pvmetadatacopies (metadatacopies)
|
||||
#
|
||||
# "---" is like a comment line, used to separate text for readability
|
||||
#
|
||||
@@ -113,25 +122,42 @@
|
||||
# included in the text as indicators of new lines when printing
|
||||
# the descriptions for help/man output.
|
||||
#
|
||||
# Note that one the most difficult aspect of these definitions is
|
||||
# the variants of --thin / --type thin / --type thin-pool,
|
||||
# --cache / --type cache / --type cache-pool.
|
||||
# There are no consistent rules to follow and the behaviors are
|
||||
# unpredictable; each possible variation and combination needs
|
||||
# to be tested individually to see what it means.
|
||||
# RULE: rules that a given command must follow, i.e. required (and)
|
||||
# or invalid (not) combinations of options, LV types or LV properties.
|
||||
#
|
||||
# Another capability we might want to add here is a way to express
|
||||
# rules, per definition, of what arg combinations are allowed or
|
||||
# required, e.g.
|
||||
# RULE: A and|not B
|
||||
#
|
||||
# if --foo is set, then --bar cannot be set could be encoded as:
|
||||
# RULE_OPT_INCOMPAT_OPT: --foo --bar
|
||||
# Conditions in A are applied to a given command+LV.
|
||||
# If the conditions in A are true, then the checks in B
|
||||
# are applied. If the checks in B are true|false according
|
||||
# to and|not, then the command fails|continues.
|
||||
#
|
||||
# if --foo is set, then --bar is required could be encoded as:
|
||||
# RULE_OPT_REQUIRES_OPT: --foo --bar
|
||||
# When A is "all", the conditions in B are always applied.
|
||||
#
|
||||
# Conditions:
|
||||
# . if any --option listed is set, the checks may apply
|
||||
# . if any LV_type listed matches LV, the checks may apply
|
||||
# . if all lv_is_prop listed matches LV, the checks may apply
|
||||
# . if all of the above pass, then perform the checks
|
||||
#
|
||||
# Checks for "and":
|
||||
# . if any --option listed is not set, then fail
|
||||
# . if none of the LV_types matches the LV, then fail
|
||||
# . if any of the lv_is_prop do not match the LV, then fail
|
||||
#
|
||||
# Checks for "not":
|
||||
# . if any --option listed is set, then fail
|
||||
# . if any of the LV_types matches the LV, then fail
|
||||
# . if any of the lv_is_prop match the LV, then fail
|
||||
#
|
||||
# RULE: --option|LV_type|lv_is_prop|all ... and|not --option|LV_type|lv_is_prop ...
|
||||
#
|
||||
# RULE: --opt1 not --opt2
|
||||
# RULE: --opt1 and --opt2
|
||||
# RULE: --opt1 LV_type1 lv_is_prop1 and --opt2
|
||||
# RULE: --opt1 LV_type1 and lv_is_prop1
|
||||
# RULE: LV_type1 and lv_is_prop1
|
||||
#
|
||||
# if --foo is set, then positional arg 1 is required
|
||||
# RULE_OPT_REQUIRES_POS: --foo 1
|
||||
#
|
||||
|
||||
#
|
||||
@@ -177,17 +203,17 @@ OO_USAGE_COMMON: OO_ALL, --force, --noudevsync
|
||||
#
|
||||
# options for pvs, lvs, vgs, fullreport
|
||||
#
|
||||
OO_REPORT: --aligned, --all, --binary, --configreport String, --foreign,
|
||||
OO_REPORT: --aligned, --all, --binary, --configreport ConfigReport, --foreign,
|
||||
--ignorelockingfailure, --ignoreskippedcluster, --logonly,
|
||||
--nameprefixes, --noheadings, --nolocking, --nosuffix,
|
||||
--options String, --partial, --readonly, --reportformat String, --rows,
|
||||
--options String, --partial, --readonly, --reportformat ReportFmt, --rows,
|
||||
--select String, --separator String, --shared, --sort String,
|
||||
--trustcache, --unbuffered, --units Units, --unquoted
|
||||
|
||||
#
|
||||
# options for config, dumpconfig, lvmconfig
|
||||
#
|
||||
OO_CONFIG: --atversion String, --typeconfig String, --file String, --ignoreadvanced,
|
||||
OO_CONFIG: --atversion String, --typeconfig ConfigType, --file String, --ignoreadvanced,
|
||||
--ignoreunsupported, --ignorelocal, --list, --mergedconfig, --metadataprofile String,
|
||||
--sinceversion String, --showdeprecated, --showunsupported, --validate, --withsummary,
|
||||
--withcomments, --withspaces, --unconfigured, --withversions
|
||||
@@ -196,9 +222,9 @@ OO_CONFIG: --atversion String, --typeconfig String, --file String, --ignoreadvan
|
||||
|
||||
# None of these can function as a required option for lvchange.
|
||||
|
||||
OO_LVCHANGE: --autobackup Bool, --force, --ignorelockingfailure,
|
||||
--ignoremonitoring, --ignoreskippedcluster, --noudevsync,
|
||||
--reportformat String, --sysinit, --select String
|
||||
OO_LVCHANGE: --autobackup Bool, --force, --ignoremonitoring,
|
||||
--ignoreskippedcluster, --noudevsync, --reportformat ReportFmt,
|
||||
--select String
|
||||
|
||||
# Any of these can function as a required option for lvchange.
|
||||
# profile is also part of OO_ALL, but is repeated in OO_LVCHANGE_META
|
||||
@@ -211,30 +237,47 @@ OO_LVCHANGE_META: --addtag Tag, --deltag Tag,
|
||||
--errorwhenfull Bool, --discards Discards, --zero Bool,
|
||||
--cachemode CacheMode, --cachepolicy String, --cachesettings String,
|
||||
--minrecoveryrate SizeKB, --maxrecoveryrate SizeKB,
|
||||
--writebehind Number, --writemostly PV
|
||||
--writebehind Number, --writemostly WriteMostlyPV, --persistent n
|
||||
|
||||
lvchange OO_LVCHANGE_META VG|LV|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_properties
|
||||
DESC: Change a general LV property.
|
||||
RULE: all not lv_is_pvmove lv_is_mirror_log lv_is_mirror_image
|
||||
RULE: all and lv_is_vg_writable
|
||||
RULE: --contiguous not --alloc
|
||||
RULE: --profile not --detachprofile
|
||||
RULE: --metadataprofile not --detachprofile
|
||||
RULE: --minrecoveryrate --maxrecoveryrate and LV_raid
|
||||
RULE: --writebehind --writemostly and LV_raid1
|
||||
RULE: --cachemode --cachepolicy --cachesettings and LV_cache LV_cachepool
|
||||
RULE: --errorwhenfull --discards --zero and LV_thinpool
|
||||
RULE: --permission not lv_is_external_origin lv_is_raid_metadata lv_is_raid_image LV_thinpool
|
||||
RULE: --alloc --contiguous --metadataprofile --permission --persistent --profile --readahead not lv_is_thick_origin
|
||||
|
||||
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_resync
|
||||
DESC: Resyncronize a mirror or raid LV.
|
||||
RULE: all not lv_is_pvmove lv_is_locked
|
||||
RULE: all not LV_raid0
|
||||
|
||||
lvchange --syncaction String VG|LV_raid|Tag|Select ...
|
||||
lvchange --syncaction SyncAction VG|LV_raid|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_syncaction
|
||||
DESC: Resynchronize or check a raid LV.
|
||||
RULE: all not LV_raid0
|
||||
|
||||
lvchange --rebuild PV VG|LV_raid|Tag|Select ...
|
||||
OO: OO_LVCHANGE
|
||||
ID: lvchange_rebuild
|
||||
DESC: Reconstruct data on specific PVs of a raid LV.
|
||||
RULE: all not LV_raid0
|
||||
|
||||
# try removing the META change options from here?
|
||||
lvchange --activate Active VG|LV|Tag|Select ...
|
||||
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip, OO_LVCHANGE_META, OO_LVCHANGE
|
||||
OO: --activationmode ActivationMode, --partial, --ignoreactivationskip,
|
||||
--ignorelockingfailure, --sysinit, OO_LVCHANGE_META, OO_LVCHANGE
|
||||
ID: lvchange_activate
|
||||
DESC: Activate or deactivate an LV.
|
||||
|
||||
@@ -247,16 +290,18 @@ lvchange --monitor Bool VG|LV|Tag|Select ...
|
||||
OO: --poll Bool, OO_LVCHANGE
|
||||
ID: lvchange_monitor
|
||||
DESC: Start or stop monitoring an LV from dmeventd.
|
||||
RULE: all not lv_is_pvmove
|
||||
|
||||
lvchange --poll Bool VG|LV|Tag|Select ...
|
||||
OO: --monitor Bool, OO_LVCHANGE
|
||||
ID: lvchange_poll
|
||||
DESC: Start or stop processing an LV conversion.
|
||||
|
||||
lvchange --persistent Bool VG|LV|Tag|Select ...
|
||||
OO: --minor Number, --major Number, OO_LVCHANGE
|
||||
lvchange --persistent y --minor Number LV
|
||||
OO: --major Number, OO_LVCHANGE
|
||||
ID: lvchange_persistent
|
||||
DESC: Make the minor device number persistent for an LV.
|
||||
RULE: all not LV_thinpool LV_cachepool
|
||||
|
||||
---
|
||||
|
||||
@@ -266,63 +311,72 @@ OO_LVCONVERT_RAID: --mirrors SNumber, --stripes_long Number,
|
||||
OO_LVCONVERT_POOL: --poolmetadata LV, --poolmetadatasize SizeMB,
|
||||
--poolmetadataspare Bool, --readahead Readahead, --chunksize SizeKB
|
||||
|
||||
OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync,
|
||||
--usepolicies
|
||||
OO_LVCONVERT: --alloc Alloc, --background, --force, --noudevsync
|
||||
|
||||
---
|
||||
|
||||
# FIXME: lvconvert --merge is an extremely ambiguous command.
|
||||
# It can do very different operations, but which one depends
|
||||
# on knowing the LV type. So, the command doesn't know what
|
||||
# it's actually doing until quite late, when processing a
|
||||
# single LV.
|
||||
#
|
||||
# Use different option names for different merge operations
|
||||
# so that we can have different command definitions,
|
||||
# different behaviors, different optional options, etc:
|
||||
#
|
||||
# lvconvert --merge-mirror LV_linear_striped_raid ...
|
||||
# DESC: Merge LV that was previously split from a mirror.
|
||||
#
|
||||
# lvconvert --merge-thin LV_thin
|
||||
# DESC: Merge thin LV into its origin LV.
|
||||
#
|
||||
# lvconvert --merge-snapshot LV_snapshot
|
||||
# DESC: Merge COW snapshot LV into its origin.
|
||||
#
|
||||
# Then we could add VG|Tag to --merge-mirror arg pos 1, because
|
||||
# "lvconvert --merge VG|Tag" is a terrible command. It will do
|
||||
# different operations on each LV it finds, depending on the
|
||||
# current LV type.
|
||||
# These cover all the core, raid-related type conversions.
|
||||
# They are all routed into the core raid conversion code.
|
||||
|
||||
lvconvert --merge LV_linear_striped_raid_thin_snapshot|VG|Tag ...
|
||||
OO: --background, --interval Number, OO_LVCONVERT
|
||||
ID: lvconvert_merge
|
||||
DESC: Merge LV that was previously split from a mirror.
|
||||
DESC: Merge thin LV into its origin LV.
|
||||
DESC: Merge COW snapshot LV into its origin.
|
||||
lvconvert --type linear LV
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_types
|
||||
DESC: Convert LV to linear.
|
||||
RULE: all not lv_is_locked lv_is_pvmove
|
||||
|
||||
lvconvert --type striped LV
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_types
|
||||
DESC: Convert LV to striped.
|
||||
|
||||
lvconvert --type mirror LV
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_types
|
||||
DESC: Convert LV to type mirror (also see type raid1).
|
||||
|
||||
lvconvert --type raid LV
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_types
|
||||
DESC: Convert LV to raid.
|
||||
|
||||
lvconvert --mirrors SNumber LV
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT, --mirrorlog MirrorLog
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_types
|
||||
DESC: Convert LV to raid1 or mirror, or change number of mirror images.
|
||||
|
||||
---
|
||||
|
||||
# FIXME: by using two different positional args, this is the
|
||||
# single violation of the standard method of using process_each_lv().
|
||||
# Before calling process_each, it steals the first positional arg
|
||||
# and adjusts argv/argc so it's not seen by process_each.
|
||||
# lvconvert raid-related utilities
|
||||
# Create a new command set for these and migrate them out of lvconvert?
|
||||
|
||||
# alternate form of lvconvert --snapshot
|
||||
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
|
||||
OO: --snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
|
||||
ID: lvconvert_combine_split_snapshot
|
||||
DESC: Combine LV with a previously split snapshot LV.
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
lvconvert --splitmirrors Number --name LV_new LV_raid1_mirror_cache
|
||||
OO: OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_split_mirror_images
|
||||
DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
|
||||
|
||||
lvconvert --snapshot LV_linear_striped_raid LV_snapshot
|
||||
OO: --type snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
|
||||
ID: lvconvert_combine_split_snapshot
|
||||
DESC: Combine LV with a previously split snapshot LV.
|
||||
lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
|
||||
OO: OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_split_mirror_images
|
||||
DESC: Split images from a raid1 LV and track changes to origin.
|
||||
|
||||
lvconvert --mirrorlog MirrorLog LV_mirror
|
||||
OO: OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_change_mirrorlog
|
||||
DESC: Change the type of mirror log used by a mirror LV.
|
||||
|
||||
---
|
||||
|
||||
# lvconvert utilities for creating/maintaining thin and cache objects.
|
||||
# Create a new command set for these and migrate them out of lvconvert?
|
||||
|
||||
lvconvert --type thin --thinpool LV LV_linear_striped_raid
|
||||
OO: --thin, --originname LV_new, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||
ID: lvconvert_to_thin_with_external
|
||||
@@ -357,6 +411,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
lvconvert --type thin-pool LV_linear_striped_raid_cache
|
||||
OO: --stripes_long Number, --stripesize SizeKB,
|
||||
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_thinpool
|
||||
DESC: Convert LV to type thin-pool.
|
||||
|
||||
@@ -365,6 +420,7 @@ DESC: Convert LV to type thin-pool.
|
||||
lvconvert --thinpool LV_linear_striped_raid_cache
|
||||
OO: --type thin-pool, --stripes_long Number, --stripesize SizeKB,
|
||||
--discards Discards, --zero Bool, OO_LVCONVERT_POOL, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_thinpool
|
||||
DESC: Convert LV to type thin-pool (variant, use --type thin-pool).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
@@ -374,6 +430,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
lvconvert --type cache-pool LV_linear_striped_raid
|
||||
OO: OO_LVCONVERT_POOL, OO_LVCONVERT,
|
||||
--cachemode CacheMode, --cachepolicy String, --cachesettings String
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_cachepool
|
||||
DESC: Convert LV to type cache-pool.
|
||||
|
||||
@@ -388,109 +445,83 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
# FIXME: we should be able to remove LV_mirror from the list of accepted
|
||||
# LV types, but there are some dubious commands in the test suite that
|
||||
# fail without it (the tests should be cleaned up to avoid using commands
|
||||
# that don't make sense.)
|
||||
#
|
||||
# FIXME: it would be nice to remove LV_raid1 from the list of accepted
|
||||
# LV types and let raid1 be covered by just the second definition, but
|
||||
# unfortunatley lvconvert --type mirror --mirrors N LV_raid1 will
|
||||
# match the first definition since the LV type cannot be used when
|
||||
# choosing a matching command definition.
|
||||
|
||||
lvconvert --type mirror --mirrors SNumber LV_linear_striped_raid1_mirror
|
||||
OO: --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_mirror
|
||||
DESC: Convert LV to type mirror.
|
||||
|
||||
lvconvert --type mirror LV_raid1
|
||||
OO: --mirrors SNumber, OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_mirror
|
||||
DESC: Convert LV from type raid1 to type mirror.
|
||||
|
||||
---
|
||||
|
||||
lvconvert --type raid LV_linear_striped_mirror_raid
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_raid
|
||||
DESC: Convert LV to type raid.
|
||||
DESC: Change LV between raid types.
|
||||
|
||||
---
|
||||
|
||||
# FIXME: there are two unique operations here that differ
|
||||
# by only the LV type, so they have to be defined together.
|
||||
# We don't know what this command is going to do until after
|
||||
# the LV is read. It would be better if the alternate form
|
||||
# variant were dropped to remove the ambiguity
|
||||
# (then --type raid1|mirror would be required to change a
|
||||
# linear or striped LV to raid1|mirror.)
|
||||
#
|
||||
# First command definition
|
||||
# this changes the number of mirror images in a raid1|mirror LV.
|
||||
# lvconvert --mirrors SNumber LV_raid_mirror
|
||||
# ID: lvconvert_change_mirror_images
|
||||
# DESC: Change the number of mirror images in the LV.
|
||||
#
|
||||
# Second command definition
|
||||
# alternate form of: lvconvert --type raid1|mirror LV_linear_striped
|
||||
# lvconvert --mirrors SNumber LV_linear_striped
|
||||
# ID: lvconvert_to_raid1_or_mirror
|
||||
# DESC: Convert LV to type raid1 or mirror
|
||||
# DESC: (variant, infers --type raid1|mirror).
|
||||
|
||||
# first def is unique, second def is alternate form of lvconvert --type raid1|mirror
|
||||
lvconvert --mirrors SNumber LV_raid_mirror_linear_striped
|
||||
OO: --type raid1, --type mirror, --mirrorlog MirrorLog, OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_to_mirrored_or_change_image_count
|
||||
DESC: Change the number of mirror images in a raid1 or mirror LV.
|
||||
DESC: Convert a linear or striped LV to type raid1 or mirror
|
||||
DESC: (variant, infers --type raid1|mirror).
|
||||
|
||||
---
|
||||
|
||||
lvconvert --type striped LV_raid
|
||||
OO: OO_LVCONVERT_RAID, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_raid_to_striped
|
||||
DESC: Convert LV to type striped.
|
||||
|
||||
---
|
||||
|
||||
lvconvert --type linear LV_raid_mirror
|
||||
lvconvert --splitcache LV_cachepool_cache_thinpool
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_raid_or_mirror_to_linear
|
||||
DESC: Convert LV to type linear.
|
||||
ID: lvconvert_split_and_keep_cachepool
|
||||
DESC: Separate and keep the cache pool from a cache LV.
|
||||
|
||||
# FIXME: the 'mirrors 0' trick as an alias for linear
|
||||
# is used inconsistently, confusing things and making
|
||||
# definitions difficult.
|
||||
---
|
||||
|
||||
# alternate form of lvconvert --type linear
|
||||
lvconvert --mirrors 0 LV_raid_mirror
|
||||
OO: --type linear, --type mirror, OO_LVCONVERT
|
||||
ID: lvconvert_raid_or_mirror_to_linear
|
||||
DESC: Convert LV to type linear (variant, infers --type linear).
|
||||
lvconvert --uncache LV_cache_thinpool
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_split_and_delete_cachepool
|
||||
DESC: Separate and delete the cache pool from a cache LV.
|
||||
|
||||
---
|
||||
|
||||
# FIXME: add a new option defining this operation, e.g. --swapmetadata
|
||||
|
||||
lvconvert --poolmetadata LV LV_thinpool_cachepool
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_swap_pool_metadata
|
||||
DESC: Swap metadata LV in a thin pool or cache pool (temporary command).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
lvconvert --splitmirrors Number --name LV_new LV_raid1_mirror_cache
|
||||
OO: OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_split_mirror_images_to_new
|
||||
DESC: Split images from a raid1 or mirror LV and use them to create a new LV.
|
||||
# lvconvert utilities related to snapshots and repair.
|
||||
# Create a new command set for these and migrate them out of lvconvert?
|
||||
|
||||
lvconvert --splitmirrors Number --trackchanges LV_raid1_cache
|
||||
OO: OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_split_mirror_images_and_track
|
||||
DESC: Split images from a raid1 LV and track changes to origin.
|
||||
# FIXME: lvconvert --merge is an extremely ambiguous command.
|
||||
# It can do very different operations, but which one depends
|
||||
# on knowing the LV type. So, the command doesn't know what
|
||||
# it's actually doing until quite late, when processing a
|
||||
# single LV.
|
||||
#
|
||||
# Use different option names for different merge operations
|
||||
# so that we can have different command definitions,
|
||||
# different behaviors, different optional options, etc:
|
||||
#
|
||||
# lvconvert --merge-mirror LV_linear_striped_raid ...
|
||||
# DESC: Merge LV that was previously split from a mirror.
|
||||
#
|
||||
# lvconvert --merge-thin LV_thin
|
||||
# DESC: Merge thin LV into its origin LV.
|
||||
#
|
||||
# lvconvert --merge-snapshot LV_snapshot
|
||||
# DESC: Merge COW snapshot LV into its origin.
|
||||
#
|
||||
# Then we could add VG|Tag to --merge-mirror arg pos 1, because
|
||||
# "lvconvert --merge VG|Tag" is a terrible command. It will do
|
||||
# different operations on each LV it finds, depending on the
|
||||
# current LV type.
|
||||
|
||||
lvconvert --merge LV_linear_striped_raid_thin_snapshot|VG|Tag ...
|
||||
OO: --background, --interval Number, OO_LVCONVERT
|
||||
ID: lvconvert_merge
|
||||
DESC: Merge LV that was previously split from a mirror.
|
||||
DESC: Merge thin LV into its origin LV.
|
||||
DESC: Merge COW snapshot LV into its origin.
|
||||
RULE: all not lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
|
||||
|
||||
---
|
||||
|
||||
# FIXME: by using two different positional args, this is the
|
||||
# single violation of the standard method of using process_each_lv().
|
||||
# Before calling process_each, it steals the first positional arg
|
||||
# and adjusts argv/argc so it's not seen by process_each.
|
||||
|
||||
# alternate form of lvconvert --snapshot
|
||||
lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
|
||||
OO: --snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
|
||||
ID: lvconvert_combine_split_snapshot
|
||||
DESC: Combine LV with a previously split snapshot LV.
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
lvconvert --snapshot LV_linear_striped_raid LV_snapshot
|
||||
OO: --type snapshot, --chunksize SizeKB, --zero Bool, OO_LVCONVERT
|
||||
ID: lvconvert_combine_split_snapshot
|
||||
DESC: Combine LV with a previously split snapshot LV.
|
||||
|
||||
---
|
||||
|
||||
@@ -509,7 +540,8 @@ DESC: Split images from a raid1 LV and track changes to origin.
|
||||
# and the LV type is known.
|
||||
|
||||
lvconvert --repair LV_raid_mirror_thinpool
|
||||
OO: OO_LVCONVERT
|
||||
OO: --usepolicies, OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_repair_pvs_or_thinpool
|
||||
DESC: Replace failed PVs in a raid or mirror LV.
|
||||
DESC: Repair a thin pool.
|
||||
@@ -524,28 +556,6 @@ DESC: Replace specific PV(s) in a raid* LV with another PV.
|
||||
|
||||
---
|
||||
|
||||
lvconvert --mirrorlog MirrorLog LV_mirror
|
||||
OO: OO_LVCONVERT
|
||||
OP: PV ...
|
||||
ID: lvconvert_change_mirrorlog
|
||||
DESC: Change the type of mirror log used by a mirror LV.
|
||||
|
||||
---
|
||||
|
||||
lvconvert --splitcache LV_cachepool_cache_thinpool
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_split_and_keep_cachepool
|
||||
DESC: Separate and keep the cache pool from a cache LV.
|
||||
|
||||
---
|
||||
|
||||
lvconvert --uncache LV_cache_thinpool
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_split_and_delete_cachepool
|
||||
DESC: Separate and delete the cache pool from a cache LV.
|
||||
|
||||
---
|
||||
|
||||
lvconvert --splitsnapshot LV_snapshot
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_split_cow_snapshot
|
||||
@@ -558,29 +568,19 @@ DESC: Separate a COW snapshot from its origin LV.
|
||||
|
||||
lvconvert LV_mirror
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_poll_mirror
|
||||
ID: lvconvert_poll_start
|
||||
DESC: Poll mirror LV to collapse resync layers.
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
# FIXME: add a new option defining this operation, e.g. --swapmetadata
|
||||
|
||||
lvconvert --poolmetadata LV LV_thinpool_cachepool
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_swap_pool_metadata
|
||||
DESC: Swap metadata LV in a thin pool or cache pool (temporary command).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
# --extents is not specified; it's an automatic alternative for --size
|
||||
|
||||
OO_LVCREATE: --addtag Tag, --alloc Alloc, --autobackup Bool, --activate Active,
|
||||
--contiguous Bool, --ignoreactivationskip, --ignoremonitoring, --major Number,
|
||||
--metadataprofile String, --minor Number, --monitor Bool, --name String, --nosync,
|
||||
--noudevsync, --permission Permission, --persistent Bool, --readahead Readahead,
|
||||
--reportformat String, --setactivationskip Bool, --wipesignatures Bool,
|
||||
--reportformat ReportFmt, --setactivationskip Bool, --wipesignatures Bool,
|
||||
--zero Bool
|
||||
|
||||
OO_LVCREATE_CACHE: --cachemode CacheMode, --cachepolicy String, --cachesettings String
|
||||
@@ -1005,10 +1005,10 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
lvdisplay
|
||||
OO: --aligned, --all, --binary, --colon, --columns,
|
||||
--configreport String, --foreign, --history, --ignorelockingfailure,
|
||||
--configreport ConfigReport, --foreign, --history, --ignorelockingfailure,
|
||||
--ignoreskippedcluster, --logonly, --maps, --noheadings,
|
||||
--nosuffix, --options String, --sort String, --partial, --readonly,
|
||||
--reportformat String, --segments, --select String, --separator String,
|
||||
--reportformat ReportFmt, --segments, --select String, --separator String,
|
||||
--shared, --unbuffered, --units Units
|
||||
OP: VG|LV|Tag ...
|
||||
ID: lvdisplay_general
|
||||
@@ -1019,7 +1019,7 @@ ID: lvdisplay_general
|
||||
|
||||
lvextend --size SizeMB LV
|
||||
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
|
||||
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
|
||||
--nofsck, --nosync, --noudevsync, --reportformat ReportFmt, --resizefs,
|
||||
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
|
||||
OP: PV ...
|
||||
ID: lvextend_by_size
|
||||
@@ -1028,7 +1028,7 @@ DESC: Extend an LV by a specified size.
|
||||
lvextend LV PV ...
|
||||
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
|
||||
--nofsck, --nosync, --noudevsync,
|
||||
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
|
||||
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB
|
||||
ID: lvextend_by_pv
|
||||
DESC: Extend an LV by specified PV extents.
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
@@ -1036,7 +1036,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
lvextend --poolmetadatasize SizeMB LV_thinpool
|
||||
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
|
||||
--nofsck, --nosync, --noudevsync,
|
||||
--reportformat String, --stripes Number, --stripesize SizeKB
|
||||
--reportformat ReportFmt, --stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
ID: lvextend_pool_metadata_by_size
|
||||
DESC: Extend a pool metadata SubLV by a specified size.
|
||||
@@ -1044,7 +1044,8 @@ DESC: Extend a pool metadata SubLV by a specified size.
|
||||
lvextend --usepolicies LV_thinpool_snapshot
|
||||
OO: --alloc Alloc, --autobackup Bool, --force, --mirrors SNumber,
|
||||
--nofsck, --nosync, --noudevsync,
|
||||
--reportformat String, --resizefs
|
||||
--reportformat ReportFmt, --resizefs
|
||||
OP: PV ...
|
||||
ID: lvextend_by_policy
|
||||
DESC: Extend an LV according to a predefined policy.
|
||||
|
||||
@@ -1052,37 +1053,38 @@ DESC: Extend an LV according to a predefined policy.
|
||||
|
||||
lvmconfig
|
||||
OO: OO_CONFIG
|
||||
OP: String ...
|
||||
ID: lvmconfig_general
|
||||
|
||||
---
|
||||
|
||||
lvreduce --size SizeMB LV
|
||||
OO: --autobackup Bool, --force, --nofsck, --noudevsync,
|
||||
--reportformat String, --resizefs
|
||||
--reportformat ReportFmt, --resizefs
|
||||
ID: lvreduce_general
|
||||
|
||||
---
|
||||
|
||||
lvremove VG|LV|Tag|Select ...
|
||||
OO: --autobackup Bool, --force, --nohistory, --noudevsync,
|
||||
--reportformat String, --select String
|
||||
--reportformat ReportFmt, --select String
|
||||
ID: lvremove_general
|
||||
|
||||
---
|
||||
|
||||
lvrename VG LV LV_new
|
||||
OO: --autobackup Bool, --noudevsync, --reportformat String
|
||||
OO: --autobackup Bool, --noudevsync, --reportformat ReportFmt
|
||||
ID: lvrename_vg_lv_lv
|
||||
|
||||
lvrename LV LV_new
|
||||
OO: --autobackup Bool, --noudevsync, --reportformat String
|
||||
OO: --autobackup Bool, --noudevsync, --reportformat ReportFmt
|
||||
ID: lvrename_lv_lv
|
||||
|
||||
---
|
||||
|
||||
lvresize --size SizeMB LV
|
||||
OO: --alloc Alloc, --autobackup Bool, --force,
|
||||
--nofsck, --nosync, --noudevsync, --reportformat String, --resizefs,
|
||||
--nofsck, --nosync, --noudevsync, --reportformat ReportFmt, --resizefs,
|
||||
--stripes Number, --stripesize SizeKB, --poolmetadatasize SizeMB
|
||||
OP: PV ...
|
||||
ID: lvresize_by_size
|
||||
@@ -1091,7 +1093,7 @@ DESC: Resize an LV by a specified size.
|
||||
lvresize LV PV ...
|
||||
OO: --alloc Alloc, --autobackup Bool, --force,
|
||||
--nofsck, --nosync, --noudevsync,
|
||||
--reportformat String, --resizefs, --stripes Number, --stripesize SizeKB
|
||||
--reportformat ReportFmt, --resizefs, --stripes Number, --stripesize SizeKB
|
||||
ID: lvresize_by_pv
|
||||
DESC: Resize an LV by specified PV extents.
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
@@ -1099,7 +1101,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
lvresize --poolmetadatasize SizeMB LV_thinpool
|
||||
OO: --alloc Alloc, --autobackup Bool, --force,
|
||||
--nofsck, --nosync, --noudevsync,
|
||||
--reportformat String, --stripes Number, --stripesize SizeKB
|
||||
--reportformat ReportFmt, --stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
ID: lvresize_pool_metadata_by_size
|
||||
DESC: Resize a pool metadata SubLV by a specified size.
|
||||
@@ -1115,14 +1117,20 @@ ID: lvs_general
|
||||
|
||||
lvscan
|
||||
OO: --all, --blockdevice, --ignorelockingfailure, --partial,
|
||||
--readonly, --reportformat String, --cache_long
|
||||
--readonly, --reportformat ReportFmt
|
||||
ID: lvscan_general
|
||||
|
||||
lvscan --cache_long
|
||||
OO: --blockdevice, --ignorelockingfailure, --partial,
|
||||
--readonly, --reportformat ReportFmt
|
||||
OP: LV ...
|
||||
ID: lvscan_cache
|
||||
|
||||
---
|
||||
|
||||
# None of these can function as a required option for pvchange.
|
||||
OO_PVCHANGE: --autobackup Bool, --force, --ignoreskippedcluster,
|
||||
--reportformat String, --uuid
|
||||
--reportformat ReportFmt, --uuid
|
||||
|
||||
# Any of these can function as a required option for pvchange.
|
||||
OO_PVCHANGE_META: --allocatable Bool, --addtag Tag, --deltag Tag,
|
||||
@@ -1141,7 +1149,7 @@ DESC: Change properties of specified PVs.
|
||||
---
|
||||
|
||||
pvresize PV ...
|
||||
OO: --setphysicalvolumesize SizeMB, --reportformat String
|
||||
OO: --setphysicalvolumesize SizeMB, --reportformat ReportFmt
|
||||
ID: pvresize_general
|
||||
|
||||
---
|
||||
@@ -1160,16 +1168,16 @@ OO: --dataalignment SizeKB, --dataalignmentoffset SizeKB, --bootloaderareasize S
|
||||
--force, --labelsector Number, --metadatatype MetadataType,
|
||||
--pvmetadatacopies MetadataCopiesPV, --metadatasize SizeMB,
|
||||
--metadataignore Bool, --norestorefile, --setphysicalvolumesize SizeMB,
|
||||
--reportformat String, --restorefile String, --uuidstr String, --zero Bool
|
||||
--reportformat ReportFmt, --restorefile String, --uuidstr String, --zero Bool
|
||||
ID: pvcreate_general
|
||||
|
||||
---
|
||||
|
||||
pvdisplay
|
||||
OO: --aligned, --all, --binary, --colon, --columns, --configreport String,
|
||||
OO: --aligned, --all, --binary, --colon, --columns, --configreport ConfigReport,
|
||||
--foreign, --ignorelockingfailure, --ignoreskippedcluster,
|
||||
--logonly, --maps, --noheadings, --nosuffix, --options String,
|
||||
--readonly, --reportformat String, --select String, --separator String, --shared,
|
||||
--readonly, --reportformat ReportFmt, --select String, --separator String, --shared,
|
||||
--short, --sort String, --unbuffered, --units Units
|
||||
OP: PV|Tag ...
|
||||
ID: pvdisplay_general
|
||||
@@ -1178,20 +1186,20 @@ ID: pvdisplay_general
|
||||
|
||||
pvmove PV
|
||||
OO: --abort, --alloc Alloc, --atomic, --autobackup Bool, --background,
|
||||
--interval Number, --name LV, --noudevsync, --reportformat String
|
||||
--interval Number, --name LV, --noudevsync, --reportformat ReportFmt
|
||||
OP: PV ...
|
||||
ID: pvmove_one
|
||||
DESC: Move PV extents.
|
||||
|
||||
pvmove
|
||||
OO: --abort, --background
|
||||
OO: --abort, --background, --interval Number
|
||||
ID: pvmove_any
|
||||
DESC: Continue or abort existing pvmove operations.
|
||||
|
||||
---
|
||||
|
||||
pvremove PV ...
|
||||
OO: --force, --reportformat String
|
||||
OO: --force, --reportformat ReportFmt
|
||||
ID: pvremove_general
|
||||
|
||||
---
|
||||
@@ -1204,14 +1212,14 @@ ID: pvs_general
|
||||
---
|
||||
|
||||
pvscan
|
||||
OO: --ignorelockingfailure, --reportformat String, --exported, --novolumegroup,
|
||||
OO: --ignorelockingfailure, --reportformat ReportFmt, --exported, --novolumegroup,
|
||||
--short, --uuid
|
||||
ID: pvscan_show
|
||||
DESC: Display PV information.
|
||||
|
||||
pvscan --cache_long
|
||||
OO: --ignorelockingfailure, --reportformat String, --background,
|
||||
--activate Active, --major Number, --minor Number,
|
||||
OO: --ignorelockingfailure, --reportformat ReportFmt, --background,
|
||||
--activate Active, --major Number, --minor Number
|
||||
OP: PV|String ...
|
||||
ID: pvscan_cache
|
||||
DESC: Populate the lvmetad cache by scanning PVs.
|
||||
@@ -1220,25 +1228,45 @@ DESC: Populate the lvmetad cache by scanning PVs.
|
||||
|
||||
vgcfgbackup
|
||||
OO: --file String, --foreign, --ignorelockingfailure, --partial, --readonly,
|
||||
--reportformat String
|
||||
--reportformat ReportFmt
|
||||
OP: VG ...
|
||||
ID: vgcfgbackup_general
|
||||
|
||||
---
|
||||
|
||||
OO_VGCFGRESTORE: --force_long, --metadatatype MetadataType
|
||||
|
||||
vgcfgrestore VG
|
||||
OO: --file String, --force_long, --list, --metadatatype MetadataType
|
||||
OO: OO_VGCFGRESTORE
|
||||
ID: vgcfgrestore_by_vg
|
||||
DESC: Restore VG metadata from last backup.
|
||||
|
||||
vgcfgrestore --file String VG
|
||||
OO: OO_VGCFGRESTORE
|
||||
ID: vgcfgrestore_by_file
|
||||
DESC: Restore VG metadata from specified file.
|
||||
|
||||
vgcfgrestore --list VG
|
||||
OO: OO_VGCFGRESTORE
|
||||
ID: vgcfgrestore_list_by_vg
|
||||
DESC: List all VG metadata backups.
|
||||
|
||||
# FIXME: the optional VG pos arg is not used or checked and can be
|
||||
# anything, but a test in the test suite uses it. Fix the test or
|
||||
# verify that the positional VG is correct?
|
||||
|
||||
vgcfgrestore --list --file String
|
||||
ID: vgcfgrestore_by_file
|
||||
OO: OO_VGCFGRESTORE
|
||||
OP: VG
|
||||
ID: vgcfgrestore_list_by_file
|
||||
DESC: List one VG metadata backup file.
|
||||
|
||||
---
|
||||
|
||||
# None of these can function as a required option for vgchange.
|
||||
|
||||
OO_VGCHANGE: --autobackup Bool, --ignoremonitoring, --ignoreskippedcluster,
|
||||
--noudevsync, --reportformat String, --select String, --force
|
||||
--noudevsync, --reportformat ReportFmt, --select String, --force
|
||||
|
||||
# Any of these can function as a required option for vgchange.
|
||||
# profile is also part of OO_ALL, but is repeated in OO_VGCHANGE_META
|
||||
@@ -1248,7 +1276,7 @@ OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
|
||||
--logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid,
|
||||
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
|
||||
--profile String, --detachprofile, --metadataprofile String,
|
||||
--profile String, --detachprofile, --metadataprofile String
|
||||
|
||||
vgchange OO_VGCHANGE_META
|
||||
OO: OO_VGCHANGE
|
||||
@@ -1296,7 +1324,7 @@ DESC: Stop the lockspace of a shared VG in lvmlockd.
|
||||
---
|
||||
|
||||
vgck
|
||||
OO: --reportformat String
|
||||
OO: --reportformat ReportFmt
|
||||
OP: VG|Tag ...
|
||||
ID: vgck_general
|
||||
|
||||
@@ -1305,7 +1333,7 @@ ID: vgck_general
|
||||
vgconvert VG ...
|
||||
OO: --force, --labelsector Number, --bootloaderareasize SizeMB,
|
||||
--metadatatype MetadataType, --pvmetadatacopies MetadataCopiesPV,
|
||||
--metadatasize SizeMB, --reportformat String
|
||||
--metadatasize SizeMB, --reportformat ReportFmt
|
||||
ID: vgconvert_general
|
||||
|
||||
---
|
||||
@@ -1315,7 +1343,7 @@ OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogic
|
||||
--maxphysicalvolumes Number, --metadataprofile String, --metadatatype MetadataType,
|
||||
--physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number,
|
||||
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||
--reportformat String, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
|
||||
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
|
||||
--shared, --systemid String, --locktype LockType, --lockopt String
|
||||
ID: vgcreate_general
|
||||
|
||||
@@ -1323,16 +1351,16 @@ ID: vgcreate_general
|
||||
|
||||
vgdisplay
|
||||
OO: --activevolumegroups, --aligned, --binary, --colon, --columns,
|
||||
--configreport String, --foreign, --ignorelockingfailure,
|
||||
--configreport ConfigReport, --foreign, --ignorelockingfailure,
|
||||
--ignoreskippedcluster, --logonly, --noheadings, --nosuffix,
|
||||
--options String, --partial, --readonly, --reportformat String, --select String,
|
||||
--options String, --partial, --readonly, --reportformat ReportFmt, --select String,
|
||||
--shared, --short, --separator String, --sort String, --unbuffered, --units Units
|
||||
OP: VG|Tag ...
|
||||
ID: vgdisplay_general
|
||||
|
||||
---
|
||||
|
||||
OO_VGEXPORT: --reportformat String
|
||||
OO_VGEXPORT: --reportformat ReportFmt
|
||||
|
||||
vgexport VG|Tag|Select ...
|
||||
OO: --select String, OO_VGEXPORT
|
||||
@@ -1352,12 +1380,12 @@ OO: --autobackup Bool,
|
||||
--force, --zero Bool, --labelsector Number, --metadatatype MetadataType,
|
||||
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV,
|
||||
--metadataignore Bool, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
|
||||
--reportformat String, --restoremissing
|
||||
--reportformat ReportFmt, --restoremissing
|
||||
ID: vgextend_general
|
||||
|
||||
---
|
||||
|
||||
OO_VGIMPORT: --force, --reportformat String
|
||||
OO_VGIMPORT: --force, --reportformat ReportFmt
|
||||
|
||||
vgimport VG|Tag|Select ...
|
||||
OO: --select String, OO_VGIMPORT
|
||||
@@ -1384,13 +1412,13 @@ ID: vgmerge_general
|
||||
---
|
||||
|
||||
vgmknodes
|
||||
OO: --ignorelockingfailure, --refresh, --reportformat String
|
||||
OO: --ignorelockingfailure, --refresh, --reportformat ReportFmt
|
||||
OP: VG|LV|Tag ...
|
||||
ID: vgmknodes_general
|
||||
|
||||
---
|
||||
|
||||
OO_VGREDUCE: --autobackup Bool, --force, --reportformat String
|
||||
OO_VGREDUCE: --autobackup Bool, --force, --reportformat ReportFmt
|
||||
|
||||
vgreduce VG PV ...
|
||||
OO: OO_VGREDUCE
|
||||
@@ -1410,18 +1438,18 @@ DESC: Remove all missing PVs from a VG.
|
||||
---
|
||||
|
||||
vgremove VG|Tag|Select ...
|
||||
OO: --force, --noudevsync, --reportformat String, --select String
|
||||
OO: --force, --noudevsync, --reportformat ReportFmt, --select String
|
||||
ID: vgremove_general
|
||||
|
||||
---
|
||||
|
||||
vgrename VG VG_new
|
||||
OO: --autobackup Bool, --force, --reportformat String
|
||||
OO: --autobackup Bool, --force, --reportformat ReportFmt
|
||||
ID: vgrename_by_name
|
||||
DESC: Rename a VG.
|
||||
|
||||
vgrename String VG_new
|
||||
OO: --autobackup Bool, --force, --reportformat String
|
||||
OO: --autobackup Bool, --force, --reportformat ReportFmt
|
||||
ID: vgrename_by_uuid
|
||||
DESC: Rename a VG by specifying the VG UUID.
|
||||
|
||||
@@ -1436,7 +1464,7 @@ ID: vgs_general
|
||||
|
||||
vgscan
|
||||
OO: --cache_long, --ignorelockingfailure, --mknodes, --notifydbus,
|
||||
--partial, --reportformat String
|
||||
--partial, --reportformat ReportFmt
|
||||
ID: vgscan_general
|
||||
|
||||
---
|
||||
@@ -1462,19 +1490,23 @@ DESC: Split a VG by PVs in a specified LV.
|
||||
|
||||
# built-in and deprecated commands
|
||||
|
||||
# use lvmconfig
|
||||
config
|
||||
OO: OO_CONFIG
|
||||
OP: String ...
|
||||
ID: lvmconfig_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
# use lvmconfig
|
||||
dumpconfig
|
||||
OO: OO_CONFIG
|
||||
OP: String ...
|
||||
ID: lvmconfig_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
devtypes
|
||||
OO: --aligned, --binary, --nameprefixes, --noheadings,
|
||||
--nosuffix, --options String, --reportformat String, --rows,
|
||||
--nosuffix, --options String, --reportformat ReportFmt, --rows,
|
||||
--select String, --separator String, --sort String, --unbuffered, --unquoted
|
||||
ID: devtypes_general
|
||||
|
||||
@@ -1484,10 +1516,10 @@ OP: VG ...
|
||||
ID: fullreport_general
|
||||
|
||||
lastlog
|
||||
OO: --reportformat String, --select String
|
||||
OO: --reportformat ReportFmt, --select String
|
||||
ID: lastlog_general
|
||||
|
||||
lvpoll --polloperation String LV ...
|
||||
lvpoll --polloperation PollOp LV ...
|
||||
OO: --abort, --autobackup Bool, --handlemissingpvs, --interval Number
|
||||
ID: lvpoll_general
|
||||
|
||||
@@ -1500,8 +1532,10 @@ ID: help_general
|
||||
version
|
||||
ID: version_general
|
||||
|
||||
# deprecated
|
||||
pvdata
|
||||
ID: pvdata_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
segtypes
|
||||
ID: segtypes_general
|
||||
@@ -1512,17 +1546,25 @@ ID: systemid_general
|
||||
tags
|
||||
ID: tags_general
|
||||
|
||||
# deprecated
|
||||
lvmchange
|
||||
ID: lvmchange_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
# deprecated
|
||||
lvmdiskscan
|
||||
OO: --lvmpartition, --readonly
|
||||
ID: lvmdiskscan_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
# deprecated
|
||||
lvmsadc
|
||||
ID: lvmsadc_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
# deprecated
|
||||
lvmsar
|
||||
OO: --full, --stdin
|
||||
ID: lvmsar_general
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
|
||||
@@ -54,27 +54,6 @@ struct command_name {
|
||||
#define ARG_DEF_FLAG_NEW 1 << 0
|
||||
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
|
||||
|
||||
/* arg_def lv_types */
|
||||
enum {
|
||||
ARG_DEF_LV_ANY = 0,
|
||||
ARG_DEF_LV_LINEAR = 1 << 0,
|
||||
ARG_DEF_LV_STRIPED = 1 << 1,
|
||||
ARG_DEF_LV_SNAPSHOT = 1 << 2,
|
||||
ARG_DEF_LV_MIRROR = 1 << 3,
|
||||
ARG_DEF_LV_RAID = 1 << 4,
|
||||
ARG_DEF_LV_RAID0 = 1 << 5,
|
||||
ARG_DEF_LV_RAID1 = 1 << 6,
|
||||
ARG_DEF_LV_RAID4 = 1 << 7,
|
||||
ARG_DEF_LV_RAID5 = 1 << 8,
|
||||
ARG_DEF_LV_RAID6 = 1 << 9,
|
||||
ARG_DEF_LV_RAID10 = 1 << 10,
|
||||
ARG_DEF_LV_THIN = 1 << 11,
|
||||
ARG_DEF_LV_THINPOOL = 1 << 12,
|
||||
ARG_DEF_LV_CACHE = 1 << 13,
|
||||
ARG_DEF_LV_CACHEPOOL = 1 << 14,
|
||||
ARG_DEF_LV_LAST = 1 << 15,
|
||||
};
|
||||
|
||||
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
|
||||
{
|
||||
return (val_bits & (1 << val_enum)) ? 1 : 0;
|
||||
@@ -82,16 +61,36 @@ static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
|
||||
|
||||
static inline uint64_t val_enum_to_bit(int val_enum)
|
||||
{
|
||||
return 1 << val_enum;
|
||||
return (1ULL << val_enum);
|
||||
}
|
||||
|
||||
static inline int lvp_bit_is_set(uint64_t lvp_bits, int lvp_enum)
|
||||
{
|
||||
return (lvp_bits & (1 << lvp_enum)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline uint64_t lvp_enum_to_bit(int lvp_enum)
|
||||
{
|
||||
return (1ULL << lvp_enum);
|
||||
}
|
||||
|
||||
static inline int lvt_bit_is_set(uint64_t lvt_bits, int lvt_enum)
|
||||
{
|
||||
return (lvt_bits & (1 << lvt_enum)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline uint64_t lvt_enum_to_bit(int lvt_enum)
|
||||
{
|
||||
return (1ULL << lvt_enum);
|
||||
}
|
||||
|
||||
/* Description a value that follows an option or exists in a position. */
|
||||
|
||||
struct arg_def {
|
||||
uint64_t val_bits; /* bits of x_VAL, can be multiple for pos_arg */
|
||||
uint64_t lvt_bits; /* lvt_enum_to_bit(x_LVT) for lv_VAL, can be multiple */
|
||||
uint64_t num; /* a literal number for conststr_VAL */
|
||||
const char *str; /* a literal string for constnum_VAL */
|
||||
uint32_t lv_types; /* ARG_DEF_LV_, for lv_VAL, can be multiple */
|
||||
uint32_t flags; /* ARG_DEF_FLAG_ */
|
||||
};
|
||||
|
||||
@@ -109,6 +108,33 @@ struct pos_arg {
|
||||
struct arg_def def; /* defines accepted values */
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Commands using a given command definition must follow a set
|
||||
* of rules. If a given command+LV matches the conditions in
|
||||
* opts/lvt_bits/lvp_bits, then the checks are applied.
|
||||
* If one condition is not met, the checks are not applied.
|
||||
* If no conditions are set, the checks are always applied.
|
||||
*/
|
||||
|
||||
#define RULE_INVALID 1
|
||||
#define RULE_REQUIRE 2
|
||||
|
||||
struct cmd_rule {
|
||||
int *opts; /* if any option in this list is set, the check may apply */
|
||||
uint64_t lvt_bits; /* if LV has one of these types (lvt_enum_to_bit), the check may apply */
|
||||
uint64_t lvp_bits; /* if LV has all of these properties (lvp_enum_to_bit), the check may apply */
|
||||
|
||||
int *check_opts; /* used options must [not] be in this list */
|
||||
uint64_t check_lvt_bits; /* LV must [not] have one of these type */
|
||||
uint64_t check_lvp_bits; /* LV must [not] have all of these properties */
|
||||
|
||||
uint32_t rule; /* RULE_INVALID, RULE_REQUIRE: check values must [not] be true */
|
||||
int opts_count; /* entries in opts[] */
|
||||
int check_opts_count; /* entries in check_opts[] */
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* CMD_RO_ARGS needs to accomodate a list of options,
|
||||
* of which one is required after which the rest are
|
||||
@@ -118,6 +144,7 @@ struct pos_arg {
|
||||
#define CMD_OO_ARGS 150 /* optional opt args */
|
||||
#define CMD_RP_ARGS 8 /* required positional args */
|
||||
#define CMD_OP_ARGS 8 /* optional positional args */
|
||||
#define CMD_MAX_RULES 32 /* max number of rules per command def */
|
||||
|
||||
/*
|
||||
* one or more from required_opt_args is required,
|
||||
@@ -158,6 +185,8 @@ struct command {
|
||||
/* optional positional args */
|
||||
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
||||
|
||||
struct cmd_rule rules[CMD_MAX_RULES];
|
||||
|
||||
int ro_count;
|
||||
int oo_count;
|
||||
int rp_count;
|
||||
@@ -165,6 +194,8 @@ struct command {
|
||||
|
||||
/* used for processing current position */
|
||||
int pos_count;
|
||||
|
||||
int rule_count;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
56
tools/lv_props.h
Normal file
56
tools/lv_props.h
Normal file
@@ -0,0 +1,56 @@
|
||||
|
||||
/*
|
||||
* NULL in the last arg can be replaced with actual
|
||||
* calls to the lv_is_prop() function when those
|
||||
* become functions (are #define now), take uniform
|
||||
* args (e.g. some take cmd others don't), and are
|
||||
* exposed in tools.h
|
||||
*
|
||||
* Until then, the lv_is_prop() functions are
|
||||
* called indirectly through _lv_is_prop().
|
||||
*/
|
||||
|
||||
lvp(LVP_NONE, "", NULL) /* enum value 0 means none */
|
||||
lvp(is_locked_LVP, "lv_is_locked", NULL)
|
||||
lvp(is_partial_LVP, "lv_is_partial", NULL)
|
||||
lvp(is_virtual_LVP, "lv_is_virtual", NULL)
|
||||
lvp(is_merging_LVP, "lv_is_merging", NULL)
|
||||
lvp(is_merging_origin_LVP, "lv_is_merging_origin", NULL)
|
||||
lvp(is_converting_LVP, "lv_is_converting", NULL)
|
||||
lvp(is_external_origin_LVP, "lv_is_external_origin", NULL)
|
||||
lvp(is_virtual_origin_LVP, "lv_is_virtual_origin", NULL)
|
||||
lvp(is_not_synced_LVP, "lv_is_not_synced", NULL)
|
||||
lvp(is_pending_delete_LVP, "lv_is_pending_delete", NULL)
|
||||
lvp(is_error_when_full_LVP, "lv_is_error_when_full", NULL)
|
||||
lvp(is_pvmove_LVP, "lv_is_pvmove", NULL)
|
||||
lvp(is_removed_LVP, "lv_is_removed", NULL)
|
||||
lvp(is_vg_writable_LVP, "lv_is_vg_writable", NULL)
|
||||
|
||||
/* kinds of sub LV */
|
||||
lvp(is_thinpool_data_LVP, "lv_is_thinpool_data", NULL)
|
||||
lvp(is_thinpool_metadata_LVP, "lv_is_thinpool_metadata", NULL)
|
||||
lvp(is_cachepool_data_LVP, "lv_is_cachepool_data", NULL)
|
||||
lvp(is_cachepool_metadata_LVP, "lv_is_cachepool_metadata", NULL)
|
||||
lvp(is_mirror_image_LVP, "lv_is_mirror_image", NULL)
|
||||
lvp(is_mirror_log_LVP, "lv_is_mirror_log", NULL)
|
||||
lvp(is_raid_image_LVP, "lv_is_raid_image", NULL)
|
||||
lvp(is_raid_metadata_LVP, "lv_is_raid_metadata", NULL)
|
||||
|
||||
/*
|
||||
* is_thick_origin should be used instead of is_origin
|
||||
* is_thick_snapshot is generally used as LV_snapshot from lv_types.h
|
||||
*/
|
||||
lvp(is_origin_LVP, "lv_is_origin", NULL)
|
||||
lvp(is_thick_origin_LVP, "lv_is_thick_origin", NULL)
|
||||
lvp(is_thick_snapshot_LVP, "lv_is_thick_snapshot", NULL)
|
||||
lvp(is_thin_origin_LVP, "lv_is_thin_origin", NULL)
|
||||
lvp(is_thin_snapshot_LVP, "lv_is_thin_snapshot", NULL)
|
||||
|
||||
lvp(is_cache_origin_LVP, "lv_is_cache_origin", NULL)
|
||||
lvp(is_merging_cow_LVP, "lv_is_merging_cow", NULL)
|
||||
lvp(is_cow_covering_origin_LVP, "lv_is_cow_covering_origin", NULL)
|
||||
lvp(is_visible_LVP, "lv_is_visible", NULL)
|
||||
lvp(is_historical_LVP, "lv_is_historical", NULL)
|
||||
lvp(is_raid_with_tracking_LVP, "lv_is_raid_with_tracking", NULL)
|
||||
lvp(LVP_COUNT, "", NULL)
|
||||
|
||||
32
tools/lv_types.h
Normal file
32
tools/lv_types.h
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
|
||||
/*
|
||||
* LV types used in command definitions. The type strings are used
|
||||
* as LV suffixes, e.g. LV_type or LV_type1_type2.
|
||||
*
|
||||
* The final NULL arg can be replaced with lv_is_type() functions
|
||||
* if the current lv_is_type #defines become functions and are
|
||||
* moved to tools.h
|
||||
*
|
||||
* Until then, the lv_is_type() functions are called indirectly
|
||||
* through _lv_is_type().
|
||||
*/
|
||||
|
||||
lvt(LVT_NONE, "", NULL)
|
||||
lvt(linear_LVT, "linear", NULL)
|
||||
lvt(striped_LVT, "striped", NULL)
|
||||
lvt(snapshot_LVT, "snapshot", NULL) /* lv_is_cow, lv_is_thick_snapshot */
|
||||
lvt(thin_LVT, "thin", NULL)
|
||||
lvt(thinpool_LVT, "thinpool", NULL)
|
||||
lvt(cache_LVT, "cache", NULL)
|
||||
lvt(cachepool_LVT, "cachepool", NULL)
|
||||
lvt(mirror_LVT, "mirror", NULL)
|
||||
lvt(raid_LVT, "raid", NULL)
|
||||
lvt(raid0_LVT, "raid0", NULL)
|
||||
lvt(raid1_LVT, "raid1", NULL)
|
||||
lvt(raid4_LVT, "raid4", NULL)
|
||||
lvt(raid5_LVT, "raid5", NULL)
|
||||
lvt(raid6_LVT, "raid6", NULL)
|
||||
lvt(raid10_LVT, "raid10", NULL)
|
||||
lvt(LVT_COUNT, "", NULL)
|
||||
|
||||
283
tools/lvchange.c
283
tools/lvchange.c
@@ -1436,286 +1436,3 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
update ? READ_FOR_UPDATE : 0, NULL,
|
||||
&_lvchange_single);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Check if the status of the LV allows running lvchange.
|
||||
*
|
||||
* FIXME: check for invalid VG/LV properties in a way that is not prone
|
||||
* to missing some. Currently, there are some checks here, some in the
|
||||
* functions above, some in process_each, and some may be missing.
|
||||
*/
|
||||
static int _lvchange_status_is_valid(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
if (!(lv->vg->status & LVM_WRITE)) {
|
||||
log_error("Operation not permitted on LV %s: writable VG required.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_pvmove(lv)) {
|
||||
log_error("Operation not permitted on LV %s: used for pvmove.",
|
||||
display_lvname(lv));
|
||||
if (arg_is_set(cmd, activate_ARG))
|
||||
log_error("Use 'pvmove --abort' to abandon a pvmove");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_mirror_log(lv)) {
|
||||
log_error("Operation not permitted on LV %s: is mirror log.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_mirror_image(lv)) {
|
||||
log_error("Operation not permitted on LV %s: is mirror image.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lv_is_origin(lv) && !lv_is_thin_volume(lv)) {
|
||||
log_error("Operation not permitted on LV %s: is under snapshot.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_properties_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
int doit = 0, docmds = 0;
|
||||
|
||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
||||
|
||||
if (!_lvchange_status_is_valid(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
if (arg_is_set(cmd, persistent_ARG) && lv_is_pool(lv)) {
|
||||
log_error("Operation not permitted on LV %s: persistent device numbers are not supported with pools.",
|
||||
display_lvname(lv));
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a persistent lv lock already exists from activation
|
||||
* (with the needed mode or higher), this will be a no-op.
|
||||
* Otherwise, the lv lock will be taken as non-persistent
|
||||
* and released when this command exits.
|
||||
*/
|
||||
if (!lockd_lv(cmd, lv, "ex", 0)) {
|
||||
stack;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
for (i = 0; i < cmd->command->ro_count; i++) {
|
||||
opt_enum = cmd->command->required_opt_args[i].opt;
|
||||
|
||||
if (!arg_is_set(cmd, opt_enum))
|
||||
continue;
|
||||
|
||||
if (!archive(lv->vg))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
docmds++;
|
||||
|
||||
switch (opt_enum) {
|
||||
case permission_ARG:
|
||||
doit += _lvchange_permission(cmd, lv);
|
||||
break;
|
||||
|
||||
case alloc_ARG:
|
||||
case contiguous_ARG:
|
||||
doit += _lvchange_alloc(cmd, lv);
|
||||
break;
|
||||
|
||||
case errorwhenfull_ARG:
|
||||
doit += _lvchange_errorwhenfull(cmd, lv);
|
||||
break;
|
||||
|
||||
case readahead_ARG:
|
||||
doit += _lvchange_readahead(cmd, lv);
|
||||
break;
|
||||
|
||||
case persistent_ARG:
|
||||
doit += _lvchange_persistent(cmd, lv);
|
||||
break;
|
||||
|
||||
case discards_ARG:
|
||||
case zero_ARG:
|
||||
doit += _lvchange_pool_update(cmd, lv);
|
||||
break;
|
||||
|
||||
case addtag_ARG:
|
||||
case deltag_ARG:
|
||||
doit += _lvchange_tag(cmd, lv, opt_enum);
|
||||
break;
|
||||
|
||||
case writemostly_ARG:
|
||||
case writebehind_ARG:
|
||||
doit += _lvchange_writemostly(lv);
|
||||
break;
|
||||
|
||||
case minrecoveryrate_ARG:
|
||||
case maxrecoveryrate_ARG:
|
||||
doit += _lvchange_recovery_rate(lv);
|
||||
break;
|
||||
|
||||
case profile_ARG:
|
||||
case metadataprofile_ARG:
|
||||
case detachprofile_ARG:
|
||||
doit += _lvchange_profile(lv);
|
||||
break;
|
||||
|
||||
case setactivationskip_ARG:
|
||||
doit += _lvchange_activation_skip(lv);
|
||||
break;
|
||||
|
||||
case cachemode_ARG:
|
||||
case cachepolicy_ARG:
|
||||
case cachesettings_ARG:
|
||||
doit += _lvchange_cache(cmd, lv);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "Failed to check for option %s",
|
||||
arg_long_option_name(i));
|
||||
}
|
||||
|
||||
if (doit)
|
||||
log_print_unless_silent("Logical volume %s changed.", display_lvname(lv));
|
||||
|
||||
if (doit != docmds)
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_properties_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
||||
int ret;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, READ_FOR_UPDATE, handle, _lvchange_properties_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lvchange_activate_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
struct logical_volume *origin;
|
||||
char snaps_msg[128];
|
||||
|
||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
||||
|
||||
if (!_lvchange_status_is_valid(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
/* FIXME: untangle the proper logic for cow / sparse / virtual origin */
|
||||
|
||||
/* If LV is sparse, activate origin instead */
|
||||
if (lv_is_cow(lv) && lv_is_virtual_origin(origin = origin_from_cow(lv)))
|
||||
lv = origin;
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
origin = origin_from_cow(lv);
|
||||
if (origin->origin_count < 2)
|
||||
snaps_msg[0] = '\0';
|
||||
else if (dm_snprintf(snaps_msg, sizeof(snaps_msg),
|
||||
" and %u other snapshot(s)",
|
||||
origin->origin_count - 1) < 0) {
|
||||
log_error("Failed to prepare message.");
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!arg_is_set(cmd, yes_ARG) &&
|
||||
(yes_no_prompt("Change of snapshot %s will also change its "
|
||||
"origin %s%s. Proceed? [y/n]: ",
|
||||
display_lvname(lv), display_lvname(origin),
|
||||
snaps_msg) == 'n')) {
|
||||
log_error("Logical volume %s not changed.", display_lvname(lv));
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If --sysinit -aay is used and at the same time lvmetad is used,
|
||||
* we want to rely on autoactivation to take place. Also, we
|
||||
* need to take special care here as lvmetad service does
|
||||
* not neet to be running at this moment yet - it could be
|
||||
* just too early during system initialization time.
|
||||
*/
|
||||
if (arg_is_set(cmd, sysinit_ARG) && (arg_uint_value(cmd, activate_ARG, 0) == CHANGE_AAY)) {
|
||||
if (lvmetad_used()) {
|
||||
log_warn("WARNING: lvmetad is active, skipping direct activation during sysinit.");
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_lvchange_activate(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_activate_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
cmd->lockd_vg_default_sh = 1;
|
||||
|
||||
/*
|
||||
* Include foreign VGs that contain active LVs.
|
||||
* That shouldn't happen in general, but if it does by some
|
||||
* mistake, then we want to allow those LVs to be deactivated.
|
||||
*/
|
||||
cmd->include_active_foreign_vgs = 1;
|
||||
|
||||
/* Allow deactivating if locks fail. */
|
||||
if (is_change_activating((activation_change_t)arg_uint_value(cmd, activate_ARG, CHANGE_AY)))
|
||||
cmd->lockd_vg_enforce_sh = 1;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_activate_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _lvchange_refresh_single(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct processing_handle *handle)
|
||||
{
|
||||
/* FIXME: sort out hidden/internal LVs, e.g. _lvchange_hidden_is_valid() */
|
||||
|
||||
if (!_lvchange_status_is_valid(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
log_verbose("Refreshing logical volume %s (if active).", display_lvname(lv));
|
||||
|
||||
if (!_lv_refresh(cmd, lv))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
int lvchange_refresh_cmd(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct processing_handle *handle = init_processing_handle(cmd, NULL);
|
||||
int ret;
|
||||
|
||||
cmd->handles_missing_pvs = 1;
|
||||
cmd->lockd_vg_default_sh = 1;
|
||||
|
||||
ret = process_each_lv(cmd, argc, argv, NULL, NULL, 0, handle, _lvchange_refresh_single);
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -79,6 +79,25 @@ struct command_name command_names[MAX_COMMAND_NAMES] = {
|
||||
#undef xx
|
||||
};
|
||||
|
||||
/*
|
||||
* Table of LV properties
|
||||
*/
|
||||
static struct lv_props _lv_props[LVP_COUNT + 1] = {
|
||||
#define lvp(a, b, c) {a, b, c},
|
||||
#include "lv_props.h"
|
||||
#undef lvp
|
||||
};
|
||||
|
||||
/*
|
||||
* Table of LV types
|
||||
*/
|
||||
static struct lv_types _lv_types[LVT_COUNT + 1] = {
|
||||
#define lvt(a, b, c) {a, b, c},
|
||||
#include "lv_types.h"
|
||||
#undef lvt
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Table of valid command lines
|
||||
*/
|
||||
@@ -96,9 +115,34 @@ struct command_function command_functions[COMMAND_ID_COUNT] = {
|
||||
{ lvmconfig_general_CMD, lvmconfig },
|
||||
};
|
||||
#if 0
|
||||
{ lvchange_properties_CMD, lvchange_properties_cmd },
|
||||
{ lvchange_activate_CMD, lvchange_activate_cmd },
|
||||
{ lvchange_refresh_CMD, lvchange_refresh_cmd },
|
||||
/* all raid-related type conversions */
|
||||
|
||||
{ lvconvert_raid_types_CMD, lvconvert_raid_types_fn },
|
||||
|
||||
/* raid-related utilities (move into lvconvert_raid_types?) */
|
||||
|
||||
{ lvconvert_split_mirror_images_CMD, lvconvert_split_mirror_images_fn },
|
||||
{ lvconvert_change_mirrorlog_CMD, lvconvert_change_mirrorlog_fn },
|
||||
|
||||
/* utilities for creating/maintaining thin and cache objects. */
|
||||
|
||||
{ lvconvert_to_thin_with_external_CMD, lvconvert_to_thin_with_external_fn },
|
||||
{ lvconvert_to_cache_vol_CMD, lvconvert_to_cache_vol_fn },
|
||||
{ lvconvert_to_thinpool_CMD, lvconvert_to_thinpool_fn },
|
||||
{ lvconvert_to_cachepool_CMD, lvconvert_to_cachepool_fn },
|
||||
{ lvconvert_split_and_keep_cachepool_CMD, lvconvert_split_and_keep_cachepool_fn },
|
||||
{ lvconvert_split_and_delete_cachepool_CMD, lvconvert_split_and_delete_cachepool_fn },
|
||||
{ lvconvert_swap_pool_metadata_CMD, lvconvert_swap_pool_metadata_fn },
|
||||
|
||||
/* utilities related to snapshots and repair. */
|
||||
|
||||
{ lvconvert_merge_CMD, lvconvert_merge_fn },
|
||||
{ lvconvert_combine_split_snapshot_CMD, lvconvert_combine_split_snapshot_fn },
|
||||
{ lvconvert_repair_pvs_or_thinpool_CMD, lvconvert_repair_pvs_or_thinpool_fn },
|
||||
{ lvconvert_replace_pv_CMD, lvconvert_replace_pv_fn },
|
||||
{ lvconvert_split_cow_snapshot_CMD, lvconvert_split_cow_snapshot_fn },
|
||||
{ lvconvert_poll_start_CMD, lvconvert_poll_start_fn },
|
||||
|
||||
#endif
|
||||
|
||||
/* Command line args */
|
||||
@@ -772,6 +816,66 @@ int metadatacopies_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int polloperation_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "pvmove") ||
|
||||
!strcmp(av->value, "convert") ||
|
||||
!strcmp(av->value, "merge") ||
|
||||
!strcmp(av->value, "merge_thin"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int writemostly_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
/* Could we verify that a PV arg looks like /dev/foo ? */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int syncaction_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "check") ||
|
||||
!strcmp(av->value, "repair"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reportformat_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "basic") ||
|
||||
!strcmp(av->value, "json"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int configreport_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "log") ||
|
||||
!strcmp(av->value, "vg") ||
|
||||
!strcmp(av->value, "lv") ||
|
||||
!strcmp(av->value, "pv") ||
|
||||
!strcmp(av->value, "pvseg") ||
|
||||
!strcmp(av->value, "seg"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int configtype_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!strcmp(av->value, "current") ||
|
||||
!strcmp(av->value, "default") ||
|
||||
!strcmp(av->value, "diff") ||
|
||||
!strcmp(av->value, "full") ||
|
||||
!strcmp(av->value, "list") ||
|
||||
!strcmp(av->value, "missing") ||
|
||||
!strcmp(av->value, "new") ||
|
||||
!strcmp(av->value, "profilable") ||
|
||||
!strcmp(av->value, "profilable-command") ||
|
||||
!strcmp(av->value, "profilable-metadata"))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: there's been a confusing mixup among:
|
||||
* resizeable, resizable, allocatable, allocation.
|
||||
@@ -994,6 +1098,20 @@ void lvm_register_commands(void)
|
||||
_set_valid_args_for_command_name(i);
|
||||
}
|
||||
|
||||
struct lv_props *get_lv_prop(int lvp_enum)
|
||||
{
|
||||
if (!lvp_enum)
|
||||
return NULL;
|
||||
return &_lv_props[lvp_enum];
|
||||
}
|
||||
|
||||
struct lv_types *get_lv_type(int lvt_enum)
|
||||
{
|
||||
if (!lvt_enum)
|
||||
return NULL;
|
||||
return &_lv_types[lvt_enum];
|
||||
}
|
||||
|
||||
/*
|
||||
* Also see merge_synonym(). The command definitions
|
||||
* are written using just one variation of the option
|
||||
@@ -1319,7 +1437,7 @@ static void _print_description(int ci)
|
||||
* set to match.
|
||||
*
|
||||
* required_pos_args[0].types & select_VAL means
|
||||
* cmd->argv[] in that pos can be NULL if arg_is_set(select_ARG)
|
||||
* argv[] in that pos can be NULL if arg_is_set(select_ARG)
|
||||
*/
|
||||
|
||||
/* The max number of unused options we keep track of to warn about */
|
||||
@@ -1328,6 +1446,7 @@ static void _print_description(int ci)
|
||||
static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv)
|
||||
{
|
||||
const char *name;
|
||||
char buf[64];
|
||||
int match_required, match_ro, match_rp, match_type, match_unused, mismatch_required;
|
||||
int best_i = 0, best_required = 0, best_type = 0, best_unused = 0;
|
||||
int close_i = 0, close_ro = 0, close_type;
|
||||
@@ -1335,6 +1454,7 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
||||
int temp_unused_count;
|
||||
int best_unused_options[MAX_UNUSED_COUNT] = { 0 };
|
||||
int best_unused_count = 0;
|
||||
int opts_match_count, opts_unmatch_count;
|
||||
int ro, rp;
|
||||
int i, j;
|
||||
int opt_enum, opt_i;
|
||||
@@ -1559,7 +1679,55 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
/*
|
||||
* Check any rules related to option combinations.
|
||||
* Other rules are checked after VG is read.
|
||||
*/
|
||||
|
||||
for (i = 0; i < commands[best_i].rule_count; i++) {
|
||||
struct cmd_rule *rule;
|
||||
rule = &commands[best_i].rules[i];
|
||||
|
||||
/*
|
||||
* The rule wants to validate options (check_opts). That can be
|
||||
* done here if the only qualification for the validation is
|
||||
* other options (and not specific LV type or LV property which
|
||||
* are not known here.)
|
||||
*/
|
||||
|
||||
if (rule->check_opts_count && !rule->lvt_bits && !rule->lvp_bits) {
|
||||
/*
|
||||
* When no opt is specified for applying the rule, then
|
||||
* the rule is always applied, otherwise the rule is
|
||||
* applied when the specific option is set.
|
||||
*/
|
||||
if (rule->opts_count &&
|
||||
!opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
|
||||
continue;
|
||||
|
||||
opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
|
||||
&opts_match_count, &opts_unmatch_count);
|
||||
|
||||
if (opts_match_count && (rule->rule == RULE_INVALID)) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||
log_error("Invalid options for command (%s %d): %s",
|
||||
commands[best_i].command_line_id, best_i, buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (opts_unmatch_count && (rule->rule == RULE_REQUIRE)) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||
log_error("Required options for command (%s %d): %s",
|
||||
commands[best_i].command_line_id, best_i, buf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log_debug("command line id: %s %d", commands[best_i].command_line_id, best_i);
|
||||
|
||||
return &commands[best_i];
|
||||
@@ -1618,7 +1786,7 @@ static int _usage(const char *name, int help_count)
|
||||
log_print(" be omitted if the --select option is used.");
|
||||
log_print(". --size Number can be replaced with --extents NumberExtents.");
|
||||
log_print(". When --name is omitted from lvcreate, a new LV name is");
|
||||
log_print(" generated with the \"lvol\" prefix and a unique numeral suffix.");
|
||||
log_print(" generated with the \"lvol\" prefix and a unique numeric suffix.");
|
||||
log_print(". The required VG parameter in lvcreate may be omitted when");
|
||||
log_print(" the VG name is included in another option, e.g. --name VG/LV.");
|
||||
log_print(". For required options listed in parentheses, e.g. (--A, --B),");
|
||||
@@ -2457,6 +2625,12 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
if (!(cmd->command = _find_command(cmd, cmd->name, &argc, argv)))
|
||||
return EINVALID_CMD_LINE;
|
||||
|
||||
/*
|
||||
* Remaining position args after command name and --options are removed.
|
||||
*/
|
||||
cmd->position_argc = argc;
|
||||
cmd->position_argv = argv;
|
||||
|
||||
set_cmd_name(cmd->name);
|
||||
|
||||
if (arg_is_set(cmd, backgroundfork_ARG)) {
|
||||
|
||||
625
tools/toollib.c
625
tools/toollib.c
@@ -2326,6 +2326,541 @@ static struct lv_segment _historical_lv_segment = {
|
||||
.origin_list = DM_LIST_HEAD_INIT(_historical_lv_segment.origin_list),
|
||||
};
|
||||
|
||||
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
|
||||
int *match_count, int *unmatch_count)
|
||||
{
|
||||
int match = 0;
|
||||
int unmatch = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (arg_is_set(cmd, opts[i]))
|
||||
match++;
|
||||
else
|
||||
unmatch++;
|
||||
}
|
||||
|
||||
if (match_count)
|
||||
*match_count = match;
|
||||
if (unmatch_count)
|
||||
*unmatch_count = unmatch;
|
||||
|
||||
return match ? 1 : 0;
|
||||
}
|
||||
|
||||
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
|
||||
char *buf, int len)
|
||||
{
|
||||
int pos = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = snprintf(buf + pos, len - pos, "%s ", arg_long_option_name(opts[i]));
|
||||
if (ret >= len - pos)
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
buf[len - 1] = '\0';
|
||||
}
|
||||
|
||||
static void lvp_bits_to_str(uint64_t bits, char *buf, int len)
|
||||
{
|
||||
struct lv_props *prop;
|
||||
int lvp_enum;
|
||||
int pos = 0;
|
||||
int ret;
|
||||
|
||||
for (lvp_enum = 0; lvp_enum < LVP_COUNT; lvp_enum++) {
|
||||
if (!(prop = get_lv_prop(lvp_enum)))
|
||||
continue;
|
||||
|
||||
if (lvp_bit_is_set(bits, lvp_enum)) {
|
||||
ret = snprintf(buf + pos, len - pos, "%s ", prop->name);
|
||||
if (ret >= len - pos)
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
}
|
||||
|
||||
static void lvt_bits_to_str(uint64_t bits, char *buf, int len)
|
||||
{
|
||||
struct lv_types *type;
|
||||
int lvt_enum;
|
||||
int pos = 0;
|
||||
int ret;
|
||||
|
||||
for (lvt_enum = 0; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||
if (!(type = get_lv_type(lvt_enum)))
|
||||
continue;
|
||||
|
||||
if (lvt_bit_is_set(bits, lvt_enum)) {
|
||||
ret = snprintf(buf + pos, len - pos, "%s ", type->name);
|
||||
if (ret >= len - pos)
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the lv_prop function pointer used for lv_is_foo() #defines.
|
||||
* Alternatively, lv_is_foo() could all be turned into functions.
|
||||
*/
|
||||
|
||||
static int _lv_is_prop(struct cmd_context *cmd, struct logical_volume *lv, int lvp_enum)
|
||||
{
|
||||
switch (lvp_enum) {
|
||||
case is_locked_LVP:
|
||||
return lv_is_locked(lv);
|
||||
case is_partial_LVP:
|
||||
return lv_is_partial(lv);
|
||||
case is_virtual_LVP:
|
||||
return lv_is_virtual(lv);
|
||||
case is_merging_LVP:
|
||||
return lv_is_merging(lv);
|
||||
case is_merging_origin_LVP:
|
||||
return lv_is_merging_origin(lv);
|
||||
case is_converting_LVP:
|
||||
return lv_is_converting(lv);
|
||||
case is_external_origin_LVP:
|
||||
return lv_is_external_origin(lv);
|
||||
case is_virtual_origin_LVP:
|
||||
return lv_is_virtual_origin(lv);
|
||||
case is_not_synced_LVP:
|
||||
return lv_is_not_synced(lv);
|
||||
case is_pending_delete_LVP:
|
||||
return lv_is_pending_delete(lv);
|
||||
case is_error_when_full_LVP:
|
||||
return lv_is_error_when_full(lv);
|
||||
case is_pvmove_LVP:
|
||||
return lv_is_pvmove(lv);
|
||||
case is_removed_LVP:
|
||||
return lv_is_removed(lv);
|
||||
case is_vg_writable_LVP:
|
||||
return (lv->vg->status & LVM_WRITE) ? 1 : 0;
|
||||
case is_thinpool_data_LVP:
|
||||
return lv_is_thin_pool_data(lv);
|
||||
case is_thinpool_metadata_LVP:
|
||||
return lv_is_thin_pool_metadata(lv);
|
||||
case is_cachepool_data_LVP:
|
||||
return lv_is_cache_pool_data(lv);
|
||||
case is_cachepool_metadata_LVP:
|
||||
return lv_is_cache_pool_metadata(lv);
|
||||
case is_mirror_image_LVP:
|
||||
return lv_is_mirror_image(lv);
|
||||
case is_mirror_log_LVP:
|
||||
return lv_is_mirror_log(lv);
|
||||
case is_raid_image_LVP:
|
||||
return lv_is_raid_image(lv);
|
||||
case is_raid_metadata_LVP:
|
||||
return lv_is_raid_metadata(lv);
|
||||
case is_origin_LVP: /* use lv_is_thick_origin */
|
||||
return lv_is_origin(lv);
|
||||
case is_thick_origin_LVP:
|
||||
return lv_is_thick_origin(lv);
|
||||
case is_thick_snapshot_LVP:
|
||||
return lv_is_thick_snapshot(lv);
|
||||
case is_thin_origin_LVP:
|
||||
return lv_is_thin_origin(lv, NULL);
|
||||
case is_thin_snapshot_LVP:
|
||||
return lv_is_thin_snapshot(lv);
|
||||
case is_cache_origin_LVP:
|
||||
return lv_is_cache_origin(lv);
|
||||
case is_merging_cow_LVP:
|
||||
return lv_is_merging_cow(lv);
|
||||
case is_cow_covering_origin_LVP:
|
||||
return lv_is_cow_covering_origin(lv);
|
||||
case is_visible_LVP:
|
||||
return lv_is_visible(lv);
|
||||
case is_historical_LVP:
|
||||
return lv_is_historical(lv);
|
||||
case is_raid_with_tracking_LVP:
|
||||
return lv_is_raid_with_tracking(lv);
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "unknown lv property value lvp_enum %d", lvp_enum);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if an LV matches a given LV type enum.
|
||||
*/
|
||||
|
||||
static int _lv_is_type(struct cmd_context *cmd, struct logical_volume *lv, int lvt_enum)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
switch (lvt_enum) {
|
||||
case striped_LVT:
|
||||
return seg_is_striped(seg);
|
||||
case linear_LVT:
|
||||
return seg_is_linear(seg);
|
||||
case snapshot_LVT:
|
||||
return lv_is_cow(lv);
|
||||
case thin_LVT:
|
||||
return lv_is_thin_volume(lv);
|
||||
case thinpool_LVT:
|
||||
return lv_is_thin_pool(lv);
|
||||
case cache_LVT:
|
||||
return lv_is_cache(lv);
|
||||
case cachepool_LVT:
|
||||
return lv_is_cache_pool(lv);
|
||||
case mirror_LVT:
|
||||
return lv_is_mirror(lv);
|
||||
case raid_LVT:
|
||||
return lv_is_raid(lv);
|
||||
case raid0_LVT:
|
||||
return seg_is_raid0(seg);
|
||||
case raid1_LVT:
|
||||
return seg_is_raid1(seg);
|
||||
case raid4_LVT:
|
||||
return seg_is_raid4(seg);
|
||||
#if 0
|
||||
case raid5_LVT:
|
||||
return seg_is_raid5(seg);
|
||||
case raid6_LVT:
|
||||
return seg_is_raid6(seg);
|
||||
#endif
|
||||
case raid10_LVT:
|
||||
return seg_is_raid10(seg);
|
||||
default:
|
||||
log_error(INTERNAL_ERROR "unknown lv type value lvt_enum %d", lvt_enum);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_lvt_enum(struct logical_volume *lv)
|
||||
{
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
if (seg_is_striped(seg))
|
||||
return striped_LVT;
|
||||
if (seg_is_linear(seg))
|
||||
return linear_LVT;
|
||||
if (lv_is_cow(lv))
|
||||
return snapshot_LVT;
|
||||
if (lv_is_thin_volume(lv))
|
||||
return thin_LVT;
|
||||
if (lv_is_thin_pool(lv))
|
||||
return thinpool_LVT;
|
||||
if (lv_is_cache(lv))
|
||||
return cache_LVT;
|
||||
if (lv_is_cache_pool(lv))
|
||||
return cachepool_LVT;
|
||||
if (lv_is_mirror(lv))
|
||||
return mirror_LVT;
|
||||
if (lv_is_raid(lv))
|
||||
return raid_LVT;
|
||||
if (seg_is_raid0(seg))
|
||||
return raid0_LVT;
|
||||
if (seg_is_raid1(seg))
|
||||
return raid1_LVT;
|
||||
if (seg_is_raid4(seg))
|
||||
return raid4_LVT;
|
||||
#if 0
|
||||
if (seg_is_raid5(seg))
|
||||
return raid5_LVT;
|
||||
if (seg_is_raid6(seg))
|
||||
return raid6_LVT;
|
||||
#endif
|
||||
if (seg_is_raid10(seg))
|
||||
return raid10_LVT;
|
||||
|
||||
log_error(INTERNAL_ERROR "unknown lv type for %s", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call lv_is_<type> for each <type>_LVT bit set in lvt_bits.
|
||||
* If lv matches one of the specified lv types, then return 1.
|
||||
*/
|
||||
|
||||
static int _lv_types_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvt_bits,
|
||||
uint64_t *match_bits, uint64_t *unmatch_bits)
|
||||
{
|
||||
struct lv_types *type;
|
||||
int lvt_enum;
|
||||
int found_a_match = 0;
|
||||
int match;
|
||||
|
||||
if (match_bits)
|
||||
*match_bits = 0;
|
||||
if (unmatch_bits)
|
||||
*unmatch_bits = 0;
|
||||
|
||||
for (lvt_enum = 1; lvt_enum < LVT_COUNT; lvt_enum++) {
|
||||
if (!lvt_bit_is_set(lvt_bits, lvt_enum))
|
||||
continue;
|
||||
|
||||
if (!(type = get_lv_type(lvt_enum)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* All types are currently handled by _lv_is_type()
|
||||
* because lv_is_type() are #defines and not exposed
|
||||
* in tools.h
|
||||
*/
|
||||
|
||||
if (!type->fn)
|
||||
match = _lv_is_type(cmd, lv, lvt_enum);
|
||||
else
|
||||
match = type->fn(cmd, lv);
|
||||
|
||||
if (match)
|
||||
found_a_match = 1;
|
||||
|
||||
if (match_bits && match)
|
||||
*match_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
|
||||
if (unmatch_bits && !match)
|
||||
*unmatch_bits |= lvt_enum_to_bit(lvt_enum);
|
||||
}
|
||||
|
||||
return found_a_match;
|
||||
}
|
||||
|
||||
/*
|
||||
* Call lv_is_<prop> for each <prop>_LVP bit set in lvp_bits.
|
||||
* If lv matches all of the specified lv properties, then return 1.
|
||||
*/
|
||||
|
||||
static int _lv_props_match(struct cmd_context *cmd, struct logical_volume *lv, uint64_t lvp_bits,
|
||||
uint64_t *match_bits, uint64_t *unmatch_bits)
|
||||
{
|
||||
struct lv_props *prop;
|
||||
int lvp_enum;
|
||||
int found_a_mismatch = 0;
|
||||
int match;
|
||||
|
||||
if (match_bits)
|
||||
*match_bits = 0;
|
||||
if (unmatch_bits)
|
||||
*unmatch_bits = 0;
|
||||
|
||||
for (lvp_enum = 1; lvp_enum < LVP_COUNT; lvp_enum++) {
|
||||
if (!lvp_bit_is_set(lvp_bits, lvp_enum))
|
||||
continue;
|
||||
|
||||
if (!(prop = get_lv_prop(lvp_enum)))
|
||||
continue;
|
||||
|
||||
if (!prop->fn)
|
||||
match = _lv_is_prop(cmd, lv, lvp_enum);
|
||||
else
|
||||
match = prop->fn(cmd, lv);
|
||||
|
||||
if (!match)
|
||||
found_a_mismatch = 1;
|
||||
|
||||
if (match_bits && match)
|
||||
*match_bits |= lvp_enum_to_bit(lvp_enum);
|
||||
|
||||
if (unmatch_bits && !match)
|
||||
*unmatch_bits |= lvp_enum_to_bit(lvp_enum);
|
||||
}
|
||||
|
||||
return !found_a_mismatch;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the command definition specifies one required positional
|
||||
* LV (possibly repeatable), and specifies accepted LV types,
|
||||
* then verify that the LV being processed matches one of those
|
||||
* types.
|
||||
*
|
||||
* process_each_lv() can only be used for commands that have
|
||||
* one positional LV arg (optionally repeating, where each is
|
||||
* processed independently.) It cannot work for commands that
|
||||
* have different required LVs in designated positions, like
|
||||
* 'lvrename LV1 LV2', where each LV is not processed
|
||||
* independently. That means that this LV type check only
|
||||
* needs to check the lv_type of the first positional arg.
|
||||
*/
|
||||
|
||||
static int _check_lv_types(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if ((cmd->command->rp_count == 1) &&
|
||||
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
|
||||
cmd->command->required_pos_args[0].def.lvt_bits) {
|
||||
ret = _lv_types_match(cmd, lv, cmd->command->required_pos_args[0].def.lvt_bits, NULL, NULL);
|
||||
if (!ret) {
|
||||
int lvt_enum = _get_lvt_enum(lv);
|
||||
struct lv_types *type = get_lv_type(lvt_enum);
|
||||
log_warn("Operation on LV %s which has invalid type %s.",
|
||||
display_lvname(lv), type ? type->name : "unknown");
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if LV passes each rule specified in command definition. */
|
||||
|
||||
static int _check_lv_rules(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
{
|
||||
char buf[64];
|
||||
struct cmd_rule *rule;
|
||||
struct lv_types *lvtype = NULL;
|
||||
uint64_t lv_props_match_bits, lv_props_unmatch_bits;
|
||||
uint64_t lv_types_match_bits, lv_types_unmatch_bits;
|
||||
int opts_match_count, opts_unmatch_count;
|
||||
int lvt_enum;
|
||||
int ret = 1;
|
||||
int i;
|
||||
|
||||
lvt_enum = _get_lvt_enum(lv);
|
||||
if (lvt_enum)
|
||||
lvtype = get_lv_type(lvt_enum);
|
||||
|
||||
for (i = 0; i < cmd->command->rule_count; i++) {
|
||||
rule = &cmd->command->rules[i];
|
||||
|
||||
/*
|
||||
* RULE: <conditions> INVALID|REQUIRE <checks>
|
||||
*
|
||||
* If all the conditions apply to the command+LV, then
|
||||
* the checks are performed. If all conditions are zero
|
||||
* (!opts_count, !lvt_bits, !lvp_bits), then the check
|
||||
* is always performed.
|
||||
*
|
||||
* Conditions:
|
||||
*
|
||||
* 1. options (opts): if any of the specified options are set,
|
||||
* then the checks may apply.
|
||||
*
|
||||
* 2. LV types (lvt_bits): if any of the specified LV types
|
||||
* match the LV, then the checks may apply.
|
||||
*
|
||||
* 3. LV properties (lvp_bits): if all of the specified
|
||||
* LV properties match the LV, then the checks may apply.
|
||||
*
|
||||
* If conditions 1, 2, 3 all pass, then the checks apply.
|
||||
*
|
||||
* Checks:
|
||||
*
|
||||
* 1. options (check_opts):
|
||||
* INVALID: if any of the specified options are set,
|
||||
* then the command fails.
|
||||
* REQUIRE: if any of the specified options are not set,
|
||||
* then the command fails.
|
||||
*
|
||||
* 2. LV types (check_lvt_bits):
|
||||
* INVALID: if any of the specified LV types match the LV,
|
||||
* then the command fails.
|
||||
* REQUIRE: if none of the specified LV types match the LV,
|
||||
* then the command fails.
|
||||
*
|
||||
* 3. LV properties (check_lvp_bits):
|
||||
* INVALID: if any of the specified LV properties match
|
||||
* the LV, then the command fails.
|
||||
* REQUIRE: if any of the specified LV properties do not match
|
||||
* the LV, then the command fails.
|
||||
*/
|
||||
|
||||
if (rule->opts_count && !opt_in_list_is_set(cmd, rule->opts, rule->opts_count, NULL, NULL))
|
||||
continue;
|
||||
|
||||
/* If LV matches one type in lvt_bits, this returns 1. */
|
||||
if (rule->lvt_bits && !_lv_types_match(cmd, lv, rule->lvt_bits, NULL, NULL))
|
||||
continue;
|
||||
|
||||
/* If LV matches all properties in lvp_bits, this returns 1. */
|
||||
if (rule->lvp_bits && !_lv_props_match(cmd, lv, rule->lvp_bits, NULL, NULL))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Check the options, LV types, LV properties.
|
||||
*/
|
||||
|
||||
if (rule->check_opts)
|
||||
opt_in_list_is_set(cmd, rule->check_opts, rule->check_opts_count,
|
||||
&opts_match_count, &opts_unmatch_count);
|
||||
|
||||
if (rule->check_lvt_bits)
|
||||
_lv_types_match(cmd, lv, rule->check_lvt_bits,
|
||||
&lv_types_match_bits, &lv_types_unmatch_bits);
|
||||
|
||||
if (rule->check_lvp_bits)
|
||||
_lv_props_match(cmd, lv, rule->check_lvp_bits,
|
||||
&lv_props_match_bits, &lv_props_unmatch_bits);
|
||||
|
||||
/*
|
||||
* Evaluate if the check results pass based on the rule.
|
||||
* The options are checked again here because the previous
|
||||
* option validation (during command matching) does not cover
|
||||
* cases where the option is combined with conditions of LV types
|
||||
* or properties.
|
||||
*/
|
||||
|
||||
/* Fail if any invalid options are set. */
|
||||
|
||||
if (rule->check_opts && (rule->rule == RULE_INVALID) && opts_match_count) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||
log_warn("An invalid option is set: %s", buf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if any required options are not set. */
|
||||
|
||||
if (rule->check_opts && (rule->rule == RULE_REQUIRE) && opts_unmatch_count) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
opt_array_to_str(cmd, rule->check_opts, rule->check_opts_count, buf, sizeof(buf));
|
||||
log_warn("A required option is not set: %s", buf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV matches any of the invalid LV types. */
|
||||
|
||||
if (rule->check_lvt_bits && (rule->rule == RULE_INVALID) && lv_types_match_bits) {
|
||||
log_warn("Command on LV %s with invalid type: %s",
|
||||
display_lvname(lv), lvtype ? lvtype->name : "unknown");
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV does not match any of the required LV types. */
|
||||
|
||||
if (rule->check_lvt_bits && (rule->rule == RULE_REQUIRE) && !lv_types_match_bits) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
lvt_bits_to_str(rule->check_lvt_bits, buf, sizeof(buf));
|
||||
log_warn("Command on LV %s with type %s does not match required type: %s",
|
||||
display_lvname(lv), lvtype ? lvtype->name : "unknown", buf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV matches any of the invalid LV properties. */
|
||||
|
||||
if (rule->check_lvp_bits && (rule->rule == RULE_INVALID) && lv_props_match_bits) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
lvp_bits_to_str(lv_props_match_bits, buf, sizeof(buf));
|
||||
log_warn("Command on LV %s with invalid properties: %s",
|
||||
display_lvname(lv), buf);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/* Fail if the LV does not match any of the required LV properties. */
|
||||
|
||||
if (rule->check_lvp_bits && (rule->rule == RULE_REQUIRE) && lv_props_unmatch_bits) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
lvp_bits_to_str(lv_props_unmatch_bits, buf, sizeof(buf));
|
||||
log_warn("Command on LV %s requires properties: %s",
|
||||
display_lvname(lv), buf);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct dm_list *arg_lvnames, const struct dm_list *tags_in,
|
||||
int stop_on_error,
|
||||
@@ -2350,9 +2885,6 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct dm_list found_arg_lvnames;
|
||||
struct glv_list *glvl, *tglvl;
|
||||
int do_report_ret_code = 1;
|
||||
uint32_t lv_types;
|
||||
struct logical_volume *lv;
|
||||
struct lv_segment *seg;
|
||||
|
||||
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_LV);
|
||||
|
||||
@@ -2504,65 +3036,42 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If the command definition specifies one required positional
|
||||
* LV (possibly repeatable), and specifies accepted LV types,
|
||||
* then verify that the LV being processed matches one of those
|
||||
* types.
|
||||
*
|
||||
* process_each_lv() can only be used for commands that have
|
||||
* one positional LV arg (optionally repeating, where each is
|
||||
* processed independently.) It cannot work for commands that
|
||||
* have different required LVs in designated positions, like
|
||||
* 'lvrename LV1 LV2', where each LV is not processed
|
||||
* independently. That means that this LV type check only
|
||||
* needs to check the lv_type of the first positional arg.
|
||||
*
|
||||
* There is one command that violates this rule by stealing
|
||||
* the first positional LV arg before calling process_each_lv:
|
||||
* lvconvert --type snapshot LV_linear_striped_raid LV_snapshot
|
||||
* This code cannot validate that case. process_each_lv() sees
|
||||
* a single LV name arg, but it's in pos 2. Could we work around
|
||||
* this by looking at the final positional arg rather than always
|
||||
* looking at pos 1?
|
||||
*
|
||||
* This only validates types for required LV positional args
|
||||
* (currently there are no command specifications that include
|
||||
* specific LV types in optional positional args.)
|
||||
* The command definition may include restrictions on the
|
||||
* types and properties of LVs that can be processed.
|
||||
*/
|
||||
|
||||
if ((cmd->command->rp_count == 1) &&
|
||||
val_bit_is_set(cmd->command->required_pos_args[0].def.val_bits, lv_VAL) &&
|
||||
cmd->command->required_pos_args[0].def.lv_types) {
|
||||
if (!_check_lv_types(cmd, lvl->lv)) {
|
||||
/* FIXME: include this result in report log? */
|
||||
/* FIXME: avoid duplicating message for each level */
|
||||
|
||||
lv_types = cmd->command->required_pos_args[0].def.lv_types;
|
||||
lv = lvl->lv;
|
||||
seg = first_seg(lv);
|
||||
|
||||
if ((lv_is_cow(lv) && !(lv_types & ARG_DEF_LV_SNAPSHOT)) ||
|
||||
(lv_is_thin_volume(lv) && !(lv_types & ARG_DEF_LV_THIN)) ||
|
||||
(lv_is_thin_pool(lv) && !(lv_types & ARG_DEF_LV_THINPOOL)) ||
|
||||
(lv_is_cache(lv) && !(lv_types & ARG_DEF_LV_CACHE)) ||
|
||||
(lv_is_cache_pool(lv) && !(lv_types & ARG_DEF_LV_CACHEPOOL)) ||
|
||||
(lv_is_mirror(lv) && !(lv_types & ARG_DEF_LV_MIRROR)) ||
|
||||
(lv_is_raid(lv) && !(lv_types & (ARG_DEF_LV_RAID | ARG_DEF_LV_RAID0 | ARG_DEF_LV_RAID1 | ARG_DEF_LV_RAID4 | ARG_DEF_LV_RAID5 | ARG_DEF_LV_RAID6 | ARG_DEF_LV_RAID10))) ||
|
||||
(segtype_is_striped(seg->segtype) && !(lv_types & ARG_DEF_LV_STRIPED)) ||
|
||||
(segtype_is_linear(seg->segtype) && !(lv_types & ARG_DEF_LV_LINEAR))) {
|
||||
/*
|
||||
* If a named LV arg cannot be processed it's an error, otherwise
|
||||
* the LV is skipped and doesn't cause the command to fail.
|
||||
*/
|
||||
if (str_list_match_item(&found_arg_lvnames, lv->name)) {
|
||||
log_error("Operation not permitted (%s %d) on LV %s with type %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lv), seg->segtype->name);
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted (%s %d) on LV %s with type %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lv), seg->segtype->name);
|
||||
}
|
||||
continue;
|
||||
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
|
||||
log_error("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_check_lv_rules(cmd, lvl->lv)) {
|
||||
/* FIXME: include this result in report log? */
|
||||
/* FIXME: avoid duplicating message for each level */
|
||||
|
||||
if (str_list_match_item(&found_arg_lvnames, lvl->lv->name)) {
|
||||
log_error("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted (%s %d) on LV %s.",
|
||||
cmd->command->command_line_id, cmd->command->command_line_enum,
|
||||
display_lvname(lvl->lv));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
|
||||
|
||||
@@ -159,6 +159,12 @@ const char *extract_vgname(struct cmd_context *cmd, const char *lv_name);
|
||||
const char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
|
||||
unsigned *dev_dir_found);
|
||||
|
||||
int opt_in_list_is_set(struct cmd_context *cmd, int *opts, int count,
|
||||
int *match_count, int *unmatch_count);
|
||||
|
||||
void opt_array_to_str(struct cmd_context *cmd, int *opts, int count,
|
||||
char *buf, int len);
|
||||
|
||||
int pvcreate_params_from_args(struct cmd_context *cmd, struct pvcreate_params *pp);
|
||||
int pvcreate_each_device(struct cmd_context *cmd, struct processing_handle *handle, struct pvcreate_params *pp);
|
||||
|
||||
|
||||
@@ -50,14 +50,14 @@
|
||||
#define CMD_LEN 256
|
||||
#define MAX_ARGS 64
|
||||
|
||||
/* define the enums for the values accepted by command line --options */
|
||||
/* define the enums for the values accepted by command line --options, foo_VAL */
|
||||
enum {
|
||||
#define val(a, b, c, d) a ,
|
||||
#include "vals.h"
|
||||
#undef val
|
||||
};
|
||||
|
||||
/* define the enums for the command line --options */
|
||||
/* define the enums for the command line --options, foo_ARG */
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
#include "args.h"
|
||||
@@ -69,6 +69,20 @@ enum {
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
|
||||
/* define enums for LV properties, foo_LVP */
|
||||
enum {
|
||||
#define lvp(a, b, c) a ,
|
||||
#include "lv_props.h"
|
||||
#undef lvp
|
||||
};
|
||||
|
||||
/* define enums for LV types, foo_LVT */
|
||||
enum {
|
||||
#define lvt(a, b, c) a ,
|
||||
#include "lv_types.h"
|
||||
#undef lvt
|
||||
};
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
|
||||
@@ -111,6 +125,21 @@ struct val_props {
|
||||
const char *usage;
|
||||
};
|
||||
|
||||
/* a global table of possible LV properties */
|
||||
struct lv_props {
|
||||
int lvp_enum; /* is_foo_LVP from lv_props.h */
|
||||
const char *name; /* "lv_is_foo" used in command-lines.in */
|
||||
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
|
||||
};
|
||||
|
||||
/* a global table of possible LV types */
|
||||
/* (as exposed externally in command line interface, not exactly as internal segtype is used) */
|
||||
struct lv_types {
|
||||
int lvt_enum; /* is_foo_LVT from lv_types.h */
|
||||
const char *name; /* "foo" used in command-lines.in, i.e. LV_foo */
|
||||
int (*fn) (struct cmd_context *cmd, struct logical_volume *lv); /* lv_is_foo() */
|
||||
};
|
||||
|
||||
#define CACHE_VGMETADATA 0x00000001
|
||||
#define PERMITTED_READ_ONLY 0x00000002
|
||||
/* Process all VGs if none specified on the command line. */
|
||||
@@ -162,6 +191,12 @@ int readahead_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int vgmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int pvmetadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int metadatacopies_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int polloperation_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int writemostly_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int syncaction_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int reportformat_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int configreport_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
int configtype_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av);
|
||||
|
||||
/* we use the enums to access the switches */
|
||||
unsigned arg_count(const struct cmd_context *cmd, int a);
|
||||
@@ -203,4 +238,7 @@ int vgchange_activate(struct cmd_context *cmd, struct volume_group *vg,
|
||||
|
||||
int vgchange_background_polling(struct cmd_context *cmd, struct volume_group *vg);
|
||||
|
||||
struct lv_props *get_lv_prop(int lvp_enum);
|
||||
struct lv_types *get_lv_type(int lvt_enum);
|
||||
|
||||
#endif
|
||||
|
||||
35
tools/vals.h
35
tools/vals.h
@@ -57,11 +57,13 @@
|
||||
* words is not defined or stored in a consistent way,
|
||||
* but is just whatever the parsing function happens to look
|
||||
* for, so adding a new accepted value for the val type is
|
||||
* often just making the parsing function recognize a new
|
||||
* word. This new word should then also be added to the
|
||||
* usage string for the val type here. It would be nice
|
||||
* if the accepted values could be defined in a more
|
||||
* consistent way, perhaps in struct val_props.
|
||||
* generally making the parsing function recognize a new
|
||||
* word, and making the implementation code also recognize
|
||||
* that word to do something different. This new word should
|
||||
* then also be added to the usage string for the val type here.
|
||||
* It would be nice if the accepted values could be defined in a
|
||||
* more consistent way, and perhaps in a single place, perhaps in
|
||||
* struct val_props.
|
||||
*
|
||||
* The usage text for an option is not always the full
|
||||
* set of words accepted for an option, but may be a
|
||||
@@ -92,9 +94,9 @@
|
||||
* should avoid suggesting the upper case letters.
|
||||
*/
|
||||
|
||||
val(none_VAL, NULL, "None", "") /* unused, for enum value 0 */
|
||||
val(conststr_VAL, NULL, "ConstString", "") /* used only for command defs */
|
||||
val(constnum_VAL, NULL, "ConstNumber", "") /* used only for command defs */
|
||||
val(none_VAL, NULL, "None", "ERR") /* unused, for enum value 0 */
|
||||
val(conststr_VAL, NULL, "ConstString", "ERR") /* used only for command defs */
|
||||
val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
|
||||
val(bool_VAL, yes_no_arg, "Bool", "y|n")
|
||||
val(number_VAL, int_arg, "Number", NULL)
|
||||
val(string_VAL, string_arg, "String", NULL)
|
||||
@@ -111,7 +113,7 @@ val(mirrorlog_VAL, mirrorlog_arg, "MirrorLog", "core|disk")
|
||||
val(sizekb_VAL, size_kb_arg, "SizeKB", "Number[k|unit]")
|
||||
val(sizemb_VAL, size_mb_arg, "SizeMB", "Number[m|unit]")
|
||||
val(numsigned_VAL, int_arg_with_sign, "SNumber", "[+|-]Number")
|
||||
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%{VG|PVS|FREE}]")
|
||||
val(numsignedper_VAL, int_arg_with_sign_and_percent, "SNumberP", "[+|-]Number[%VG|%PVS|%FREE]")
|
||||
val(permission_VAL, permission_arg, "Permission", "rw|r")
|
||||
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
|
||||
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
|
||||
@@ -122,16 +124,13 @@ val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
|
||||
val(vgmetadatacopies_VAL, vgmetadatacopies_arg, "MetadataCopiesVG", "all|unmanaged|Number")
|
||||
val(pvmetadatacopies_VAL, pvmetadatacopies_arg, "MetadataCopiesPV", "0|1|2")
|
||||
val(metadatacopies_VAL, metadatacopies_arg, "unused", "unused")
|
||||
val(polloperation_VAL, polloperation_arg, "PollOp", "pvmove|convert|merge|merge_thin")
|
||||
val(writemostly_VAL, writemostly_arg, "WriteMostlyPV", "PV[:t|n|y]")
|
||||
val(syncaction_VAL, syncaction_arg, "SyncAction", "check|repair")
|
||||
val(reportformat_VAL, reportformat_arg, "ReportFmt", "basic|json")
|
||||
val(configreport_VAL, configreport_arg, "ConfigReport", "log|vg|lv|pv|pvseg|seg")
|
||||
val(configtype_VAL, configtype_arg, "ConfigType", "current|default|diff|full|list|missing|new|profilable|profilable-command|profilable-metadata")
|
||||
|
||||
/* this should always be last */
|
||||
val(VAL_COUNT, NULL, NULL, NULL)
|
||||
|
||||
/*
|
||||
* FIXME: I suspect many of the following are good candidates for a custom VAL
|
||||
* enum for the benefit of custom parsing, or custom usage, or both:
|
||||
*
|
||||
* configreport_ARG, configtype_ARG, polloperation_ARG, raidrebuild_ARG,
|
||||
* raidsyncaction_ARG, raidwritemostly_ARG, reportformat_ARG, syncaction_ARG,
|
||||
* cachepolicy_ARG, cachesettings_ARG, writemostly_ARG
|
||||
*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user