mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-09 23:33:17 +03:00
Compare commits
88 Commits
v2_02_162
...
dev-dct-cm
Author | SHA1 | Date | |
---|---|---|---|
|
cd8d65b0b8 | ||
|
8c71fc1cc2 | ||
|
0336b41828 | ||
|
c0a0eedf2e | ||
|
73df2aedf9 | ||
|
114db6f745 | ||
|
d83f2d766d | ||
|
8e9d5d12ae | ||
|
c7bd33d951 | ||
|
8297276967 | ||
|
2ff893cd85 | ||
|
9c9b9b276a | ||
|
6d52b17dfc | ||
|
0973d6e331 | ||
|
a185a2bea2 | ||
|
93b61c07eb | ||
|
e30fb19030 | ||
|
2fed8d8515 | ||
|
480c1c9599 | ||
|
37b8b84fee | ||
|
b4f0503d1b | ||
|
6fcfa2855b | ||
|
5ac008116b | ||
|
29f7dc2922 | ||
|
e8985c71bc | ||
|
54bf15555b | ||
|
785e2c31f5 | ||
|
7111d48748 | ||
|
e805ef2d66 | ||
|
f21afddeb7 | ||
|
7d1125e5b7 | ||
|
d86caf952e | ||
|
9c21139284 | ||
|
5649834f7d | ||
|
1fde4bf4d0 | ||
|
ef69934746 | ||
|
06ce9b4e42 | ||
|
bb9789f2b3 | ||
|
48e14390c1 | ||
|
3d3f62e10a | ||
|
e5a5fd3669 | ||
|
dad02900f1 | ||
|
4bcbcdb1a2 | ||
|
175e0905d5 | ||
|
fc93085c7a | ||
|
6f90c954b7 | ||
|
c55134aa48 | ||
|
7d6cf12554 | ||
|
57fa5d4329 | ||
|
76ef2d15d8 | ||
|
de7f1deb80 | ||
|
6f236c3353 | ||
|
ba0c26a078 | ||
|
30884208d4 | ||
|
802bd34562 | ||
|
8f25ad6416 | ||
|
9aefe9aa7a | ||
|
d2c3b23e6d | ||
|
91f866f786 | ||
|
7482ff93b8 | ||
|
b66fa91c46 | ||
|
b1b0b134ec | ||
|
d1a25fe597 | ||
|
4a15abe865 | ||
|
5c3141a8b9 | ||
|
be497175e0 | ||
|
2b01dca28a | ||
|
8b1a368b59 | ||
|
fdc3fcbfce | ||
|
a234cebbed | ||
|
415c5fd5d8 | ||
|
6361bc4734 | ||
|
804a397643 | ||
|
d0d03f315b | ||
|
5765a28456 | ||
|
c490be9134 | ||
|
d0df1ff995 | ||
|
1ce958bc5e | ||
|
48d9c46daa | ||
|
52d2fa7022 | ||
|
d1ff254c3c | ||
|
b3fbcd1ff7 | ||
|
4ffe15bf6a | ||
|
d01b1b6cc1 | ||
|
a8e4790810 | ||
|
800c0d3dd6 | ||
|
237f84e038 | ||
|
6b6e258e0c |
@@ -1 +1 @@
|
||||
1.02.132-git (2016-07-28)
|
||||
1.02.134-git (2016-08-15)
|
||||
|
31
WHATS_NEW
31
WHATS_NEW
@@ -1,3 +1,34 @@
|
||||
Version 2.02.165 -
|
||||
===================================
|
||||
Suppress some unnecessary --stripesize parameter warnings.
|
||||
Fix 'pvmove -n name ...' to prohibit collocation of RAID SubLVs
|
||||
|
||||
Version 2.02.164 - 15th August 2016
|
||||
===================================
|
||||
Fix selection of PVs when allocating raid0_meta.
|
||||
Fix sdbus socket leak leading to hang in lvmnotify.
|
||||
Specify max stripes for raid LV types: raid0:64; 1:10; 4,5:63; 6:62; 10:32.
|
||||
Avoid double suffix when naming _rmeta LV paired with _rimage LV.
|
||||
|
||||
Version 2.02.163 - 10th August 2016
|
||||
===================================
|
||||
Add profile for lvmdbusd which uses lvm shell json report output.
|
||||
Restrict in-command modification of some parms in lvm shell.
|
||||
Apply LVM_COMMAND_PROFILE early for lvm shell.
|
||||
Refactor reporting so lvm shell log report collects whole of cmd execution.
|
||||
Support LVM_*_FD envvars to redirect output to file descriptors.
|
||||
Limit use of --corelog and --mirrorlog to mirrors in lvconvert.
|
||||
Reject --nosync option for RAID6 LVs in lvcreate.
|
||||
Do not refresh whole cmd context if profile dropped after processing LVM cmd.
|
||||
Support straightforward lvconvert between striped and raid4 LVs.
|
||||
Support straightforward lvconvert between raid1 and mirror LVs.
|
||||
Report supported conversions when asked for unsupported raid lvconvert.
|
||||
Add "--rebuild PV" option to lvchange to allow for PV selective rebuilds.
|
||||
Preserve existing mirror region size when using --repair.
|
||||
Forbid stripe parameters with lvconvert --repair.
|
||||
Unify stripe size validation into get_stripe_params to catch missing cases.
|
||||
Further lvconvert validation logic refactoring.
|
||||
|
||||
Version 2.02.162 - 28th July 2016
|
||||
=================================
|
||||
Extend vg_validate also to check raid configurations thoroughly.
|
||||
|
@@ -1,3 +1,11 @@
|
||||
Version 1.02.134 -
|
||||
===================================
|
||||
|
||||
Version 1.02.133 - 10th August 2016
|
||||
===================================
|
||||
Add dm_report_destroy_rows/dm_report_group_output_and_pop_all for lvm shell.
|
||||
Adjust group handling and json production for lvm shell.
|
||||
|
||||
Version 1.02.132 - 28th July 2016
|
||||
=================================
|
||||
Fix json reporting to escape '"' character that may appear in reported string.
|
||||
|
@@ -24,7 +24,8 @@ PROFILES=$(PROFILE_TEMPLATES) \
|
||||
$(srcdir)/cache-mq.profile \
|
||||
$(srcdir)/cache-smq.profile \
|
||||
$(srcdir)/thin-generic.profile \
|
||||
$(srcdir)/thin-performance.profile
|
||||
$(srcdir)/thin-performance.profile \
|
||||
$(srcdir)/lvmdbusd.profile
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
|
50
conf/lvmdbusd.profile
Normal file
50
conf/lvmdbusd.profile
Normal file
@@ -0,0 +1,50 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!
|
||||
#
|
||||
# LVM configuration profile used by lvmdbusd daemon.
|
||||
#
|
||||
# This sets up LVM to produce output in the most suitable format for processing
|
||||
# by lvmdbusd daemon which utilizes LVM shell to execute LVM commands.
|
||||
#
|
||||
# Do not edit this file in any way. This profile is distributed together with
|
||||
# lvmdbusd and it contains configuration that is important for lvmdbusd to
|
||||
# cooperate and interface with LVM correctly.
|
||||
#
|
||||
|
||||
global {
|
||||
# use bytes for expected and deterministic output
|
||||
units=b
|
||||
# no need for suffix if we have units set
|
||||
suffix=0
|
||||
}
|
||||
|
||||
report {
|
||||
compact_output=0
|
||||
compact_output_cols=""
|
||||
binary_values_as_numeric=0
|
||||
# time in number of seconds since the Epoch
|
||||
time_format="%s"
|
||||
mark_hidden_devices=1
|
||||
# lvmdbusd expects JSON output
|
||||
output_format=json
|
||||
# *_cols_full for lvm fullreport's fields which lvmdbusd relies on to update its state
|
||||
vgs_cols_full="vg_name,vg_uuid,vg_fmt,vg_size,vg_free,vg_sysid,vg_extent_size,vg_extent_count,vg_free_count,vg_profile,max_lv,max_pv,pv_count,lv_count,snap_count,vg_seqno,vg_mda_count,vg_mda_free,vg_mda_size,vg_mda_used_count,vg_attr,vg_tags"
|
||||
pvs_cols_full="pv_name,pv_uuid,pv_fmt,pv_size,pv_free,pv_used,dev_size,pv_mda_size,pv_mda_free,pv_ba_start,pv_ba_size,pe_start,pv_pe_count,pv_pe_alloc_count,pv_attr,pv_tags,vg_name,vg_uuid"
|
||||
lvs_cols_full="lv_uuid,lv_name,lv_path,lv_size,vg_name,pool_lv_uuid,pool_lv,origin_uuid,origin,data_percent,lv_attr,lv_tags,vg_uuid,lv_active,data_lv,metadata_lv,lv_parent,lv_role,lv_layout"
|
||||
pvsegs_cols_full="pvseg_start,pvseg_size,segtype,pv_uuid,lv_uuid,pv_name"
|
||||
segs_cols_full="seg_pe_ranges,segtype,lv_uuid"
|
||||
vgs_sort_full="vg_name"
|
||||
pvs_sort_full="pv_name"
|
||||
lvs_sort_full="vg_name,lv_name"
|
||||
pvsegs_sort_full="pv_uuid,pvseg_start"
|
||||
segs_sort_full="lv_uuid,seg_start"
|
||||
}
|
||||
|
||||
log {
|
||||
# lvmdbusd relies on command log report to inspect LVM command's execution status
|
||||
report_command_log=1
|
||||
# display only outermost LVM shell-related log that lvmdbusd inspects first after LVM command execution (it calls 'lastlog' for more detailed log afterwards if needed)
|
||||
command_log_selection="log_context=shell"
|
||||
command_log_cols="log_seq_num,log_type,log_context,log_object_type,log_object_name,log_object_id,log_object_group,log_object_group_id,log_message,log_errno,log_ret_code"
|
||||
command_log_sort="log_seq_num"
|
||||
}
|
@@ -950,6 +950,9 @@ static void _destroy_config(struct cmd_context *cmd)
|
||||
* they will get loaded again automatically.
|
||||
*/
|
||||
dm_list_iterate_items_safe(profile, tmp_profile, &cmd->profile_params->profiles) {
|
||||
if (cmd->is_interactive && (profile == cmd->profile_params->shell_profile))
|
||||
continue;
|
||||
|
||||
config_destroy(profile->cft);
|
||||
profile->cft = NULL;
|
||||
dm_list_move(&cmd->profile_params->profiles_to_load, &profile->list);
|
||||
@@ -1649,37 +1652,6 @@ static void _init_globals(struct cmd_context *cmd)
|
||||
init_mirror_in_sync(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close and reopen stream on file descriptor fd.
|
||||
*/
|
||||
static int _reopen_stream(FILE *stream, int fd, const char *mode, const char *name, FILE **new_stream)
|
||||
{
|
||||
int fd_copy, new_fd;
|
||||
|
||||
if ((fd_copy = dup(fd)) < 0) {
|
||||
log_sys_error("dup", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fclose(stream))
|
||||
log_sys_error("fclose", name);
|
||||
|
||||
if ((new_fd = dup2(fd_copy, fd)) < 0)
|
||||
log_sys_error("dup2", name);
|
||||
else if (new_fd != fd)
|
||||
log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
|
||||
|
||||
if (close(fd_copy) < 0)
|
||||
log_sys_error("close", name);
|
||||
|
||||
if (!(*new_stream = fdopen(fd, mode))) {
|
||||
log_sys_error("fdopen", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* init_connections();
|
||||
* _init_lvmetad();
|
||||
@@ -1835,7 +1807,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
unsigned set_filters)
|
||||
{
|
||||
struct cmd_context *cmd;
|
||||
FILE *new_stream;
|
||||
int flags;
|
||||
|
||||
#ifdef M_MMAP_MAX
|
||||
@@ -1885,9 +1856,8 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (is_valid_fd(STDIN_FILENO) &&
|
||||
((flags = fcntl(STDIN_FILENO, F_GETFL)) > 0) &&
|
||||
(flags & O_ACCMODE) != O_WRONLY) {
|
||||
if (!_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream))
|
||||
if (!reopen_standard_stream(&stdin, "r"))
|
||||
goto_out;
|
||||
stdin = new_stream;
|
||||
if (setvbuf(stdin, cmd->linebuffer, _IOLBF, linebuffer_size)) {
|
||||
log_sys_error("setvbuf", "");
|
||||
goto out;
|
||||
@@ -1897,9 +1867,8 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
if (is_valid_fd(STDOUT_FILENO) &&
|
||||
((flags = fcntl(STDOUT_FILENO, F_GETFL)) > 0) &&
|
||||
(flags & O_ACCMODE) != O_RDONLY) {
|
||||
if (!_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream))
|
||||
if (!reopen_standard_stream(&stdout, "w"))
|
||||
goto_out;
|
||||
stdout = new_stream;
|
||||
if (setvbuf(stdout, cmd->linebuffer + linebuffer_size,
|
||||
_IOLBF, linebuffer_size)) {
|
||||
log_sys_error("setvbuf", "");
|
||||
@@ -1911,7 +1880,6 @@ struct cmd_context *create_toolcontext(unsigned is_long_lived,
|
||||
/* Without buffering, must not use stdin/stdout */
|
||||
init_silent(1);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Environment variable LVM_SYSTEM_DIR overrides this below.
|
||||
*/
|
||||
@@ -2227,7 +2195,6 @@ int refresh_toolcontext(struct cmd_context *cmd)
|
||||
void destroy_toolcontext(struct cmd_context *cmd)
|
||||
{
|
||||
struct dm_config_tree *cft_cmdline;
|
||||
FILE *new_stream;
|
||||
int flags;
|
||||
|
||||
if (cmd->dump_filter && cmd->filter && cmd->filter->dump &&
|
||||
@@ -2254,9 +2221,6 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
if (cmd->cft_def_hash)
|
||||
dm_hash_destroy(cmd->cft_def_hash);
|
||||
|
||||
if (cmd->log_rh)
|
||||
dm_report_free(cmd->log_rh);
|
||||
|
||||
if (cmd->libmem)
|
||||
dm_pool_destroy(cmd->libmem);
|
||||
|
||||
@@ -2266,20 +2230,18 @@ void destroy_toolcontext(struct cmd_context *cmd)
|
||||
if (is_valid_fd(STDIN_FILENO) &&
|
||||
((flags = fcntl(STDIN_FILENO, F_GETFL)) > 0) &&
|
||||
(flags & O_ACCMODE) != O_WRONLY) {
|
||||
if (_reopen_stream(stdin, STDIN_FILENO, "r", "stdin", &new_stream)) {
|
||||
stdin = new_stream;
|
||||
if (reopen_standard_stream(&stdin, "r"))
|
||||
setlinebuf(stdin);
|
||||
} else
|
||||
else
|
||||
cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
|
||||
}
|
||||
|
||||
if (is_valid_fd(STDOUT_FILENO) &&
|
||||
((flags = fcntl(STDOUT_FILENO, F_GETFL)) > 0) &&
|
||||
(flags & O_ACCMODE) != O_RDONLY) {
|
||||
if (_reopen_stream(stdout, STDOUT_FILENO, "w", "stdout", &new_stream)) {
|
||||
stdout = new_stream;
|
||||
if (reopen_standard_stream(&stdout, "w"))
|
||||
setlinebuf(stdout);
|
||||
} else
|
||||
else
|
||||
cmd->linebuffer = NULL; /* Leave buffer in place (deliberate leak) */
|
||||
}
|
||||
|
||||
|
@@ -66,6 +66,15 @@ struct cmd_context_initialized_parts {
|
||||
unsigned connections:1;
|
||||
};
|
||||
|
||||
struct cmd_report {
|
||||
int log_only;
|
||||
dm_report_group_type_t report_group_type;
|
||||
struct dm_report_group *report_group;
|
||||
struct dm_report *log_rh;
|
||||
const char *log_name;
|
||||
log_report_t saved_log_report_state;
|
||||
};
|
||||
|
||||
/* FIXME Split into tool & library contexts */
|
||||
/* command-instance-related variables needed by library */
|
||||
struct cmd_context {
|
||||
@@ -81,7 +90,7 @@ struct cmd_context {
|
||||
const char *cmd_line;
|
||||
struct command *command;
|
||||
char **argv;
|
||||
struct arg_values *arg_values;
|
||||
struct arg_values *opt_arg_values;
|
||||
struct dm_list arg_value_groups;
|
||||
|
||||
/*
|
||||
@@ -186,9 +195,9 @@ struct cmd_context {
|
||||
char proc_dir[PATH_MAX];
|
||||
|
||||
/*
|
||||
* Command log reporting.
|
||||
* Reporting.
|
||||
*/
|
||||
struct dm_report *log_rh; /* keep log report of last cmd for further queries if cmd line is interactive (e.g. lvm shell) */
|
||||
struct cmd_report cmd_report;
|
||||
|
||||
/*
|
||||
* Buffers.
|
||||
|
@@ -385,6 +385,13 @@ int override_config_tree_from_string(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cmd->is_interactive &&
|
||||
!config_force_check(cmd, CONFIG_STRING, cft_new)) {
|
||||
log_error("Ignoring invalid configuration string.");
|
||||
dm_config_destroy(cft_new);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(cs = dm_pool_zalloc(cft_new->mem, sizeof(struct config_source)))) {
|
||||
log_error("Failed to allocate config source.");
|
||||
dm_config_destroy(cft_new);
|
||||
@@ -984,6 +991,20 @@ static int _config_def_check_node_is_profilable(struct cft_check_handle *handle,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_def_check_node_is_allowed(struct cft_check_handle *handle,
|
||||
const char *rp, struct dm_config_node *cn,
|
||||
const cfg_def_item_t *def)
|
||||
{
|
||||
if (handle->disallowed_flags & def->flags) {
|
||||
log_warn_suppress(handle->suppress_messages,
|
||||
"Configuration %s \"%s\" is not allowed here.",
|
||||
cn->v ? "option" : "section", rp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _config_def_check_node(struct cft_check_handle *handle,
|
||||
const char *vp, char *pvp, char *rp, char *prp,
|
||||
size_t buf_size, struct dm_config_node *cn)
|
||||
@@ -1034,6 +1055,9 @@ static int _config_def_check_node(struct cft_check_handle *handle,
|
||||
!_config_def_check_node_is_profilable(handle, rp, cn, def))
|
||||
return_0;
|
||||
|
||||
if (!_config_def_check_node_is_allowed(handle, rp, cn, def))
|
||||
return_0;
|
||||
|
||||
handle->status[def->id] |= CFG_VALID;
|
||||
return 1;
|
||||
}
|
||||
@@ -2113,7 +2137,7 @@ bad:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _check_profile(struct cmd_context *cmd, struct profile *profile)
|
||||
int config_force_check(struct cmd_context *cmd, config_source_t source, struct dm_config_tree *cft)
|
||||
{
|
||||
struct cft_check_handle *handle;
|
||||
int r;
|
||||
@@ -2124,13 +2148,19 @@ static int _check_profile(struct cmd_context *cmd, struct profile *profile)
|
||||
}
|
||||
|
||||
handle->cmd = cmd;
|
||||
handle->cft = profile->cft;
|
||||
handle->source = profile->source;
|
||||
/* the check is compulsory - allow only profilable items in a profile config! */
|
||||
handle->cft = cft;
|
||||
handle->source = source;
|
||||
handle->force_check = 1;
|
||||
/* provide warning messages only if config/checks=1 */
|
||||
handle->suppress_messages = !find_config_tree_bool(cmd, config_checks_CFG, NULL);
|
||||
|
||||
/*
|
||||
* Some settings can't be changed if we're running commands interactively
|
||||
* within lvm shell so check for them in case we're in this interactive mode.
|
||||
*/
|
||||
if (cmd->is_interactive)
|
||||
handle->disallowed_flags |= CFG_DISALLOW_INTERACTIVE;
|
||||
|
||||
r = config_def_check(handle);
|
||||
|
||||
dm_pool_free(cmd->libmem, handle);
|
||||
@@ -2252,7 +2282,7 @@ int load_profile(struct cmd_context *cmd, struct profile *profile) {
|
||||
* messages to be suppressed, but the check itself is always done
|
||||
* for profiles!
|
||||
*/
|
||||
if (!_check_profile(cmd, profile)) {
|
||||
if (!config_force_check(cmd, profile->source, profile->cft)) {
|
||||
log_error("Ignoring invalid %s %s.",
|
||||
_config_source_names[profile->source], profile->name);
|
||||
config_destroy(profile->cft);
|
||||
|
@@ -48,6 +48,7 @@ struct profile_params {
|
||||
struct profile *global_metadata_profile; /* profile (as given by --metadataprofile cmd arg) that overrides any other VG/LV-based profile */
|
||||
struct dm_list profiles_to_load; /* list of profiles which are only added, but still need to be loaded for any use */
|
||||
struct dm_list profiles; /* list of profiles which are loaded already and which are ready for use */
|
||||
struct profile *shell_profile; /* master profile used in interactive/shell mode */
|
||||
};
|
||||
|
||||
#define CFG_PATH_MAX_LEN 128
|
||||
@@ -98,31 +99,34 @@ typedef union {
|
||||
|
||||
|
||||
/* whether the configuration item name is variable */
|
||||
#define CFG_NAME_VARIABLE 0x001
|
||||
#define CFG_NAME_VARIABLE 0x0001
|
||||
/* whether empty value is allowed */
|
||||
#define CFG_ALLOW_EMPTY 0x002
|
||||
#define CFG_ALLOW_EMPTY 0x0002
|
||||
/* whether the configuration item is for advanced use only */
|
||||
#define CFG_ADVANCED 0x004
|
||||
#define CFG_ADVANCED 0x0004
|
||||
/* whether the configuration item is not officially supported */
|
||||
#define CFG_UNSUPPORTED 0x008
|
||||
#define CFG_UNSUPPORTED 0x0008
|
||||
/* whether the configuration item is customizable by a profile */
|
||||
#define CFG_PROFILABLE 0x010
|
||||
/* whether the configuration item is customizable by a profile */
|
||||
/* and whether it can be attached to VG/LV metadata at the same time
|
||||
#define CFG_PROFILABLE 0x0010
|
||||
/* whether the configuration item is customizable by a profile
|
||||
* and whether it can be attached to VG/LV metadata at the same time
|
||||
* The CFG_PROFILABLE_METADATA flag incorporates CFG_PROFILABLE flag!!! */
|
||||
#define CFG_PROFILABLE_METADATA 0x030
|
||||
#define CFG_PROFILABLE_METADATA 0x0030
|
||||
/* whether the default value is undefned */
|
||||
#define CFG_DEFAULT_UNDEFINED 0x040
|
||||
#define CFG_DEFAULT_UNDEFINED 0x0040
|
||||
/* whether the default value is commented out on output */
|
||||
#define CFG_DEFAULT_COMMENTED 0x080
|
||||
#define CFG_DEFAULT_COMMENTED 0x0080
|
||||
/* whether the default value is calculated during run time */
|
||||
#define CFG_DEFAULT_RUN_TIME 0x100
|
||||
#define CFG_DEFAULT_RUN_TIME 0x0100
|
||||
/* whether the configuration setting is disabled (and hence defaults always used) */
|
||||
#define CFG_DISABLED 0x200
|
||||
#define CFG_DISABLED 0x0200
|
||||
/* whether to print integers in octal form (prefixed by "0") */
|
||||
#define CFG_FORMAT_INT_OCTAL 0x400
|
||||
#define CFG_FORMAT_INT_OCTAL 0x0400
|
||||
/* whether to disable checks for the whole config section subtree */
|
||||
#define CFG_SECTION_NO_CHECK 0x800
|
||||
#define CFG_SECTION_NO_CHECK 0x0800
|
||||
/* whether to disallow a possibility to override configuration
|
||||
* setting for commands run interactively (e.g. in lvm shell) */
|
||||
#define CFG_DISALLOW_INTERACTIVE 0x1000
|
||||
|
||||
/* configuration definition item structure */
|
||||
typedef struct cfg_def_item {
|
||||
@@ -212,11 +216,15 @@ struct cft_check_handle {
|
||||
unsigned check_diff:1; /* check if the value used differs from default one */
|
||||
unsigned ignoreadvanced:1; /* do not include advnced configs */
|
||||
unsigned ignoreunsupported:1; /* do not include unsupported configs */
|
||||
uint16_t disallowed_flags; /* set of disallowed flags */
|
||||
uint8_t status[CFG_COUNT]; /* flags for each configuration item - the result of the check */
|
||||
};
|
||||
|
||||
int config_def_get_path(char *buf, size_t buf_size, int id);
|
||||
/* Checks config using given handle - the handle may be reused. */
|
||||
int config_def_check(struct cft_check_handle *handle);
|
||||
/* Forces config check and automatically creates a new handle inside with defaults and discards the handle after the check. */
|
||||
int config_force_check(struct cmd_context *cmd, config_source_t source, struct dm_config_tree *cft);
|
||||
|
||||
int override_config_tree_from_string(struct cmd_context *cmd, const char *config_settings);
|
||||
int override_config_tree_from_profile(struct cmd_context *cmd, struct profile *profile);
|
||||
|
@@ -23,6 +23,11 @@
|
||||
* - define a configuration array of one or more types:
|
||||
* cfg_array(id, name, parent, flags, types, default_value, since_version, unconfigured_default_value, deprecated_since_version, deprecation_comment, comment)
|
||||
*
|
||||
* - define a configuration setting where the default value is evaluated in runtime
|
||||
* cfg_runtime(id, name, parent, flags, type, since_version, deprecated_since_version, deprecation_comment, comment)
|
||||
* (for each cfg_runtime, you need to define 'get_default_<name>(struct cmd_context *cmd, struct profile *profile)' function
|
||||
* to get the default value in runtime - usually, these functions are placed in config.[ch] file)
|
||||
*
|
||||
*
|
||||
* If default value can't be assigned statically because it depends on some
|
||||
* run-time checks or if it depends on other settings already defined,
|
||||
@@ -52,6 +57,7 @@
|
||||
* CFG_DISABLED - configuration is disabled (defaults always used)
|
||||
* CFG_FORMAT_INT_OCTAL - print integer number in octal form (also prefixed by "0")
|
||||
* CFG_SECTION_NO_CHECK - do not check content of the section at all - use with care!!!
|
||||
* CFG_DISALLOW_INTERACTIVE - disallow configuration node for use in interactive environment (e.g. cmds run in lvm shell)
|
||||
*
|
||||
* type: Allowed type for the value of simple configuation setting, one of:
|
||||
* CFG_TYPE_BOOL
|
||||
@@ -166,7 +172,7 @@ cfg(config_checks_CFG, "checks", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 1, vsn(2,
|
||||
cfg(config_abort_on_errors_CFG, "abort_on_errors", config_CFG_SECTION, 0, CFG_TYPE_BOOL, 0, vsn(2,2,99), NULL, 0, NULL,
|
||||
"Abort the LVM process if a configuration mismatch is found.\n")
|
||||
|
||||
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, 0, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
|
||||
cfg_runtime(config_profile_dir_CFG, "profile_dir", config_CFG_SECTION, CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, vsn(2, 2, 99), 0, NULL,
|
||||
"Directory where LVM looks for configuration profiles.\n")
|
||||
|
||||
cfg(devices_dir_CFG, "dir", devices_CFG_SECTION, CFG_ADVANCED, CFG_TYPE_STRING, DEFAULT_DEV_DIR, vsn(1, 0, 0), NULL, 0, NULL,
|
||||
@@ -553,7 +559,7 @@ cfg_runtime(allocation_thin_pool_chunk_size_CFG, "thin_pool_chunk_size", allocat
|
||||
cfg(allocation_physical_extent_size_CFG, "physical_extent_size", allocation_CFG_SECTION, CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, DEFAULT_EXTENT_SIZE, vsn(2, 2, 112), NULL, 0, NULL,
|
||||
"Default physical extent size in KiB to use for new VGs.\n")
|
||||
|
||||
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_BOOL, DEFAULT_COMMAND_LOG_REPORT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
"Enable or disable LVM log reporting.\n"
|
||||
"If enabled, LVM will collect a log of operations, messages,\n"
|
||||
"per-object return codes with object identification and associated\n"
|
||||
@@ -569,17 +575,17 @@ cfg(log_report_command_log_CFG, "report_command_log", log_CFG_SECTION, CFG_PROFI
|
||||
"You can also use log/command_log_selection to define selection\n"
|
||||
"criteria used each time the log is reported.\n")
|
||||
|
||||
cfg(log_command_log_sort_CFG, "command_log_sort", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SORT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
cfg(log_command_log_sort_CFG, "command_log_sort", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SORT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
"List of columns to sort by when reporting command log.\n"
|
||||
"See <lvm command> --logonly --configreport log -o help\n"
|
||||
"for the list of possible fields.\n")
|
||||
|
||||
cfg(log_command_log_cols_CFG, "command_log_cols", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_COLS, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
cfg(log_command_log_cols_CFG, "command_log_cols", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_COLS, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
"List of columns to report when reporting command log.\n"
|
||||
"See <lvm command> --logonly --configreport log -o help\n"
|
||||
"for the list of possible fields.\n")
|
||||
|
||||
cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SELECTION, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
cfg(log_command_log_selection_CFG, "command_log_selection", log_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_COMMAND_LOG_SELECTION, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
"Selection criteria used when reporting command log.\n"
|
||||
"You can define selection criteria that are applied each\n"
|
||||
"time log is reported. This way, it is possible to control the\n"
|
||||
@@ -1509,7 +1515,7 @@ cfg(disk_area_start_sector_CFG, "start_sector", disk_area_CFG_SUBSECTION, CFG_UN
|
||||
cfg(disk_area_size_CFG, "size", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_COMMENTED, CFG_TYPE_INT, 0, vsn(1, 0, 0), NULL, 0, NULL, NULL)
|
||||
cfg(disk_area_id_CFG, "id", disk_area_CFG_SUBSECTION, CFG_UNSUPPORTED | CFG_DEFAULT_UNDEFINED, CFG_TYPE_STRING, NULL, vsn(1, 0, 0), NULL, 0, NULL, NULL)
|
||||
|
||||
cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED, CFG_TYPE_STRING, DEFAULT_REP_OUTPUT_FORMAT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
cfg(report_output_format_CFG, "output_format", report_CFG_SECTION, CFG_PROFILABLE | CFG_DEFAULT_COMMENTED | CFG_DISALLOW_INTERACTIVE, CFG_TYPE_STRING, DEFAULT_REP_OUTPUT_FORMAT, vsn(2, 2, 158), NULL, 0, NULL,
|
||||
"Format of LVM command's report output.\n"
|
||||
"If there is more than one report per command, then the format\n"
|
||||
"is applied for all reports. You can also change output format\n"
|
||||
|
@@ -66,8 +66,13 @@
|
||||
#define DEFAULT_MIRROR_LOG_FAULT_POLICY "allocate"
|
||||
#define DEFAULT_MIRROR_IMAGE_FAULT_POLICY "remove"
|
||||
#define DEFAULT_MIRROR_MAX_IMAGES 8 /* limited by kernel DM_KCOPYD_MAX_REGIONS */
|
||||
// FIXME Increase this to 64
|
||||
#define DEFAULT_RAID_MAX_IMAGES 8 /* limited by kernel failed devices bitfield in superblock (raid4/5/6 max 253) */
|
||||
/* Limited by kernel failed devices bitfield in superblock (raid4/5/6 MD max 253) */
|
||||
/*
|
||||
* FIXME: Increase these to 64 and further to the MD maximum
|
||||
* once the SubLVs split and name shift got enhanced
|
||||
*/
|
||||
#define DEFAULT_RAID1_MAX_IMAGES 10
|
||||
#define DEFAULT_RAID_MAX_IMAGES 64
|
||||
#define DEFAULT_ALLOCATION_STRIPE_ALL_DEVICES 0 /* Don't stripe across all devices if not -i/--stripes given */
|
||||
|
||||
#define DEFAULT_RAID_FAULT_POLICY "warn"
|
||||
|
174
lib/log/log.c
174
lib/log/log.c
@@ -18,6 +18,7 @@
|
||||
#include "memlock.h"
|
||||
#include "defaults.h"
|
||||
#include "report.h"
|
||||
#include "lvm-file.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
@@ -59,6 +60,154 @@ static log_report_t _log_report = {
|
||||
.object_group = NULL
|
||||
};
|
||||
|
||||
#define LOG_STREAM_BUFFER_SIZE 4096
|
||||
|
||||
struct log_stream_item {
|
||||
FILE *stream;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
struct log_stream {
|
||||
struct log_stream_item out;
|
||||
struct log_stream_item err;
|
||||
struct log_stream_item report;
|
||||
} _log_stream = {{NULL, NULL},
|
||||
{NULL, NULL},
|
||||
{NULL, NULL}};
|
||||
|
||||
#define out_stream (_log_stream.out.stream ? : stdout)
|
||||
#define err_stream (_log_stream.err.stream ? : stderr)
|
||||
#define report_stream (_log_stream.report.stream ? : stdout)
|
||||
|
||||
static int _set_custom_log_stream(struct log_stream_item *stream_item, int custom_fd)
|
||||
{
|
||||
FILE *final_stream = NULL;
|
||||
int flags;
|
||||
int r = 1;
|
||||
|
||||
if (custom_fd < 0)
|
||||
goto out;
|
||||
|
||||
if (is_valid_fd(custom_fd)) {
|
||||
if ((flags = fcntl(custom_fd, F_GETFL)) > 0) {
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
log_error("File descriptor %d already open in read-only "
|
||||
"mode, expected write-only or read-write mode.",
|
||||
(int) custom_fd);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (custom_fd == STDIN_FILENO) {
|
||||
log_error("Can't set standard input for log output.");
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (custom_fd == STDOUT_FILENO) {
|
||||
final_stream = stdout;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (custom_fd == STDERR_FILENO) {
|
||||
final_stream = stderr;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(final_stream = fdopen(custom_fd, "w"))) {
|
||||
log_error("Failed to open stream for file descriptor %d.",
|
||||
(int) custom_fd);
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(stream_item->buffer = dm_malloc(LOG_STREAM_BUFFER_SIZE))) {
|
||||
log_error("Failed to allocate buffer for stream on file "
|
||||
"descriptor %d.", (int) custom_fd);
|
||||
} else {
|
||||
if (setvbuf(final_stream, stream_item->buffer, _IOLBF, LOG_STREAM_BUFFER_SIZE)) {
|
||||
log_sys_error("setvbuf", "");
|
||||
dm_free(stream_item->buffer);
|
||||
stream_item->buffer = NULL;
|
||||
}
|
||||
}
|
||||
out:
|
||||
stream_item->stream = final_stream;
|
||||
return r;
|
||||
}
|
||||
|
||||
int init_custom_log_streams(struct custom_fds *custom_fds)
|
||||
{
|
||||
return _set_custom_log_stream(&_log_stream.out, custom_fds->out) &&
|
||||
_set_custom_log_stream(&_log_stream.err, custom_fds->err) &&
|
||||
_set_custom_log_stream(&_log_stream.report, custom_fds->report);
|
||||
}
|
||||
|
||||
static void _check_and_replace_standard_log_streams(FILE *old_stream, FILE *new_stream)
|
||||
{
|
||||
if (_log_stream.out.stream == old_stream)
|
||||
_log_stream.out.stream = new_stream;
|
||||
|
||||
if (_log_stream.err.stream == old_stream)
|
||||
_log_stream.err.stream = new_stream;
|
||||
|
||||
if (_log_stream.report.stream == old_stream)
|
||||
_log_stream.report.stream = new_stream;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close and reopen standard stream on file descriptor fd.
|
||||
*/
|
||||
int reopen_standard_stream(FILE **stream, const char *mode)
|
||||
{
|
||||
int fd, fd_copy, new_fd;
|
||||
const char *name;
|
||||
FILE *old_stream = *stream;
|
||||
FILE *new_stream;
|
||||
|
||||
if (old_stream == stdin) {
|
||||
fd = STDIN_FILENO;
|
||||
name = "stdin";
|
||||
} else if (old_stream == stdout) {
|
||||
fd = STDOUT_FILENO;
|
||||
name = "stdout";
|
||||
} else if (old_stream == stderr) {
|
||||
fd = STDERR_FILENO;
|
||||
name = "stderr";
|
||||
} else {
|
||||
log_error(INTERNAL_ERROR "reopen_standard_stream called on non-standard stream");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((fd_copy = dup(fd)) < 0) {
|
||||
log_sys_error("dup", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fclose(old_stream))
|
||||
log_sys_error("fclose", name);
|
||||
|
||||
if ((new_fd = dup2(fd_copy, fd)) < 0)
|
||||
log_sys_error("dup2", name);
|
||||
else if (new_fd != fd)
|
||||
log_error("dup2(%d, %d) returned %d", fd_copy, fd, new_fd);
|
||||
|
||||
if (close(fd_copy) < 0)
|
||||
log_sys_error("close", name);
|
||||
|
||||
if (!(new_stream = fdopen(fd, mode))) {
|
||||
log_sys_error("fdopen", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_check_and_replace_standard_log_streams(old_stream, new_stream);
|
||||
|
||||
*stream = new_stream;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void init_log_fn(lvm2_log_fn_t log_fn)
|
||||
{
|
||||
_lvm2_log_fn = log_fn;
|
||||
@@ -207,10 +356,10 @@ void fin_log(void)
|
||||
if (_log_to_file) {
|
||||
if (dm_fclose(_log_file)) {
|
||||
if (errno)
|
||||
fprintf(stderr, "failed to write log file: %s\n",
|
||||
fprintf(err_stream, "failed to write log file: %s\n",
|
||||
strerror(errno));
|
||||
else
|
||||
fprintf(stderr, "failed to write log file\n");
|
||||
fprintf(err_stream, "failed to write log file\n");
|
||||
|
||||
}
|
||||
_log_to_file = 0;
|
||||
@@ -300,6 +449,7 @@ static const char *_get_log_level_name(int use_stderr, int level)
|
||||
const char *log_get_report_context_name(log_report_context_t context)
|
||||
{
|
||||
static const char *log_context_names[LOG_REPORT_CONTEXT_COUNT] = {[LOG_REPORT_CONTEXT_NULL] = "",
|
||||
[LOG_REPORT_CONTEXT_SHELL] = "shell",
|
||||
[LOG_REPORT_CONTEXT_PROCESSING] = "processing"};
|
||||
return log_context_names[context];
|
||||
}
|
||||
@@ -308,6 +458,7 @@ const char *log_get_report_context_name(log_report_context_t context)
|
||||
const char *log_get_report_object_type_name(log_report_object_type_t object_type)
|
||||
{
|
||||
static const char *log_object_type_names[LOG_REPORT_OBJECT_TYPE_COUNT] = {[LOG_REPORT_OBJECT_TYPE_NULL] = "",
|
||||
[LOG_REPORT_OBJECT_TYPE_CMD] = "cmd",
|
||||
[LOG_REPORT_OBJECT_TYPE_ORPHAN] = "orphan",
|
||||
[LOG_REPORT_OBJECT_TYPE_PV] = "pv",
|
||||
[LOG_REPORT_OBJECT_TYPE_LABEL] = "label",
|
||||
@@ -378,8 +529,8 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
|
||||
/* When newer glibc returns >= sizeof(locn), we will just log what
|
||||
* has fit into buffer, it's '\0' terminated string */
|
||||
if (n < 0) {
|
||||
fprintf(stderr, _("vsnprintf failed: skipping external "
|
||||
"logging function"));
|
||||
fprintf(err_stream, _("vsnprintf failed: skipping external "
|
||||
"logging function"));
|
||||
goto log_it;
|
||||
}
|
||||
}
|
||||
@@ -426,7 +577,7 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
|
||||
_log_report.object_name, _log_report.object_id,
|
||||
_log_report.object_group, _log_report.object_group_id,
|
||||
message, _lvm_errno, 0))
|
||||
fprintf(stderr, _("failed to report cmdstatus"));
|
||||
fprintf(err_stream, _("failed to report cmdstatus"));
|
||||
else
|
||||
logged_via_report = 1;
|
||||
|
||||
@@ -468,10 +619,10 @@ static void _vprint_log(int level, const char *file, int line, int dm_errno_or_c
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
/* Typically only log_warn goes to stdout */
|
||||
stream = (use_stderr || (level != _LOG_WARN)) ? stderr : stdout;
|
||||
if (stream == stderr)
|
||||
fflush(stdout);
|
||||
/* Typically only log_warn goes to out_stream */
|
||||
stream = (use_stderr || (level != _LOG_WARN)) ? err_stream : out_stream;
|
||||
if (stream == err_stream)
|
||||
fflush(out_stream);
|
||||
fprintf(stream, "%s%s%s%s", buf, log_command_name(),
|
||||
_msg_prefix, indent_spaces);
|
||||
vfprintf(stream, trformat, ap);
|
||||
@@ -556,6 +707,7 @@ void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
void print_log_libdm(int level, const char *file, int line, int dm_errno_or_class,
|
||||
const char *format, ...)
|
||||
{
|
||||
FILE *orig_out_stream = out_stream;
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
@@ -567,9 +719,13 @@ void print_log_libdm(int level, const char *file, int line, int dm_errno_or_clas
|
||||
((level & ~(_LOG_STDERR|_LOG_ONCE|_LOG_BYPASS_REPORT)) == _LOG_WARN))
|
||||
level |= _LOG_BYPASS_REPORT;
|
||||
|
||||
_log_stream.out.stream = report_stream;
|
||||
|
||||
va_start(ap, format);
|
||||
_vprint_log(level, file, line, dm_errno_or_class, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
_log_stream.out.stream = orig_out_stream;
|
||||
}
|
||||
|
||||
log_report_t log_get_report_state(void)
|
||||
|
@@ -16,6 +16,8 @@
|
||||
#ifndef _LVM_LOGGING_H
|
||||
#define _LVM_LOGGING_H
|
||||
|
||||
#include "lvm-file.h"
|
||||
|
||||
__attribute__ ((format(printf, 5, 6)))
|
||||
void print_log(int level, const char *file, int line, int dm_errno_or_class,
|
||||
const char *format, ...);
|
||||
@@ -35,6 +37,9 @@ void print_log_libdm(int level, const char *file, int line, int dm_errno_or_clas
|
||||
|
||||
#include "log.h"
|
||||
|
||||
int init_custom_log_streams(struct custom_fds *custom_fds);
|
||||
int reopen_standard_stream(FILE **stream, const char *mode);
|
||||
|
||||
typedef void (*lvm2_log_fn_t) (int level, const char *file, int line,
|
||||
int dm_errno_or_class, const char *message);
|
||||
|
||||
@@ -72,12 +77,14 @@ void syslog_suppress(int suppress);
|
||||
/* Hooks to handle logging through report. */
|
||||
typedef enum {
|
||||
LOG_REPORT_CONTEXT_NULL,
|
||||
LOG_REPORT_CONTEXT_SHELL,
|
||||
LOG_REPORT_CONTEXT_PROCESSING,
|
||||
LOG_REPORT_CONTEXT_COUNT
|
||||
} log_report_context_t;
|
||||
|
||||
typedef enum {
|
||||
LOG_REPORT_OBJECT_TYPE_NULL,
|
||||
LOG_REPORT_OBJECT_TYPE_CMD,
|
||||
LOG_REPORT_OBJECT_TYPE_ORPHAN,
|
||||
LOG_REPORT_OBJECT_TYPE_PV,
|
||||
LOG_REPORT_OBJECT_TYPE_LABEL,
|
||||
@@ -96,6 +103,10 @@ typedef struct log_report {
|
||||
const char *object_group_id;
|
||||
} log_report_t;
|
||||
|
||||
#define LOG_STATUS_NAME "status"
|
||||
#define LOG_STATUS_SUCCESS "success"
|
||||
#define LOG_STATUS_FAILURE "failure"
|
||||
|
||||
log_report_t log_get_report_state(void);
|
||||
void log_restore_report_state(log_report_t log_report);
|
||||
|
||||
|
@@ -119,6 +119,7 @@ enum {
|
||||
LV_TYPE_RAID10,
|
||||
LV_TYPE_RAID4,
|
||||
LV_TYPE_RAID5,
|
||||
LV_TYPE_RAID5_N,
|
||||
LV_TYPE_RAID5_LA,
|
||||
LV_TYPE_RAID5_RA,
|
||||
LV_TYPE_RAID5_LS,
|
||||
@@ -169,6 +170,7 @@ static const char *_lv_type_names[] = {
|
||||
[LV_TYPE_RAID10] = SEG_TYPE_NAME_RAID10,
|
||||
[LV_TYPE_RAID4] = SEG_TYPE_NAME_RAID4,
|
||||
[LV_TYPE_RAID5] = SEG_TYPE_NAME_RAID5,
|
||||
[LV_TYPE_RAID5_N] = SEG_TYPE_NAME_RAID5_N,
|
||||
[LV_TYPE_RAID5_LA] = SEG_TYPE_NAME_RAID5_LA,
|
||||
[LV_TYPE_RAID5_RA] = SEG_TYPE_NAME_RAID5_RA,
|
||||
[LV_TYPE_RAID5_LS] = SEG_TYPE_NAME_RAID5_LS,
|
||||
@@ -3279,7 +3281,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
|
||||
log_debug("Adjusted allocation request to %" PRIu32 " logical extents. Existing size %" PRIu32 ". New size %" PRIu32 ".",
|
||||
total_extents, existing_extents, total_extents + existing_extents);
|
||||
if (ah->log_len)
|
||||
log_debug("Mirror log of %" PRIu32 " extents of size %" PRIu32 "sectors needed for region size %" PRIu32 ".",
|
||||
log_debug("Mirror log of %" PRIu32 " extents of size %" PRIu32 " sectors needed for region size %" PRIu32 ".",
|
||||
ah->log_len, extent_size, ah->region_size);
|
||||
|
||||
if (mirrors || stripes)
|
||||
|
@@ -97,6 +97,9 @@ static void _check_raid0_seg(struct lv_segment *seg, int *error_count)
|
||||
if (seg_is_raid0_meta(seg) &&
|
||||
!seg->meta_areas)
|
||||
raid_seg_error("no meta areas");
|
||||
if (!seg_is_raid0_meta(seg) &&
|
||||
seg->meta_areas)
|
||||
raid_seg_error("meta areas");
|
||||
if (!seg->stripe_size)
|
||||
raid_seg_error("zero stripe size");
|
||||
if (!is_power_of_2(seg->stripe_size))
|
||||
@@ -121,7 +124,7 @@ static void _check_raid_region_recovery(struct lv_segment *seg, int *error_count
|
||||
/* min/max recovery rate may be zero but min may not be larger than max if set */
|
||||
if (seg->max_recovery_rate &&
|
||||
seg->min_recovery_rate > seg->max_recovery_rate)
|
||||
raid_seg_error_val("min recovery larger than max recovery larger", seg->min_recovery_rate);
|
||||
raid_seg_error_val("min recovery larger than max recovery", seg->min_recovery_rate);
|
||||
}
|
||||
|
||||
/* Check raid1 segment properties in @seg */
|
||||
@@ -258,10 +261,17 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
|
||||
if (seg->extents_copied > seg->area_len)
|
||||
raid_seg_error_val("extents_copied too large", seg->extents_copied);
|
||||
|
||||
/* Default still 8, change! */
|
||||
if (seg->area_count > DEFAULT_RAID_MAX_IMAGES) {
|
||||
/* Default < 10, change once raid1 split shift and rename SubLVs works! */
|
||||
if (seg_is_raid1(seg)) {
|
||||
if (seg->area_count > DEFAULT_RAID1_MAX_IMAGES) {
|
||||
log_error("LV %s invalid: maximum supported areas %u (is %u) for %s segment",
|
||||
seg->lv->name, DEFAULT_RAID1_MAX_IMAGES, seg->area_count, lvseg_name(seg));
|
||||
if ((*error_count)++ > ERROR_MAX)
|
||||
return;
|
||||
}
|
||||
} else if (seg->area_count > DEFAULT_RAID_MAX_IMAGES) {
|
||||
log_error("LV %s invalid: maximum supported areas %u (is %u) for %s segment",
|
||||
seg->lv->name, DEFAULT_RAID_MAX_IMAGES, seg->area_count, lvseg_name(seg));
|
||||
seg->lv->name, DEFAULT_RAID_MAX_IMAGES, seg->area_count, lvseg_name(seg));
|
||||
if ((*error_count)++ > ERROR_MAX)
|
||||
return;
|
||||
}
|
||||
@@ -289,8 +299,10 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
|
||||
/* Check for any MetaLV flaws like non-existing ones or size variations */
|
||||
if (seg->meta_areas)
|
||||
for (area_len = s = 0; s < seg->area_count; s++) {
|
||||
if (seg_metatype(seg, s) != AREA_LV)
|
||||
if (seg_metatype(seg, s) != AREA_LV) {
|
||||
raid_seg_error("no MetaLV");
|
||||
continue;
|
||||
}
|
||||
if (!lv_is_raid_metadata(seg_metalv(seg, s)))
|
||||
raid_seg_error("MetaLV without RAID metadata flag");
|
||||
if (area_len &&
|
||||
@@ -391,7 +403,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
seg_count++;
|
||||
|
||||
if (seg_is_raid(seg))
|
||||
if (complete_vg && seg_is_raid(seg))
|
||||
_check_raid_seg(seg, &error_count);
|
||||
|
||||
if (seg->le != le) {
|
||||
|
@@ -1190,7 +1190,7 @@ struct logical_volume *first_replicator_dev(const struct logical_volume *lv);
|
||||
int lv_is_raid_with_tracking(const struct logical_volume *lv);
|
||||
uint32_t lv_raid_image_count(const struct logical_volume *lv);
|
||||
int lv_raid_change_image_count(struct logical_volume *lv,
|
||||
uint32_t new_count, struct dm_list *pvs);
|
||||
uint32_t new_count, struct dm_list *allocate_pvs);
|
||||
int lv_raid_split(struct logical_volume *lv, const char *split_name,
|
||||
uint32_t new_count, struct dm_list *splittable_pvs);
|
||||
int lv_raid_split_and_track(struct logical_volume *lv,
|
||||
@@ -1200,8 +1200,11 @@ int lv_raid_convert(struct logical_volume *lv,
|
||||
const struct segment_type *new_segtype,
|
||||
int yes, int force,
|
||||
const unsigned stripes,
|
||||
const unsigned new_stripe_size_supplied,
|
||||
const unsigned new_stripe_size,
|
||||
const uint32_t new_region_size,
|
||||
struct dm_list *allocate_pvs);
|
||||
int lv_raid_rebuild(struct logical_volume *lv, struct dm_list *rebuild_pvs);
|
||||
int lv_raid_replace(struct logical_volume *lv, struct dm_list *remove_pvs,
|
||||
struct dm_list *allocate_pvs);
|
||||
int lv_raid_remove_missing(struct logical_volume *lv);
|
||||
@@ -1269,6 +1272,7 @@ uint32_t find_free_lvnum(struct logical_volume *lv);
|
||||
dm_percent_t copy_percent(const struct logical_volume *lv_mirr);
|
||||
char *generate_lv_name(struct volume_group *vg, const char *format,
|
||||
char *buffer, size_t len);
|
||||
char *top_level_lv_name(struct volume_group *vg, const char *lv_name);
|
||||
|
||||
struct generic_logical_volume *get_or_create_glv(struct dm_pool *mem, struct logical_volume *lv, int *glv_created);
|
||||
struct glv_list *get_or_create_glvl(struct dm_pool *mem, struct logical_volume *lv, int *glv_created);
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -47,7 +47,7 @@ struct segment_type *get_segtype_from_flag(struct cmd_context *cmd, uint64_t fla
|
||||
if (flag & segtype->flags)
|
||||
return segtype;
|
||||
|
||||
log_error(INTERNAL_ERROR "Unrecognised segment type flag 0x%" PRIx64, flag);
|
||||
log_error(INTERNAL_ERROR "Unrecognised segment type flag 0x%016" PRIx64, flag);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -68,6 +68,8 @@ struct dev_manager;
|
||||
#define SEG_RAID6_N_6 0x0000000800000000ULL
|
||||
#define SEG_RAID6 SEG_RAID6_ZR
|
||||
|
||||
#define SEG_STRIPED_TARGET 0x0000008000000000ULL
|
||||
|
||||
#define SEG_UNKNOWN 0x8000000000000000ULL
|
||||
|
||||
#define SEG_TYPE_NAME_LINEAR "linear"
|
||||
@@ -88,6 +90,7 @@ struct dev_manager;
|
||||
#define SEG_TYPE_NAME_RAID10 "raid10"
|
||||
#define SEG_TYPE_NAME_RAID4 "raid4"
|
||||
#define SEG_TYPE_NAME_RAID5 "raid5"
|
||||
#define SEG_TYPE_NAME_RAID5_N "raid5_n"
|
||||
#define SEG_TYPE_NAME_RAID5_LA "raid5_la"
|
||||
#define SEG_TYPE_NAME_RAID5_LS "raid5_ls"
|
||||
#define SEG_TYPE_NAME_RAID5_RA "raid5_ra"
|
||||
@@ -96,8 +99,14 @@ struct dev_manager;
|
||||
#define SEG_TYPE_NAME_RAID6_NC "raid6_nc"
|
||||
#define SEG_TYPE_NAME_RAID6_NR "raid6_nr"
|
||||
#define SEG_TYPE_NAME_RAID6_ZR "raid6_zr"
|
||||
#define SEG_TYPE_NAME_RAID6_LA_6 "raid6_la_6"
|
||||
#define SEG_TYPE_NAME_RAID6_LS_6 "raid6_ls_6"
|
||||
#define SEG_TYPE_NAME_RAID6_RA_6 "raid6_ra_6"
|
||||
#define SEG_TYPE_NAME_RAID6_RS_6 "raid6_rs_6"
|
||||
#define SEG_TYPE_NAME_RAID6_N_6 "raid6_n_6"
|
||||
|
||||
#define segtype_is_linear(segtype) (!strcmp(segtype->name, SEG_TYPE_NAME_LINEAR))
|
||||
#define segtype_is_striped_target(segtype) ((segtype)->flags & SEG_STRIPED_TARGET ? 1 : 0)
|
||||
#define segtype_is_cache(segtype) ((segtype)->flags & SEG_CACHE ? 1 : 0)
|
||||
#define segtype_is_cache_pool(segtype) ((segtype)->flags & SEG_CACHE_POOL ? 1 : 0)
|
||||
#define segtype_is_mirrored(segtype) ((segtype)->flags & SEG_AREAS_MIRRORED ? 1 : 0)
|
||||
@@ -111,6 +120,7 @@ struct dev_manager;
|
||||
#define segtype_is_raid4(segtype) ((segtype)->flags & SEG_RAID4 ? 1 : 0)
|
||||
#define segtype_is_any_raid5(segtype) ((segtype)->flags & \
|
||||
(SEG_RAID5_LS|SEG_RAID5_LA|SEG_RAID5_RS|SEG_RAID5_RA|SEG_RAID5_N) ? 1 : 0)
|
||||
#define segtype_is_raid5_n(segtype) ((segtype)->flags & SEG_RAID5_N ? 1 : 0)
|
||||
#define segtype_is_raid5_la(segtype) ((segtype)->flags & SEG_RAID5_LA ? 1 : 0)
|
||||
#define segtype_is_raid5_ra(segtype) ((segtype)->flags & SEG_RAID5_RA ? 1 : 0)
|
||||
#define segtype_is_raid5_ls(segtype) ((segtype)->flags & SEG_RAID5_LS ? 1 : 0)
|
||||
@@ -120,8 +130,11 @@ struct dev_manager;
|
||||
SEG_RAID6_LA_6|SEG_RAID6_LS_6|SEG_RAID6_RA_6|SEG_RAID6_RS_6|SEG_RAID6_N_6) ? 1 : 0)
|
||||
#define segtype_is_raid6_nc(segtype) ((segtype)->flags & SEG_RAID6_NC ? 1 : 0)
|
||||
#define segtype_is_raid6_nr(segtype) ((segtype)->flags & SEG_RAID6_NR ? 1 : 0)
|
||||
#define segtype_is_raid6_n_6(segtype) ((segtype)->flags & SEG_RAID6_N_6 ? 1 : 0)
|
||||
#define segtype_is_raid6_zr(segtype) ((segtype)->flags & SEG_RAID6_ZR ? 1 : 0)
|
||||
#define segtype_is_any_raid10(segtype) ((segtype)->flags & SEG_RAID10 ? 1 : 0)
|
||||
#define segtype_is_raid10(segtype) ((segtype)->flags & SEG_RAID10 ? 1 : 0)
|
||||
#define segtype_is_raid10_near(segtype) segtype_is_raid10(segtype)
|
||||
#define segtype_is_raid_with_meta(segtype) (segtype_is_raid(segtype) && !segtype_is_raid0(segtype))
|
||||
#define segtype_is_snapshot(segtype) ((segtype)->flags & SEG_SNAPSHOT ? 1 : 0)
|
||||
#define segtype_is_striped(segtype) ((segtype)->flags & SEG_AREAS_STRIPED ? 1 : 0)
|
||||
@@ -131,6 +144,13 @@ struct dev_manager;
|
||||
#define segtype_is_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
|
||||
#define segtype_is_unknown(segtype) ((segtype)->flags & SEG_UNKNOWN ? 1 : 0)
|
||||
|
||||
#define segtype_supports_stripe_size(segtype) \
|
||||
((segtype_is_striped(segtype) || segtype_is_mirror(segtype) || \
|
||||
segtype_is_cache(segtype) || segtype_is_cache_pool(segtype) || \
|
||||
segtype_is_thin(segtype) || segtype_is_snapshot(segtype) || \
|
||||
(segtype_is_raid(segtype) && !segtype_is_raid1(segtype))) ? 1 : 0)
|
||||
|
||||
#define seg_is_striped_target(seg) segtype_is_striped_target((seg)->segtype)
|
||||
#define seg_is_cache(seg) segtype_is_cache((seg)->segtype)
|
||||
#define seg_is_cache_pool(seg) segtype_is_cache_pool((seg)->segtype)
|
||||
#define seg_is_linear(seg) (seg_is_striped(seg) && ((seg)->area_count == 1))
|
||||
@@ -144,6 +164,7 @@ struct dev_manager;
|
||||
#define seg_is_raid1(seg) segtype_is_raid1((seg)->segtype)
|
||||
#define seg_is_raid4(seg) segtype_is_raid4((seg)->segtype)
|
||||
#define seg_is_any_raid5(seg) segtype_is_any_raid5((seg)->segtype)
|
||||
#define seg_is_raid5_n(seg) segtype_is_raid5_n((seg)->segtype)
|
||||
#define seg_is_raid5_la(seg) segtype_is_raid5_la((seg)->segtype)
|
||||
#define seg_is_raid5_ra(seg) segtype_is_raid5_ra((seg)->segtype)
|
||||
#define seg_is_raid5_ls(seg) segtype_is_raid5_ls((seg)->segtype)
|
||||
@@ -152,7 +173,10 @@ struct dev_manager;
|
||||
#define seg_is_raid6_zr(seg) segtype_is_raid6_zr((seg)->segtype)
|
||||
#define seg_is_raid6_nr(seg) segtype_is_raid6_nr((seg)->segtype)
|
||||
#define seg_is_raid6_nc(seg) segtype_is_raid6_nc((seg)->segtype)
|
||||
#define seg_is_raid6_n_6(seg) segtype_is_raid6_n_6((seg)->segtype)
|
||||
#define seg_is_any_raid10(seg) segtype_is_any_raid10((seg)->segtype)
|
||||
#define seg_is_raid10(seg) segtype_is_raid10((seg)->segtype)
|
||||
#define seg_is_raid10_near(seg) segtype_is_raid10_near((seg)->segtype)
|
||||
#define seg_is_raid_with_meta(seg) segtype_is_raid_with_meta((seg)->segtype)
|
||||
#define seg_is_replicator(seg) ((seg)->segtype->flags & SEG_REPLICATOR ? 1 : 0)
|
||||
#define seg_is_replicator_dev(seg) ((seg)->segtype->flags & SEG_REPLICATOR_DEV ? 1 : 0)
|
||||
|
@@ -16,6 +16,12 @@
|
||||
#ifndef _LVM_FILE_H
|
||||
#define _LVM_FILE_H
|
||||
|
||||
struct custom_fds {
|
||||
int out;
|
||||
int err;
|
||||
int report;
|
||||
};
|
||||
|
||||
/*
|
||||
* Create a temporary filename, and opens a descriptor to the file.
|
||||
*/
|
||||
|
@@ -73,7 +73,7 @@ void lvmnotify_send(struct cmd_context *cmd)
|
||||
out:
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_message_unref(m);
|
||||
sd_bus_unref(bus);
|
||||
sd_bus_flush_close_unref(bus);
|
||||
}
|
||||
|
||||
void set_vg_notify(struct cmd_context *cmd)
|
||||
|
@@ -38,6 +38,9 @@ struct lvm_report_object {
|
||||
struct label *label;
|
||||
};
|
||||
|
||||
static uint32_t log_seqnum = 1;
|
||||
|
||||
|
||||
/*
|
||||
* Enum for field_num index to use in per-field reserved value definition.
|
||||
* Each field is represented by enum value with name "field_<id>" where <id>
|
||||
@@ -3867,9 +3870,7 @@ int report_cmdlog(void *handle, const char *type, const char *context,
|
||||
const char *object_group_id, const char *msg,
|
||||
int current_errno, int ret_code)
|
||||
{
|
||||
static uint32_t seq_num = 1;
|
||||
|
||||
struct cmd_log_item log_item = {seq_num++, type, context, object_type_name,
|
||||
struct cmd_log_item log_item = {log_seqnum++, type, context, object_type_name,
|
||||
object_name ? : "", object_id ? : "",
|
||||
object_group ? : "", object_group_id ? : "",
|
||||
msg ? : "", current_errno, ret_code};
|
||||
@@ -3880,6 +3881,11 @@ int report_cmdlog(void *handle, const char *type, const char *context,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void report_reset_cmdlog_seqnum(void)
|
||||
{
|
||||
log_seqnum = 1;
|
||||
}
|
||||
|
||||
int report_current_object_cmdlog(const char *type, const char *msg, int32_t ret_code)
|
||||
{
|
||||
log_report_t log_state = log_get_report_state();
|
||||
|
@@ -81,9 +81,7 @@ struct processing_handle;
|
||||
typedef int (*field_report_fn) (struct report_handle * dh, struct field * field,
|
||||
const void *data);
|
||||
|
||||
int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_group_type,
|
||||
struct dm_report_group **report_group, struct dm_report **log_rh,
|
||||
int *log_only, log_report_t *saved_log_report_state);
|
||||
int report_format_init(struct cmd_context *cmd);
|
||||
|
||||
void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
|
||||
report_type_t *report_type, const char *separator,
|
||||
@@ -113,6 +111,7 @@ int report_cmdlog(void *handle, const char *type, const char *context,
|
||||
const char *object_id, const char *object_group,
|
||||
const char *object_group_id, const char *msg,
|
||||
int current_errno, int ret_code);
|
||||
void report_reset_cmdlog_seqnum(void);
|
||||
#define REPORT_OBJECT_CMDLOG_NAME "status"
|
||||
#define REPORT_OBJECT_CMDLOG_SUCCESS "success"
|
||||
#define REPORT_OBJECT_CMDLOG_FAILURE "failure"
|
||||
|
@@ -233,7 +233,7 @@ struct segment_type *init_striped_segtype(struct cmd_context *cmd)
|
||||
|
||||
segtype->ops = &_striped_ops;
|
||||
segtype->name = SEG_TYPE_NAME_STRIPED;
|
||||
segtype->flags =
|
||||
segtype->flags = SEG_STRIPED_TARGET |
|
||||
SEG_CAN_SPLIT | SEG_AREAS_STRIPED | SEG_FORMAT1_SUPPORT;
|
||||
|
||||
log_very_verbose("Initialised segtype: %s", segtype->name);
|
||||
|
2
libdm/.exported_symbols.DM_1_02_133
Normal file
2
libdm/.exported_symbols.DM_1_02_133
Normal file
@@ -0,0 +1,2 @@
|
||||
dm_report_destroy_rows
|
||||
dm_report_group_output_and_pop_all
|
@@ -2907,6 +2907,11 @@ int dm_report_compact_given_fields(struct dm_report *rh, const char *fields);
|
||||
*/
|
||||
int dm_report_is_empty(struct dm_report *rh);
|
||||
|
||||
/*
|
||||
* Destroy report content without doing output.
|
||||
*/
|
||||
void dm_report_destroy_rows(struct dm_report *rh);
|
||||
|
||||
int dm_report_output(struct dm_report *rh);
|
||||
|
||||
/*
|
||||
@@ -2969,6 +2974,7 @@ typedef enum {
|
||||
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data);
|
||||
int dm_report_group_push(struct dm_report_group *group, struct dm_report *report, void *data);
|
||||
int dm_report_group_pop(struct dm_report_group *group);
|
||||
int dm_report_group_output_and_pop_all(struct dm_report_group *group);
|
||||
int dm_report_group_destroy(struct dm_report_group *group);
|
||||
|
||||
/*
|
||||
|
@@ -4674,6 +4674,14 @@ static struct report_group_item *_get_topmost_report_group_item(struct dm_report
|
||||
return item;
|
||||
}
|
||||
|
||||
static void _json_output_start(struct dm_report_group *group)
|
||||
{
|
||||
if (!group->indent) {
|
||||
log_print(JSON_OBJECT_START);
|
||||
group->indent += JSON_INDENT_UNIT;
|
||||
}
|
||||
}
|
||||
|
||||
static int _json_output_array_start(struct dm_pool *mem, struct report_group_item *item)
|
||||
{
|
||||
const char *name = (const char *) item->data;
|
||||
@@ -4713,6 +4721,8 @@ bad:
|
||||
|
||||
static int _prepare_json_report_output(struct dm_report *rh)
|
||||
{
|
||||
_json_output_start(rh->group_item->group);
|
||||
|
||||
if (rh->group_item->output_done && dm_list_empty(&rh->rows))
|
||||
return 1;
|
||||
|
||||
@@ -4790,21 +4800,9 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int _report_group_create_single(struct dm_report_group *group)
|
||||
void dm_report_destroy_rows(struct dm_report *rh)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _report_group_create_basic(struct dm_report_group *group)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _report_group_create_json(struct dm_report_group *group)
|
||||
{
|
||||
log_print(JSON_OBJECT_START);
|
||||
group->indent += JSON_INDENT_UNIT;
|
||||
return 1;
|
||||
_destroy_rows(rh);
|
||||
}
|
||||
|
||||
struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void *data)
|
||||
@@ -4834,23 +4832,6 @@ struct dm_report_group *dm_report_group_create(dm_report_group_type_t type, void
|
||||
|
||||
dm_list_add_h(&group->items, &item->list);
|
||||
|
||||
switch (type) {
|
||||
case DM_REPORT_GROUP_SINGLE:
|
||||
if (!_report_group_create_single(group))
|
||||
goto_bad;
|
||||
break;
|
||||
case DM_REPORT_GROUP_BASIC:
|
||||
if (!_report_group_create_basic(group))
|
||||
goto_bad;
|
||||
break;
|
||||
case DM_REPORT_GROUP_JSON:
|
||||
if (!_report_group_create_json(group))
|
||||
goto_bad;
|
||||
break;
|
||||
default:
|
||||
goto_bad;
|
||||
}
|
||||
|
||||
return group;
|
||||
bad:
|
||||
dm_pool_destroy(mem);
|
||||
@@ -4902,6 +4883,7 @@ static int _report_group_push_json(struct report_group_item *item, const char *n
|
||||
DM_REPORT_OUTPUT_COLUMNS_AS_ROWS);
|
||||
item->report->flags |= DM_REPORT_OUTPUT_BUFFERED;
|
||||
} else {
|
||||
_json_output_start(item->group);
|
||||
if (name) {
|
||||
if (!_json_output_array_start(item->group->mem, item))
|
||||
return_0;
|
||||
@@ -5046,56 +5028,40 @@ int dm_report_group_pop(struct dm_report_group *group)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _report_group_destroy_single(void)
|
||||
int dm_report_group_output_and_pop_all(struct dm_report_group *group)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
struct report_group_item *item, *tmp_item;
|
||||
|
||||
static int _report_group_destroy_basic(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
dm_list_iterate_items_safe(item, tmp_item, &group->items) {
|
||||
if (!item->parent) {
|
||||
item->store.finished_count = 0;
|
||||
continue;
|
||||
}
|
||||
if (item->report && !dm_report_output(item->report))
|
||||
return_0;
|
||||
if (!dm_report_group_pop(group))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (group->type == DM_REPORT_GROUP_JSON) {
|
||||
_json_output_start(group);
|
||||
log_print(JSON_OBJECT_END);
|
||||
group->indent -= JSON_INDENT_UNIT;
|
||||
}
|
||||
|
||||
static int _report_group_destroy_json(void)
|
||||
{
|
||||
log_print(JSON_OBJECT_END);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dm_report_group_destroy(struct dm_report_group *group)
|
||||
{
|
||||
struct report_group_item *item, *tmp_item;
|
||||
int r = 0;
|
||||
int r = 1;
|
||||
|
||||
if (!group)
|
||||
return 1;
|
||||
|
||||
dm_list_iterate_items_safe(item, tmp_item, &group->items) {
|
||||
if (item->report && !dm_report_output(item->report))
|
||||
goto_out;
|
||||
if (!dm_report_group_pop(group))
|
||||
goto_out;
|
||||
}
|
||||
if (!dm_report_group_output_and_pop_all(group))
|
||||
r = 0;
|
||||
|
||||
switch (group->type) {
|
||||
case DM_REPORT_GROUP_SINGLE:
|
||||
if (!_report_group_destroy_single())
|
||||
goto_out;
|
||||
break;
|
||||
case DM_REPORT_GROUP_BASIC:
|
||||
if (!_report_group_destroy_basic())
|
||||
goto_out;
|
||||
break;
|
||||
case DM_REPORT_GROUP_JSON:
|
||||
if (!_report_group_destroy_json())
|
||||
goto_out;
|
||||
break;
|
||||
default:
|
||||
goto_out;
|
||||
}
|
||||
|
||||
r = 1;
|
||||
out:
|
||||
dm_pool_destroy(group->mem);
|
||||
return r;
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ LVMDBUSDMAN = lvmdbusd.8
|
||||
|
||||
MAN5=lvm.conf.5
|
||||
MAN7=lvmsystemid.7
|
||||
MAN8=lvm-config.8 lvm-dumpconfig.8 lvm-lvpoll.8 \
|
||||
MAN8=lvm-config.8 lvm-dumpconfig.8 lvm-fullreport.8 lvm-lvpoll.8 \
|
||||
lvchange.8 lvmconfig.8 lvconvert.8 lvcreate.8 lvdisplay.8 lvextend.8 \
|
||||
lvm.8 lvmchange.8 lvmconf.8 lvmdiskscan.8 lvmdump.8 lvmsadc.8 lvmsar.8 \
|
||||
lvreduce.8 lvremove.8 lvrename.8 lvresize.8 lvs.8 \
|
||||
|
@@ -509,7 +509,7 @@ regions (with the exception of in-flight IO counters).
|
||||
Creates one or more new statistics regions on the specified device(s).
|
||||
|
||||
The region will span the entire device unless \fB\-\-start\fP and
|
||||
\fB\-\-length\fP or \fB\-\-target\fP are given. The \fB\-\-start\fP and
|
||||
\fB\-\-length\fP or \fB\-\-segments\fP are given. The \fB\-\-start\fP an
|
||||
\fB\-\-length\fP options allow a region of arbitrary length to be placed
|
||||
at an arbitrary offset into the device. The \fB\-\-segments\fP option
|
||||
causes a new region to be created for each target in the corresponding
|
||||
@@ -600,6 +600,11 @@ the number of histogram bins and their bounds must match exactly.
|
||||
|
||||
On success the group list and newly created \fBgroup_id\fP are
|
||||
printed to stdout.
|
||||
|
||||
The group metadata is stored with the first (lowest numbered)
|
||||
\fBregion_id\fP in the group: deleting this region will also delete
|
||||
the group and other group members will be returned to their prior
|
||||
state.
|
||||
.
|
||||
.HP
|
||||
.CMD_HELP
|
||||
@@ -672,8 +677,16 @@ each with its own counter set. In this case a summary value for the
|
||||
entire region is also available for use in reports.
|
||||
|
||||
In addition, one or more regions on one device can be combined into
|
||||
a statistics group allowing reporting of aggregate values for all
|
||||
regions and areas making up the group.
|
||||
a statistics group. Groups allow several regions to be aggregated and
|
||||
reported as a single entity; counters for all regions and areas are
|
||||
summed and used to report totals for all group members. Groups also
|
||||
permit the assignment of an optional alias, allowing meaningful names
|
||||
to be associated with sets of regions.
|
||||
|
||||
The group metadata is stored with the first (lowest numbered)
|
||||
\fBregion_id\fP in the group: deleting this region will also delete
|
||||
the group and other group members will be returned to their prior
|
||||
state.
|
||||
|
||||
By default new regions span the entire device. The \fB\-\-start\fP and
|
||||
\fB\-\-length\fP options allows a region of any size to be placed at any
|
||||
|
@@ -25,6 +25,8 @@ lvchange \(em change attributes of a logical volume
|
||||
.IR AllocationPolicy ]
|
||||
.RB [ \-A | \-\-autobackup
|
||||
.RB { y | n }]
|
||||
.RB [ \-\-rebuild
|
||||
.IR PhysicalVolume ]
|
||||
.RB [ \-\-cachemode
|
||||
.RB { passthrough | writeback | writethrough }]
|
||||
.RB [ \-\-cachepolicy
|
||||
@@ -326,6 +328,31 @@ immediately poll a logical volume when it is activated, use
|
||||
\fB\-\-poll n\fP to defer and then \fB\-\-poll y\fP to restart the process.
|
||||
.
|
||||
.HP
|
||||
.BR \-\- [ raid ] rebuild
|
||||
.BR \fIPhysicalVolume
|
||||
.br
|
||||
Option can be repeated multiple times.
|
||||
Selects PhysicalVolume(s) to be rebuild in a RaidLV.
|
||||
Use this option instead of
|
||||
.BR \-\-resync
|
||||
or
|
||||
.BR \-\- [ raid ] syncaction
|
||||
\fBrepair\fP in case the PVs with corrupted data are known and their data
|
||||
should be reconstructed rather than reconstructing default (rotating) data.
|
||||
.br
|
||||
E.g. in a raid1 mirror, the master leg on /dev/sda may hold corrupt data due
|
||||
to a known transient disk error, thus
|
||||
.br
|
||||
\fBlvchange --rebuild /dev/sda LV\fP
|
||||
.br
|
||||
will request the master leg to be rebuild rather than rebuilding
|
||||
all other legs from the master.
|
||||
On a raid5 with rotating data and parity
|
||||
.br
|
||||
\fBlvchange --rebuild /dev/sda LV\fP
|
||||
.br
|
||||
will rebuild all data and parity blocks in the stripe on /dev/sda.
|
||||
.HP
|
||||
.BR \-\- [ raid ] maxrecoveryrate
|
||||
.BR \fIRate [ b | B | s | S | k | K | m | M | g | G ]
|
||||
.br
|
||||
|
@@ -452,6 +452,12 @@ Convert RaidLV to use a different raid level.
|
||||
\[bu]
|
||||
Required options depend on the raid level.
|
||||
|
||||
.B lvconvert \-\-type mirror
|
||||
VG/RaidLV
|
||||
.br
|
||||
\[bu]
|
||||
Convert RaidLV to type mirror.
|
||||
|
||||
.B lvconvert \-\-type striped
|
||||
VG/RaidLV
|
||||
.br
|
||||
@@ -605,6 +611,9 @@ VG/ThinPoolLV
|
||||
Convert the data portion of ThinPoolLV to type cache.
|
||||
.br
|
||||
\[bu]
|
||||
Requires \-\-cachepool to specify the cache pool to use.
|
||||
.br
|
||||
\[bu]
|
||||
Operates on the data sub LV of the thin pool LV.
|
||||
.br
|
||||
\[bu]
|
||||
@@ -799,6 +808,8 @@ Specifies the number mirror images in addition to the original LV image,
|
||||
e.g. \fB\-\-mirrors 1\fP means two copies of the data, the original and
|
||||
one mirror image.
|
||||
|
||||
The current maximum is 9 providing 10 raid1 images.
|
||||
|
||||
This option is required when converting an LV to a \fBraid1\fP or
|
||||
\fBmirror\fP LV.
|
||||
|
||||
|
@@ -381,10 +381,11 @@ would result in a mirror with two-sides; that is,
|
||||
a linear volume plus one copy.
|
||||
|
||||
Specifying the optional argument \fB\-\-nosync\fP will cause the creation
|
||||
of the mirror to skip the initial resynchronization. Any data written
|
||||
afterwards will be mirrored, but the original contents will not be
|
||||
copied. This is useful for skipping a potentially long and resource
|
||||
intensive initial sync of an empty device.
|
||||
of the mirror LV to skip the initial resynchronization. Any data written
|
||||
afterwards will be mirrored, but the original contents will not be copied.
|
||||
|
||||
This is useful for skipping a potentially long and resource intensive initial
|
||||
sync of an empty mirrored RaidLV.
|
||||
|
||||
There are two implementations of mirroring which can be used and correspond
|
||||
to the "\fIraid1\fP" and "\fImirror\fP" segment types.
|
||||
@@ -398,6 +399,9 @@ to configure default mirror segment type.
|
||||
The options
|
||||
\fB\-\-mirrorlog\fP and \fB\-\-corelog\fP apply
|
||||
to the legacy "\fImirror\fP" segment type only.
|
||||
|
||||
Note the current maxima for mirrors are 7 for "mirror" providing
|
||||
8 mirror legs and 9 for "raid1" providing 10 legs.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-mirrorlog
|
||||
@@ -440,7 +444,21 @@ Without this option a default name of "lvol#" will be generated where
|
||||
.HP
|
||||
.BR \-\-nosync
|
||||
.br
|
||||
Causes the creation of the mirror to skip the initial resynchronization.
|
||||
Causes the creation of mirror, raid1, raid4, raid5 and raid10 to skip the
|
||||
initial resynchronization. In case of mirror, raid1 and raid10, any data
|
||||
written afterwards will be mirrored, but the original contents will not be
|
||||
copied. In case of raid4 and raid5, no parity blocks will be written,
|
||||
though any data written afterwards will cause parity blocks to be stored.
|
||||
.br
|
||||
This is useful for skipping a potentially long and resource intensive initial
|
||||
sync of an empty mirror/raid1/raid4/raid5 and raid10 LV.
|
||||
.br
|
||||
This option is not valid for raid6, because raid6 relies on proper parity
|
||||
(P and Q Syndromes) being created during initial synchronization in order
|
||||
to reconstruct proper user date in case of device failures.
|
||||
|
||||
raid0 and raid0_meta don't provide any data copies or parity support
|
||||
and thus don't support initial resynchronization.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-noudevsync
|
||||
@@ -618,15 +636,21 @@ section of \fBlvm.conf (5)\fP or add
|
||||
\fB\-\-config allocation/raid_stripe_all_devices=1\fP
|
||||
.br
|
||||
to the command.
|
||||
.br
|
||||
Note the current limitation of 8 stripes total in any RaidLV including parity devices.
|
||||
|
||||
Note the current maxima for stripes depend on the created RAID type.
|
||||
For raid10, the maximum of stripes is 32,
|
||||
for raid0, it is 64,
|
||||
for raid4/5, it is 63
|
||||
and for raid6 it is 62.
|
||||
|
||||
See the \fB\-\-nosync\fP option to optionally avoid initial syncrhonization of RaidLVs.
|
||||
|
||||
Two implementations of basic striping are available in the kernel.
|
||||
The original device-mapper implementation is the default and should
|
||||
normally be used. The alternative implementation using MD, available
|
||||
since version 1.7 of the RAID device-mapper kernel target (kernel
|
||||
version 4.2) is provided to facilitate the development of new RAID
|
||||
features. It may be accessed with \fB--type raid0\fP, but is best
|
||||
features. It may be accessed with \fB--type raid0[_meta]\fP, but is best
|
||||
avoided at present because of assorted restrictions on resizing and converting
|
||||
such devices.
|
||||
.HP
|
||||
|
145
man/lvm-fullreport.8.in
Normal file
145
man/lvm-fullreport.8.in
Normal file
@@ -0,0 +1,145 @@
|
||||
.TH LVM-FULLREPORT 8 "LVM TOOLS #VERSION#" "Red Hat, Inc" \" -*- nroff -*-
|
||||
.SH NAME
|
||||
lvm fullreport \(em Report information about PVs, PV segments, VGs, LVs and LV segments, all at once for each VG.
|
||||
.SH SYNOPSIS
|
||||
.B lvm fullreport
|
||||
.RB [ \-a | \-\-all ]
|
||||
.RB [ \-\-aligned ]
|
||||
.RB [ \-\-binary ]
|
||||
.RB [ \-\-commandprofile
|
||||
.IR ProfileName ]
|
||||
.RB [[ \-\-configreport
|
||||
.IR ReportName ]
|
||||
.RB [ \-o | \-\-options
|
||||
.RI [ + | \- | # ] Field1 [, Field2 ...]
|
||||
.RB [ \-O | \-\-sort
|
||||
.RI [ + | \- ] Key1 [, Key2 ...]]
|
||||
.RB [ \-S | \-\-select
|
||||
.IR Selection ]
|
||||
.RB ...]
|
||||
.RB [ \-d | \-\-debug ]
|
||||
.RB [ \-h | \-? | \-\-help ]
|
||||
.RB [ \-\-ignorelockingfailure ]
|
||||
.RB [ \-\-ignoreskippedcluster ]
|
||||
.RB [ \-\-logonly ]
|
||||
.RB [ \-\-nameprefixes ]
|
||||
.RB [ \-\-noheadings ]
|
||||
.RB [ \-\-nosuffix ]
|
||||
.RB [ \-P | \-\-partial ]
|
||||
.RB [ \-\-reportformat
|
||||
.RB { basic | json }]
|
||||
.RB [ \-\-rows ]
|
||||
.RB [ \-\-separator
|
||||
.IR Separator ]
|
||||
.RB [ \-\-unbuffered ]
|
||||
.RB [ \-\-units
|
||||
.IR hHbBsSkKmMgGtTpPeE ]
|
||||
.RB [ \-\-unquoted ]
|
||||
.RB [ \-v | \-\-verbose ]
|
||||
.RB [ \-\-version ]
|
||||
.RI [ VolumeGroupName
|
||||
.RI [ VolumeGroupName ...]]
|
||||
.SH DESCRIPTION
|
||||
lvm fullreport produces formatted output about PVs, PV segments, VGs, LVs
|
||||
and LV segments, all at once for each VG and guarded by per-VG lock
|
||||
for consistency.
|
||||
.SH OPTIONS
|
||||
See \fBlvm\fP(8) for common options.
|
||||
.TP
|
||||
.B \-\-all
|
||||
Include information in the output about internal Logical Volumes that
|
||||
are components of normally-accessible Logical Volumes, such as mirrors,
|
||||
but which are not independently accessible (e.g. not mountable).
|
||||
The names of such Logical Volumes are enclosed within square brackets
|
||||
in the output. For example, after creating a mirror using
|
||||
.B lvcreate -m1 \-\-mirrorlog disk
|
||||
, this option will reveal three internal Logical
|
||||
Volumes, with suffixes mimage_0, mimage_1, and mlog.
|
||||
.TP
|
||||
.B \-\-aligned
|
||||
Use with \fB\-\-separator\fP to align the output columns.
|
||||
.TP
|
||||
.B \-\-binary
|
||||
Use binary values "0" or "1" instead of descriptive literal values
|
||||
for columns that have exactly two valid values to report (not counting
|
||||
the "unknown" value which denotes that the value could not be determined).
|
||||
.TP
|
||||
.B \-\-configreport \fI ReportName
|
||||
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
|
||||
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
|
||||
is 'pv' for PV subreport, 'pvseg' for PV segment subreport, 'vg' for
|
||||
VG subreport, 'lv' for LV subreport, 'seg' for LV segment subreport or 'log'
|
||||
for log report. If \fB\-\-configreport\fP option is not used to identify a
|
||||
report, then all command's subreports are assumed except log report. The log
|
||||
report is available only if enabled by \fBlog/report_command_log\fP
|
||||
\fBlvm.conf\fP(5) setting or if \fB\-\-logonly\fP option is used.
|
||||
.TP
|
||||
.B \-\-logonly
|
||||
Suppress the main report itself and display only log report on output.
|
||||
.TP
|
||||
.B \-\-nameprefixes
|
||||
Add an "LVM2_" prefix plus the field name to the output. Useful
|
||||
with \fB\-\-noheadings\fP to produce a list of field=value pairs that can
|
||||
be used to set environment variables (for example, in \fBudev\fP(7) rules).
|
||||
.TP
|
||||
.B \-\-noheadings
|
||||
Suppress the headings line that is normally the first line of output.
|
||||
Useful if grepping the output.
|
||||
.TP
|
||||
.B \-\-nosuffix
|
||||
Suppress the suffix on output sizes. Use with \fB\-\-units\fP
|
||||
(except h and H) if processing the output.
|
||||
.TP
|
||||
.BR \-o ", " \-\-options
|
||||
Comma-separated ordered list of columns.
|
||||
.IP
|
||||
Precede the list with '\fI+\fP' to append to the current list
|
||||
of columns, '\fI-\fP' to remove from the current list of columns
|
||||
or '\fI#\fP' to compact given columns. The \fI\-o\fP option can
|
||||
be repeated, providing several lists. These lists are evaluated
|
||||
from left to right.
|
||||
.IP
|
||||
For the list of columns, see \fBpvs\fP(8), \fBvgs\fP(8),
|
||||
\fBlvs\fP(8) man page or check \fBpvs\fP, \fBvgs\fP, \fBlvs -o help\fP
|
||||
output.
|
||||
.TP
|
||||
.BR \-O ", " \-\-sort
|
||||
Comma-separated ordered list of columns to sort by. Replaces the default
|
||||
selection. Precede any column with '\fI\-\fP' for a reverse sort on that
|
||||
column.
|
||||
.TP
|
||||
.B \-\-rows
|
||||
Output columns as rows.
|
||||
.TP
|
||||
.BR \-S ", " \-\-select " " \fISelection
|
||||
Display only rows that match Selection criteria. All rows are displayed with
|
||||
the additional "selected" column (\fB-o selected\fP) showing 1 if the row
|
||||
matches the Selection and 0 otherwise. The Selection criteria are defined
|
||||
by specifying column names and their valid values (that can include reserved
|
||||
values) while making use of supported comparison operators. See \fBlvm\fP(8)
|
||||
and \fB\-S\fP, \fB\-\-select\fP description for more detailed information
|
||||
about constructing the Selection criteria. As a quick help and to see full
|
||||
list of column names that can be used in Selection including the list of
|
||||
reserved values and the set of supported selection operators, check the
|
||||
output of \fBpvs\fP, \fBvgs\fP, \fBlvs -S help\fP command.
|
||||
.TP
|
||||
.B \-\-separator \fISeparator
|
||||
String to use to separate each column. Useful if grepping the output.
|
||||
.TP
|
||||
.B \-\-unbuffered
|
||||
Produce output immediately without sorting or aligning the columns properly.
|
||||
.TP
|
||||
.B \-\-units \fIhHbBsSkKmMgGtTpPeE
|
||||
All sizes are output in these units: (h)uman-readable, (b)ytes, (s)ectors,
|
||||
(k)ilobytes, (m)egabytes, (g)igabytes, (t)erabytes, (p)etabytes, (e)xabytes.
|
||||
Capitalise to use multiples of 1000 (S.I.) instead of 1024. Can also specify
|
||||
custom units e.g. \-\-units 3M
|
||||
.TP
|
||||
.B \-\-unquoted
|
||||
When used with \fB\-\-nameprefixes\fP, output values in the field=value
|
||||
pairs are not quoted.
|
||||
.SH SEE ALSO
|
||||
.BR lvm (8),
|
||||
.BR pvs (8),
|
||||
.BR vgs (8),
|
||||
.BR lvs (8)
|
13
man/lvm.8.in
13
man/lvm.8.in
@@ -65,6 +65,10 @@ The same as \fBlvmconfig\fP(8) below.
|
||||
.B formats
|
||||
Display recognised metadata formats.
|
||||
.TP
|
||||
.B fullreport
|
||||
Report information about PVs, PV segments, VGs, LVs and LV segments,
|
||||
all at once.
|
||||
.TP
|
||||
.B help
|
||||
Display the help text.
|
||||
.TP
|
||||
@@ -748,6 +752,15 @@ All tools return a status code of zero on success or non-zero on failure.
|
||||
Directory containing \fI.lvm_history\fP if the internal readline
|
||||
shell is invoked.
|
||||
.TP
|
||||
.B LVM_OUT_FD
|
||||
File descriptor to use for common output from LVM commands.
|
||||
.TP
|
||||
.B LVM_ERR_FD
|
||||
File descriptor to use for error output from LVM commands.
|
||||
.TP
|
||||
.B LVM_REPORT_FD
|
||||
File descriptor to use for report output from LVM commands.
|
||||
.TP
|
||||
.B LVM_COMMAND_PROFILE
|
||||
Name of default command profile to use for LVM commands. This profile
|
||||
is overriden by direct use of \fB\-\-commandprofile\fP command line option.
|
||||
|
@@ -19,35 +19,45 @@ lvmetad \(em LVM metadata cache daemon
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
The lvmetad daemon caches LVM metadata, so that LVM commands can read
|
||||
metadata without scanning disks.
|
||||
The lvmetad daemon caches LVM metadata so that LVM commands can read
|
||||
metadata from the cache rather than scanning disks. This can be an
|
||||
advantage because scanning disks is time consuming and may interfere with
|
||||
the normal work of the system. lvmetad can be a disadvantage when disk
|
||||
event notifications from the system are unreliable.
|
||||
|
||||
Metadata caching can be an advantage because scanning disks is time
|
||||
consuming and may interfere with the normal work of the system and disks.
|
||||
lvmetad does not read metadata from disks itself. Instead, it relies on
|
||||
an LVM command, like pvscan \-\-cache, to read metadata from disks and
|
||||
send it to lvmetad to be cached.
|
||||
|
||||
lvmetad does not read metadata from disks itself. The 'pvscan \-\-cache'
|
||||
command scans disks, reads the LVM metadata and sends it to lvmetad.
|
||||
|
||||
New LVM disks that appear on the system must be scanned by pvscan before
|
||||
lvmetad knows about them. If lvmetad does not know about a disk, then LVM
|
||||
New LVM disks that appear on the system must be scanned before lvmetad
|
||||
knows about them. If lvmetad does not know about a disk, then LVM
|
||||
commands using lvmetad will also not know about it. When disks are added
|
||||
or removed from the system, lvmetad must be updated.
|
||||
|
||||
lvmetad is usually combined with event-based system services that
|
||||
automatically run pvscan \-\-cache on new disks. This way, the lvmetad
|
||||
cache is automatically updated with metadata from new disks when they
|
||||
lvmetad is usually combined with event\-based system services that
|
||||
automatically run pvscan \-\-cache on disks added or removed. This way,
|
||||
the cache is automatically updated with metadata from new disks when they
|
||||
appear. LVM udev rules and systemd services implement this automation.
|
||||
Automatic scanning is usually combined with automatic activation. For
|
||||
more information, see
|
||||
.BR pvscan (8).
|
||||
|
||||
If lvmetad is started or restarted after disks have been added to the
|
||||
system, or if the global_filter has changed, the cache must be updated by
|
||||
running 'pvscan \-\-cache'.
|
||||
system, or if the global_filter has changed, the cache must be updated.
|
||||
This can be done by running pvscan \-\-cache, or it will be done
|
||||
automatically by the next LVM command that's run.
|
||||
|
||||
When lvmetad is not used, LVM commands revert to scanning disks for LVM
|
||||
metadata.
|
||||
|
||||
In some cases, lvmetad will be temporarily disabled while it continues
|
||||
running. In this state, LVM commands will ignore the lvmetad cache and
|
||||
revert to scanning disks. A warning will also be printed which includes
|
||||
the reason why lvmetad is not being used. The most common reason is the
|
||||
existence of duplicate PVs (lvmetad cannot cache data for duplicate PVs.)
|
||||
Once duplicates have been resolved, the lvmetad cache is can be updated
|
||||
with pvscan \-\-cache and commands will return to using the cache.
|
||||
|
||||
Use of lvmetad is enabled/disabled by:
|
||||
.br
|
||||
.BR lvm.conf (5)
|
||||
|
@@ -71,7 +71,7 @@ the "unknown" value which denotes that the value could not be determined).
|
||||
.B \-\-configreport \fI ReportName
|
||||
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
|
||||
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
|
||||
is either 'lvs' for command's main report or 'log' for log report.
|
||||
is either 'lv' for command's main report or 'log' for log report.
|
||||
If \fB\-\-configreport\fP option is not used to identify a report, then
|
||||
command's main report is assumed. The log report is available only if
|
||||
enabled by \fBlog/report_command_log\fP \fBlvm.conf\fP(5) setting or
|
||||
|
@@ -60,7 +60,7 @@ the "unknown" value which denotes that the value could not be determined).
|
||||
.B \-\-configreport \fI ReportName
|
||||
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
|
||||
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
|
||||
is either 'pvs' for command's main report or 'log' for log report.
|
||||
is either 'pv' for command's main report or 'log' for log report.
|
||||
If \fB\-\-configreport\fP option is not used to identify a report, then
|
||||
command's main report is assumed. The log report is available only if
|
||||
enabled by \fBlog/report_command_log\fP \fBlvm.conf\fP(5) setting or
|
||||
|
@@ -79,7 +79,7 @@ When given specific device name arguments, pvscan \-\-cache will only
|
||||
read the named devices.
|
||||
|
||||
.IP \[bu] 2
|
||||
LVM udev rules and systemd services are used to intiate automatic device
|
||||
LVM udev rules and systemd services are used to initiate automatic device
|
||||
scanning.
|
||||
|
||||
.IP \[bu] 2
|
||||
@@ -99,8 +99,8 @@ if the global_filter has changed, then all devices must be rescanned
|
||||
for metadata with the command pvscan \-\-cache.
|
||||
|
||||
.IP \[bu] 2
|
||||
lvmetad ignores older metadata formats, e.g. lvm1, and should not be
|
||||
used if they exist.
|
||||
lvmetad does not cache older metadata formats, e.g. lvm1, and will
|
||||
be temporarily disabled if they are seen.
|
||||
|
||||
.IP \[bu] 2
|
||||
To notify lvmetad about a device that is no longer present, the major and
|
||||
|
@@ -58,7 +58,7 @@ the "unknown" value which denotes that the value could not be determined).
|
||||
.B \-\-configreport \fI ReportName
|
||||
Make any subsequent \fB\-o, \-\-options\fP, \fB\-O, \-\-sort\fP or
|
||||
\fB\-S, \-\-select\fP to apply for \fIReportName\fP where \fIReportName\fP
|
||||
is either 'vgs' for command's main report or 'log' for log report.
|
||||
is either 'vg' for command's main report or 'log' for log report.
|
||||
If \fB\-\-configreport\fP option is not used to identify a report, then
|
||||
command's main report is assumed. The log report is available only if
|
||||
enabled by \fBlog/report_command_log\fP \fBlvm.conf\fP(5) setting or
|
||||
|
1245
scripts/command-lines.in
Normal file
1245
scripts/command-lines.in
Normal file
File diff suppressed because it is too large
Load Diff
1712
scripts/create-commands.c
Normal file
1712
scripts/create-commands.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -115,6 +115,7 @@ fi
|
||||
%{_mandir}/man8/lvmconfig.8.gz
|
||||
%{_mandir}/man8/lvmdiskscan.8.gz
|
||||
%{_mandir}/man8/lvmdump.8.gz
|
||||
%{_mandir}/man8/lvm-fullreport.8.gz
|
||||
%{_mandir}/man8/lvmsadc.8.gz
|
||||
%{_mandir}/man8/lvmsar.8.gz
|
||||
%{_mandir}/man8/lvreduce.8.gz
|
||||
@@ -179,6 +180,7 @@ fi
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/thin-performance.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/cache-mq.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/cache-smq.profile
|
||||
%config(noreplace) %verify(not md5 mtime size) %{_sysconfdir}/lvm/profile/lvmdbusd.profile
|
||||
%dir %{_sysconfdir}/lvm/backup
|
||||
%dir %{_sysconfdir}/lvm/cache
|
||||
%dir %{_sysconfdir}/lvm/archive
|
||||
|
@@ -1265,6 +1265,12 @@ wait_for_sync() {
|
||||
return 1
|
||||
}
|
||||
|
||||
# aux check_status_chars $vg $lv "Aaaaa"
|
||||
check_status_chars() {
|
||||
[ `dmsetup status $1-$2|awk '{print $6}'` = $3 ] && return
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if tests are running on 64bit architecture
|
||||
can_use_16T() {
|
||||
test "$(getconf LONG_BIT)" -eq 64
|
||||
|
@@ -97,7 +97,15 @@ test_lvconvert() {
|
||||
alloc="--alloc anywhere"
|
||||
fi
|
||||
|
||||
lvconvert --type mirror -m $finish_count --mirrorlog $finish_log_type \
|
||||
# --mirrorlog is invalid with -m0
|
||||
if [ "$finish_count" -eq 0 ]; then
|
||||
mirrorlog=""
|
||||
finish_log_type=""
|
||||
else
|
||||
mirrorlog="--mirrorlog"
|
||||
fi
|
||||
|
||||
lvconvert --type mirror -m $finish_count $mirrorlog $finish_log_type \
|
||||
$vg/$lv1 $alloc
|
||||
|
||||
test $active || lvchange -aey $vg/$lv1
|
||||
|
126
test/shell/lvconvert-raid-takeover.sh
Normal file
126
test/shell/lvconvert-raid-takeover.sh
Normal file
@@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
SKIP_WITH_LVMLOCKD=1
|
||||
SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
aux have_raid 1 9 0 || skip
|
||||
|
||||
aux prepare_vg 9 288
|
||||
|
||||
# Delay 1st leg so that rebuilding status characters
|
||||
# can be read before resync finished too quick.
|
||||
# aux delay_dev "$dev1" 0 1
|
||||
|
||||
# Create 3-way mirror
|
||||
lvcreate --yes --type mirror -m 2 -L 256M -n $lv1 $vg
|
||||
check lv_field $vg/$lv1 segtype "mirror"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert 3-way to 4-way mirror
|
||||
lvconvert -m 3 $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "mirror"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Takeover 4-way mirror to raid1
|
||||
lvconvert --yes --type raid1 $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid1"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
## Convert 4-way raid1 to 5-way
|
||||
lvconvert -m 4 $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid1"
|
||||
check lv_field $vg/$lv1 stripes 5
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# FIXME: enable once lvconvert rejects early
|
||||
## Try converting 4-way raid1 to 9-way
|
||||
#not lvconvert --yes -m 8 $vg/$lv1
|
||||
#check lv_field $vg/$lv1 segtype "raid1"
|
||||
#check lv_field $vg/$lv1 stripes 4
|
||||
|
||||
# Convert 5-way raid1 to 2-way
|
||||
lvconvert --yes -m 1 $vg/$lv1
|
||||
lvs $vg/$lv1
|
||||
dmsetup status $vg-$lv1
|
||||
dmsetup table $vg-$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid1"
|
||||
check lv_field $vg/$lv1 stripes 2
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert 2-way raid1 to mirror
|
||||
lvconvert --yes --type mirror $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "mirror"
|
||||
check lv_field $vg/$lv1 stripes 2
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
|
||||
# Clean up
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# Create 3-way raid0
|
||||
lvcreate -y --type raid0 -i 3 -L 256M -n $lv1 $vg
|
||||
check lv_field $vg/$lv1 segtype "raid0"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
echo y | mkfs -t ext4 /dev/mapper/$vg-$lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0 -> raid4
|
||||
lvconvert -y --ty raid4 $vg/$lv1
|
||||
lvchange --refresh $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid4"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid4 -> raid0_meta
|
||||
lvconvert -y --ty raid0_meta $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid0_meta"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0_meta -> raid4
|
||||
lvconvert -y --ty raid4 $vg/$lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid4"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid4 -> raid0
|
||||
lvconvert -y --ty raid0 $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid0"
|
||||
check lv_field $vg/$lv1 stripes 3
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
# Convert raid0 -> raid4
|
||||
lvconvert -y --ty raid4 $vg/$lv1
|
||||
lvchange --refresh $vg/$lv1
|
||||
check lv_field $vg/$lv1 segtype "raid4"
|
||||
check lv_field $vg/$lv1 stripes 4
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck -fn /dev/mapper/$vg-$lv1
|
||||
|
||||
vgremove -ff $vg
|
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2012,2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -21,13 +21,13 @@ aux can_use_16T || skip
|
||||
|
||||
aux have_raid 1 3 0 || skip
|
||||
|
||||
aux prepare_vg 5
|
||||
aux prepare_vg 5 32
|
||||
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv1 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv2 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv3 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv4 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
|
||||
# Fake 5 PiB volume group $vg1 via snapshot LVs
|
||||
for device in "$lv1" "$lv2" "$lv3" "$lv4" "$lv5"
|
||||
do
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $device $vg --virtualsize 1P
|
||||
done
|
||||
|
||||
#FIXME this should be 1024T
|
||||
#check lv_field $vg/$lv size "128.00m"
|
||||
@@ -35,43 +35,79 @@ lvcreate --type snapshot -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
|
||||
aux extend_filter_LVMTEST
|
||||
|
||||
pvcreate "$DM_DEV_DIR"/$vg/$lv[12345]
|
||||
vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv[12345]
|
||||
vgcreate -s 2M $vg1 "$DM_DEV_DIR"/$vg/$lv[12345]
|
||||
|
||||
# Delay PVs so that resynchronization doesn't fill
|
||||
# the snapshots before removal of the RaidLV
|
||||
for device in "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
|
||||
do
|
||||
aux delay_dev "$device" 0 1
|
||||
done
|
||||
|
||||
# bz837927 START
|
||||
|
||||
#
|
||||
# Create large RAID LVs
|
||||
#
|
||||
# We need '--nosync' or our virtual devices won't work
|
||||
|
||||
# 200 TiB raid1
|
||||
lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
|
||||
check lv_field $vg1/$lv1 size "200.00t"
|
||||
aux check_status_chars $vg1 $lv1 "AA"
|
||||
lvremove -ff $vg1
|
||||
|
||||
for segtype in raid4 raid5 raid6; do
|
||||
# 1 PiB raid1
|
||||
lvcreate --type raid1 -m 1 -L 1P -n $lv1 $vg1 --nosync
|
||||
check lv_field $vg1/$lv1 size "1.00p"
|
||||
aux check_status_chars $vg1 $lv1 "AA"
|
||||
lvremove -ff $vg1
|
||||
|
||||
# 750 TiB raid4/5
|
||||
for segtype in raid4 raid5; do
|
||||
lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
|
||||
check lv_field $vg1/$lv1 size "750.00t"
|
||||
aux check_status_chars $vg1 $lv1 "AAAA"
|
||||
lvremove -ff $vg1
|
||||
done
|
||||
|
||||
#
|
||||
# Convert large linear to RAID1 (belong in different test script?)
|
||||
#
|
||||
lvcreate -aey -L 200T -n $lv1 $vg1
|
||||
# Need to deactivate or the up-convert will start sync'ing
|
||||
lvchange -an $vg1/$lv1
|
||||
lvconvert --type raid1 -m 1 $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "200.00t"
|
||||
# 750 TiB raid6 (with --nosync rejection check)
|
||||
[ aux have_raid 1 9 0 ] && not lvcreate --type raid6 -i 3 -L 750T -n $lv1 $vg1 --nosync
|
||||
lvcreate --type raid6 -i 3 -L 750T -n $lv1 $vg1
|
||||
check lv_field $vg1/$lv1 size "750.00t"
|
||||
aux check_status_chars $vg1 $lv1 "aaaaa"
|
||||
lvremove -ff $vg1
|
||||
|
||||
# 1 PiB raid6 (with --nosync rejection check), then extend up to 2 PiB
|
||||
[ aux have_raid 1 9 0 ] && not lvcreate --type raid6 -i 3 -L -L 1P -n $lv1 $vg1 --nosync
|
||||
lvcreate --type raid6 -i 3 -L 1P -n $lv1 $vg1
|
||||
check lv_field $vg1/$lv1 size "1.00p"
|
||||
aux check_status_chars $vg1 $lv1 "aaaaa"
|
||||
lvextend -L +1P $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "2.00p"
|
||||
aux check_status_chars $vg1 $lv1 "aaaaa"
|
||||
lvremove -ff $vg1
|
||||
|
||||
#
|
||||
# Extending large RAID LV (belong in different script?)
|
||||
# Convert large 200 TiB linear to RAID1 (belong in different test script?)
|
||||
#
|
||||
lvcreate -aey -L 200T -n $lv1 $vg1
|
||||
lvconvert --type raid1 -m 1 $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "200.00t"
|
||||
aux check_status_chars $vg1 $lv1 "aa"
|
||||
lvremove -ff $vg1
|
||||
|
||||
#
|
||||
# Extending large 200 TiB RAID LV to 400 TiB (belong in different script?)
|
||||
#
|
||||
lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
|
||||
check lv_field $vg1/$lv1 size "200.00t"
|
||||
aux check_status_chars $vg1 $lv1 "AA"
|
||||
lvextend -L +200T $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "400.00t"
|
||||
aux check_status_chars $vg1 $lv1 "AA"
|
||||
lvremove -ff $vg1
|
||||
|
||||
# bz837927 END
|
||||
|
||||
vgremove -ff $vg1
|
||||
vgremove -ff $vg
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2012,2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
@@ -22,24 +22,31 @@ aux have_raid 1 3 0 || skip
|
||||
|
||||
aux prepare_vg 5
|
||||
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv1 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv2 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv3 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv4 $vg --virtualsize 256T
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $lv5 $vg --virtualsize 256T
|
||||
# Fake ~2.5PiB volume group $vg1 via snapshot LVs
|
||||
for device in "$lv1" "$lv2" "$lv3" "$lv4" "$lv5"
|
||||
do
|
||||
lvcreate --type snapshot -s -l 20%FREE -n $device $vg --virtualsize 520T
|
||||
done
|
||||
|
||||
aux extend_filter_LVMTEST
|
||||
|
||||
pvcreate "$DM_DEV_DIR"/$vg/$lv[12345]
|
||||
vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv[12345]
|
||||
|
||||
|
||||
#
|
||||
# Create large RAID LVs
|
||||
# Create and extend large RAID10 LV
|
||||
#
|
||||
# We need '--nosync' or our virtual devices won't work
|
||||
|
||||
lvcreate --type raid10 -m 1 -i 2 -L 200T -n $lv1 $vg1 --nosync
|
||||
check lv_field $vg1/$lv1 size "200.00t"
|
||||
vgremove -ff $vg1
|
||||
lvextend -L +200T $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "400.00t"
|
||||
lvextend -L +100T $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "500.00t"
|
||||
lvextend -L 1P $vg1/$lv1
|
||||
check lv_field $vg1/$lv1 size "1.00p"
|
||||
|
||||
vgremove -ff $vg1
|
||||
vgremove -ff $vg
|
||||
|
85
test/shell/lvcreate-raid-nosync.sh
Normal file
85
test/shell/lvcreate-raid-nosync.sh
Normal file
@@ -0,0 +1,85 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2016 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# This copyrighted material is made available to anyone wishing to use,
|
||||
# modify, copy, or redistribute it subject to the terms and conditions
|
||||
# of the GNU General Public License v.2.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
SKIP_WITH_LVMLOCKD=1
|
||||
SKIP_WITH_LVMPOLLD=1
|
||||
|
||||
. lib/inittest
|
||||
|
||||
aux have_raid 1 7 0 || skip
|
||||
|
||||
aux prepare_vg 6
|
||||
|
||||
|
||||
# Delay 1st leg so that rebuilding status characters
|
||||
# can be read before resync finished too quick.
|
||||
aux delay_dev "$dev1" 0 1
|
||||
|
||||
# raid0/raid0_meta don't support resynchronization
|
||||
for r in raid0 raid0_meta
|
||||
do
|
||||
lvcreate --yes --type raid0 -i 3 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "AAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
done
|
||||
|
||||
# raid1 supports resynchronization
|
||||
lvcreate --yes --type raid1 -m 2 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "aaa"
|
||||
aux wait_for_sync $vg $lv1
|
||||
aux check_status_chars $vg $lv1 "AAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# raid1 supports --nosync
|
||||
lvcreate --yes --type raid1 --nosync -m 2 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "AAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
for r in raid4 raid5
|
||||
do
|
||||
# raid4/5 support resynchronization
|
||||
lvcreate --yes --type $r -i 3 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "aaaa"
|
||||
aux wait_for_sync $vg $lv1
|
||||
aux check_status_chars $vg $lv1 "AAAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# raid4/5 support --nosync
|
||||
lvcreate --yes --type $r --nosync -i 3 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "AAAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
done
|
||||
|
||||
# raid6 supports resynchronization
|
||||
lvcreate --yes --type raid6 -i 3 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "aaaaa"
|
||||
aux wait_for_sync $vg $lv1
|
||||
aux check_status_chars $vg $lv1 "AAAAA"
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# raid6 rejects --nosync; it has to initialize P- and Q-Syndromes
|
||||
not lvcreate --yes --type raid6 --nosync -i 3 -l 1 -n $lv1 $vg
|
||||
|
||||
# raid10 supports resynchronization
|
||||
lvcreate --yes --type raid10 -m 1 -i 3 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "aaaaaa"
|
||||
aux wait_for_sync $vg $lv1
|
||||
aux check_status_chars $vg $lv1 "AAAAAA"
|
||||
aux wait_for_sync $vg $lv1
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
# raid10 supports --nosync
|
||||
lvcreate --yes --type raid10 --nosync -m 1 -i 3 -l 1 -n $lv1 $vg
|
||||
aux check_status_chars $vg $lv1 "AAAAAA"
|
||||
aux wait_for_sync $vg $lv1
|
||||
lvremove --yes $vg/$lv1
|
||||
|
||||
vgremove -ff $vg
|
@@ -53,6 +53,15 @@ lvcreate -l 4 --type raid10 -i 2 -m 1 -n $lv1 $vg \
|
||||
check lv_tree_on $vg ${lv1}_foo "$dev1"
|
||||
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
aux mkdev_md5sum $vg $lv1
|
||||
|
||||
# Check collocation of SubLVs is prohibited
|
||||
not pvmove $mode -n ${lv1}_rimage_0 "$dev1" "$dev2"
|
||||
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
not pvmove $mode -n ${lv1}_rimage_1 "$dev2" "$dev1"
|
||||
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
not pvmove $mode -n ${lv1}_rmeta_0 "$dev1" "$dev3"
|
||||
check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
|
||||
|
||||
pvmove $mode "$dev1" "$dev5"
|
||||
check lv_tree_on $vg ${lv1}_foo "$dev5"
|
||||
check lv_tree_on $vg $lv1 "$dev2" "$dev3" "$dev4" "$dev5"
|
||||
|
403
tools/args.h
403
tools/args.h
@@ -17,213 +17,214 @@
|
||||
* Put all long args that don't have a corresponding short option first.
|
||||
*/
|
||||
/* *INDENT-OFF* */
|
||||
arg(abort_ARG, '\0', "abort", NULL, 0, 0)
|
||||
arg(activationmode_ARG, '\0', "activationmode", string_arg, 0, 0)
|
||||
arg(addtag_ARG, '\0', "addtag", tag_arg, ARG_GROUPABLE, 0)
|
||||
arg(aligned_ARG, '\0', "aligned", NULL, 0, 0)
|
||||
arg(alloc_ARG, '\0', "alloc", alloc_arg, 0, 0)
|
||||
arg(atomic_ARG, '\0', "atomic", NULL, 0, 0)
|
||||
arg(atversion_ARG, '\0', "atversion", string_arg, 0, 0)
|
||||
arg(binary_ARG, '\0', "binary", NULL, 0, 0)
|
||||
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", size_mb_arg, 0, 0)
|
||||
arg(cache_long_ARG, '\0', "cache", NULL, 0, 0)
|
||||
arg(cachemode_ARG, '\0', "cachemode", cachemode_arg, 0, 0)
|
||||
arg(cachepool_ARG, '\0', "cachepool", string_arg, 0, 0)
|
||||
arg(commandprofile_ARG, '\0', "commandprofile", string_arg, 0, 0)
|
||||
arg(config_ARG, '\0', "config", string_arg, 0, 0)
|
||||
arg(configreport_ARG, '\0', "configreport", string_arg, ARG_GROUPABLE, 1)
|
||||
arg(configtype_ARG, '\0', "type", string_arg, 0, 0)
|
||||
arg(corelog_ARG, '\0', "corelog", NULL, 0, 0)
|
||||
arg(dataalignment_ARG, '\0', "dataalignment", size_kb_arg, 0, 0)
|
||||
arg(dataalignmentoffset_ARG, '\0', "dataalignmentoffset", size_kb_arg, 0, 0)
|
||||
arg(deltag_ARG, '\0', "deltag", tag_arg, ARG_GROUPABLE, 0)
|
||||
arg(detachprofile_ARG, '\0', "detachprofile", NULL, 0, 0)
|
||||
arg(discards_ARG, '\0', "discards", discards_arg, 0, 0)
|
||||
arg(driverloaded_ARG, '\0', "driverloaded", yes_no_arg, 0, 0)
|
||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", yes_no_arg, 0, 0)
|
||||
arg(force_long_ARG, '\0', "force", NULL, ARG_COUNTABLE, 0)
|
||||
arg(foreign_ARG, '\0', "foreign", NULL, 0, 0)
|
||||
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", NULL, 0, 0)
|
||||
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", NULL, 0, 0)
|
||||
arg(ignorelocal_ARG, '\0', "ignorelocal", NULL, 0, 0)
|
||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", NULL, 0, 0)
|
||||
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", NULL, 0, 0)
|
||||
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", NULL, 0, 0)
|
||||
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", NULL, 0, 0)
|
||||
arg(labelsector_ARG, '\0', "labelsector", int_arg, 0, 0)
|
||||
arg(lockopt_ARG, '\0', "lockopt", string_arg, 0, 0)
|
||||
arg(lockstart_ARG, '\0', "lockstart", NULL, 0, 0)
|
||||
arg(lockstop_ARG, '\0', "lockstop", NULL, 0, 0)
|
||||
arg(locktype_ARG, '\0', "locktype", locktype_arg, 0, 0)
|
||||
arg(logonly_ARG, '\0', "logonly", NULL, 0, 0)
|
||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(merge_ARG, '\0', "merge", NULL, 0, 0)
|
||||
arg(mergedconfig_ARG, '\0', "mergedconfig", NULL, 0, 0)
|
||||
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_arg, 0, 0)
|
||||
arg(metadataignore_ARG, '\0', "metadataignore", yes_no_arg, 0, 0)
|
||||
arg(metadataprofile_ARG, '\0', "metadataprofile", string_arg, 0, 0)
|
||||
arg(metadatasize_ARG, '\0', "metadatasize", size_mb_arg, 0, 0)
|
||||
arg(minor_ARG, '\0', "minor", int_arg, ARG_GROUPABLE, 0)
|
||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_arg, 0, 0)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", NULL, 0, 0)
|
||||
arg(mknodes_ARG, '\0', "mknodes", NULL, 0, 0)
|
||||
arg(monitor_ARG, '\0', "monitor", yes_no_arg, 0, 0)
|
||||
arg(nameprefixes_ARG, '\0', "nameprefixes", NULL, 0, 0)
|
||||
arg(noheadings_ARG, '\0', "noheadings", NULL, 0, 0)
|
||||
arg(nohistory_ARG, '\0', "nohistory", NULL, 0, 0)
|
||||
arg(nolocking_ARG, '\0', "nolocking", NULL, 0, 0)
|
||||
arg(norestorefile_ARG, '\0', "norestorefile", NULL, 0, 0)
|
||||
arg(nosuffix_ARG, '\0', "nosuffix", NULL, 0, 0)
|
||||
arg(nosync_ARG, '\0', "nosync", NULL, 0, 0)
|
||||
arg(notifydbus_ARG, '\0', "notifydbus", NULL, 0, 0)
|
||||
arg(noudevsync_ARG, '\0', "noudevsync", NULL, 0, 0)
|
||||
arg(originname_ARG, '\0', "originname", string_arg, 0, 0)
|
||||
arg(physicalvolumesize_ARG, '\0', "setphysicalvolumesize", size_mb_arg, 0, 0)
|
||||
arg(poll_ARG, '\0', "poll", yes_no_arg, 0, 0)
|
||||
arg(polloperation_ARG, '\0', "polloperation", string_arg, 0, 0)
|
||||
arg(pooldatasize_ARG, '\0', "pooldatasize", size_mb_arg, 0, 0)
|
||||
arg(poolmetadata_ARG, '\0', "poolmetadata", string_arg, 0, 0)
|
||||
arg(poolmetadatasize_ARG, '\0', "poolmetadatasize", size_mb_arg, 0, 0)
|
||||
arg(poolmetadataspare_ARG, '\0', "poolmetadataspare", yes_no_arg, 0, 0)
|
||||
arg(profile_ARG, '\0', "profile", string_arg, 0, 0)
|
||||
arg(pvmetadatacopies_ARG, '\0', "pvmetadatacopies", int_arg, 0, 0)
|
||||
arg(raidmaxrecoveryrate_ARG, '\0', "raidmaxrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(raidminrecoveryrate_ARG, '\0', "raidminrecoveryrate", size_kb_arg, 0, 0)
|
||||
arg(raidsyncaction_ARG, '\0', "raidsyncaction", string_arg, 0, 0)
|
||||
arg(raidwritebehind_ARG, '\0', "raidwritebehind", int_arg, 0, 0)
|
||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(readonly_ARG, '\0', "readonly", NULL, 0, 0)
|
||||
arg(refresh_ARG, '\0', "refresh", NULL, 0, 0)
|
||||
arg(removemissing_ARG, '\0', "removemissing", NULL, 0, 0)
|
||||
arg(repair_ARG, '\0', "repair", NULL, 0, 0)
|
||||
arg(replace_ARG, '\0', "replace", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(reportformat_ARG, '\0', "reportformat", string_arg, 0, 0)
|
||||
arg(restorefile_ARG, '\0', "restorefile", string_arg, 0, 0)
|
||||
arg(restoremissing_ARG, '\0', "restoremissing", NULL, 0, 0)
|
||||
arg(resync_ARG, '\0', "resync", NULL, 0, 0)
|
||||
arg(rows_ARG, '\0', "rows", NULL, 0, 0)
|
||||
arg(segments_ARG, '\0', "segments", NULL, 0, 0)
|
||||
arg(separator_ARG, '\0', "separator", string_arg, 0, 0)
|
||||
arg(shared_ARG, '\0', "shared", NULL, 0, 0)
|
||||
arg(sinceversion_ARG, '\0', "sinceversion", string_arg, 0, 0)
|
||||
arg(split_ARG, '\0', "split", NULL, 0, 0)
|
||||
arg(splitcache_ARG, '\0', "splitcache", NULL, 0, 0)
|
||||
arg(splitmirrors_ARG, '\0', "splitmirrors", int_arg, 0, 0)
|
||||
arg(splitsnapshot_ARG, '\0', "splitsnapshot", NULL, 0, 0)
|
||||
arg(showdeprecated_ARG, '\0', "showdeprecated", NULL, 0, 0)
|
||||
arg(showunsupported_ARG, '\0', "showunsupported", NULL, 0, 0)
|
||||
arg(stripes_long_ARG, '\0', "stripes", int_arg, 0, 0)
|
||||
arg(syncaction_ARG, '\0', "syncaction", string_arg, 0, 0) /* FIXME Use custom validation fn */
|
||||
arg(sysinit_ARG, '\0', "sysinit", NULL, 0, 0)
|
||||
arg(systemid_ARG, '\0', "systemid", string_arg, 0, 0)
|
||||
arg(thinpool_ARG, '\0', "thinpool", string_arg, 0, 0)
|
||||
arg(trackchanges_ARG, '\0', "trackchanges", NULL, 0, 0)
|
||||
arg(trustcache_ARG, '\0', "trustcache", NULL, 0, 0)
|
||||
arg(type_ARG, '\0', "type", segtype_arg, 0, 0)
|
||||
arg(unbuffered_ARG, '\0', "unbuffered", NULL, 0, 0)
|
||||
arg(uncache_ARG, '\0', "uncache", NULL, 0, 0)
|
||||
arg(cachepolicy_ARG, '\0', "cachepolicy", string_arg, 0, 0)
|
||||
arg(cachesettings_ARG, '\0', "cachesettings", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(unconfigured_ARG, '\0', "unconfigured", NULL, 0, 0)
|
||||
arg(units_ARG, '\0', "units", string_arg, 0, 0)
|
||||
arg(unquoted_ARG, '\0', "unquoted", NULL, 0, 0)
|
||||
arg(usepolicies_ARG, '\0', "usepolicies", NULL, 0, 0)
|
||||
arg(validate_ARG, '\0', "validate", NULL, 0, 0)
|
||||
arg(version_ARG, '\0', "version", NULL, 0, 0)
|
||||
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_arg, 0, 0)
|
||||
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", size_mb_arg, 0, 0)
|
||||
arg(withsummary_ARG, '\0', "withsummary", NULL, 0, 0)
|
||||
arg(withcomments_ARG, '\0', "withcomments", NULL, 0, 0)
|
||||
arg(withspaces_ARG, '\0', "withspaces", NULL, 0, 0)
|
||||
arg(withversions_ARG, '\0', "withversions", NULL, 0, 0)
|
||||
arg(writebehind_ARG, '\0', "writebehind", int_arg, 0, 0)
|
||||
arg(writemostly_ARG, '\0', "writemostly", string_arg, ARG_GROUPABLE, 0)
|
||||
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)
|
||||
arg(aligned_ARG, '\0', "aligned", 0, 0, 0)
|
||||
arg(alloc_ARG, '\0', "alloc", alloc_VAL, 0, 0)
|
||||
arg(atomic_ARG, '\0', "atomic", 0, 0, 0)
|
||||
arg(atversion_ARG, '\0', "atversion", string_VAL, 0, 0)
|
||||
arg(binary_ARG, '\0', "binary", 0, 0, 0)
|
||||
arg(bootloaderareasize_ARG, '\0', "bootloaderareasize", sizemb_VAL, 0, 0)
|
||||
arg(cache_long_ARG, '\0', "cache", 0, 0, 0)
|
||||
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(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)
|
||||
arg(deltag_ARG, '\0', "deltag", tag_VAL, ARG_GROUPABLE, 0)
|
||||
arg(detachprofile_ARG, '\0', "detachprofile", 0, 0, 0)
|
||||
arg(discards_ARG, '\0', "discards", discards_VAL, 0, 0)
|
||||
arg(driverloaded_ARG, '\0', "driverloaded", bool_VAL, 0, 0)
|
||||
arg(errorwhenfull_ARG, '\0', "errorwhenfull", bool_VAL, 0, 0)
|
||||
arg(force_long_ARG, '\0', "force", 0, ARG_COUNTABLE, 0)
|
||||
arg(foreign_ARG, '\0', "foreign", 0, 0, 0)
|
||||
arg(handlemissingpvs_ARG, '\0', "handlemissingpvs", 0, 0, 0)
|
||||
arg(ignoreadvanced_ARG, '\0', "ignoreadvanced", 0, 0, 0)
|
||||
arg(ignorelocal_ARG, '\0', "ignorelocal", 0, 0, 0)
|
||||
arg(ignorelockingfailure_ARG, '\0', "ignorelockingfailure", 0, 0, 0)
|
||||
arg(ignoremonitoring_ARG, '\0', "ignoremonitoring", 0, 0, 0)
|
||||
arg(ignoreskippedcluster_ARG, '\0', "ignoreskippedcluster", 0, 0, 0)
|
||||
arg(ignoreunsupported_ARG, '\0', "ignoreunsupported", 0, 0, 0)
|
||||
arg(labelsector_ARG, '\0', "labelsector", number_VAL, 0, 0)
|
||||
arg(lockopt_ARG, '\0', "lockopt", string_VAL, 0, 0)
|
||||
arg(lockstart_ARG, '\0', "lockstart", 0, 0, 0)
|
||||
arg(lockstop_ARG, '\0', "lockstop", 0, 0, 0)
|
||||
arg(locktype_ARG, '\0', "locktype", locktype_VAL, 0, 0)
|
||||
arg(logonly_ARG, '\0', "logonly", 0, 0, 0)
|
||||
arg(maxrecoveryrate_ARG, '\0', "maxrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(merge_ARG, '\0', "merge", 0, 0, 0)
|
||||
arg(mergedconfig_ARG, '\0', "mergedconfig", 0, 0, 0)
|
||||
arg(metadatacopies_ARG, '\0', "metadatacopies", metadatacopies_VAL, 0, 0)
|
||||
arg(metadataignore_ARG, '\0', "metadataignore", bool_VAL, 0, 0)
|
||||
arg(metadataprofile_ARG, '\0', "metadataprofile", string_VAL, 0, 0)
|
||||
arg(metadatasize_ARG, '\0', "metadatasize", sizemb_VAL, 0, 0)
|
||||
arg(minor_ARG, '\0', "minor", number_VAL, ARG_GROUPABLE, 0)
|
||||
arg(minrecoveryrate_ARG, '\0', "minrecoveryrate", sizekb_VAL, 0, 0)
|
||||
arg(mirrorlog_ARG, '\0', "mirrorlog", mirrorlog_VAL, 0, 0)
|
||||
arg(mirrorsonly_ARG, '\0', "mirrorsonly", 0, 0, 0)
|
||||
arg(mknodes_ARG, '\0', "mknodes", 0, 0, 0)
|
||||
arg(monitor_ARG, '\0', "monitor", bool_VAL, 0, 0)
|
||||
arg(nameprefixes_ARG, '\0', "nameprefixes", 0, 0, 0)
|
||||
arg(noheadings_ARG, '\0', "noheadings", 0, 0, 0)
|
||||
arg(nohistory_ARG, '\0', "nohistory", 0, 0, 0)
|
||||
arg(nolocking_ARG, '\0', "nolocking", 0, 0, 0)
|
||||
arg(norestorefile_ARG, '\0', "norestorefile", 0, 0, 0)
|
||||
arg(nosuffix_ARG, '\0', "nosuffix", 0, 0, 0)
|
||||
arg(nosync_ARG, '\0', "nosync", 0, 0, 0)
|
||||
arg(notifydbus_ARG, '\0', "notifydbus", 0, 0, 0)
|
||||
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(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", number_VAL, 0, 0)
|
||||
arg(raidrebuild_ARG, '\0', "raidrebuild", string_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(raidwritebehind_ARG, '\0', "raidwritebehind", number_VAL, 0, 0)
|
||||
arg(raidwritemostly_ARG, '\0', "raidwritemostly", string_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(restorefile_ARG, '\0', "restorefile", string_VAL, 0, 0)
|
||||
arg(restoremissing_ARG, '\0', "restoremissing", 0, 0, 0)
|
||||
arg(resync_ARG, '\0', "resync", 0, 0, 0)
|
||||
arg(rows_ARG, '\0', "rows", 0, 0, 0)
|
||||
arg(segments_ARG, '\0', "segments", 0, 0, 0)
|
||||
arg(separator_ARG, '\0', "separator", string_VAL, 0, 0)
|
||||
arg(shared_ARG, '\0', "shared", 0, 0, 0)
|
||||
arg(sinceversion_ARG, '\0', "sinceversion", string_VAL, 0, 0)
|
||||
arg(split_ARG, '\0', "split", 0, 0, 0)
|
||||
arg(splitcache_ARG, '\0', "splitcache", 0, 0, 0)
|
||||
arg(splitmirrors_ARG, '\0', "splitmirrors", number_VAL, 0, 0)
|
||||
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(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)
|
||||
arg(trackchanges_ARG, '\0', "trackchanges", 0, 0, 0)
|
||||
arg(trustcache_ARG, '\0', "trustcache", 0, 0, 0)
|
||||
arg(type_ARG, '\0', "type", segtype_VAL, 0, 0)
|
||||
arg(unbuffered_ARG, '\0', "unbuffered", 0, 0, 0)
|
||||
arg(uncache_ARG, '\0', "uncache", 0, 0, 0)
|
||||
arg(cachepolicy_ARG, '\0', "cachepolicy", string_VAL, 0, 0)
|
||||
arg(cachesettings_ARG, '\0', "cachesettings", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(unconfigured_ARG, '\0', "unconfigured", 0, 0, 0)
|
||||
arg(units_ARG, '\0', "units", units_VAL, 0, 0)
|
||||
arg(unquoted_ARG, '\0', "unquoted", 0, 0, 0)
|
||||
arg(usepolicies_ARG, '\0', "usepolicies", 0, 0, 0)
|
||||
arg(validate_ARG, '\0', "validate", 0, 0, 0)
|
||||
arg(version_ARG, '\0', "version", 0, 0, 0)
|
||||
arg(vgmetadatacopies_ARG, '\0', "vgmetadatacopies", metadatacopies_VAL, 0, 0)
|
||||
arg(virtualoriginsize_ARG, '\0', "virtualoriginsize", sizemb_VAL, 0, 0)
|
||||
arg(withsummary_ARG, '\0', "withsummary", 0, 0, 0)
|
||||
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)
|
||||
|
||||
/* Allow some variations */
|
||||
arg(allocation_ARG, '\0', "allocation", yes_no_arg, 0, 0)
|
||||
arg(available_ARG, '\0', "available", activation_arg, 0, 0)
|
||||
arg(resizable_ARG, '\0', "resizable", yes_no_arg, 0, 0)
|
||||
arg(allocation_ARG, '\0', "allocation", bool_VAL, 0, 0)
|
||||
arg(available_ARG, '\0', "available", activation_VAL, 0, 0)
|
||||
arg(resizable_ARG, '\0', "resizable", bool_VAL, 0, 0)
|
||||
|
||||
/*
|
||||
* ... and now the short args.
|
||||
*/
|
||||
arg(activate_ARG, 'a', "activate", activation_arg, 0, 0)
|
||||
arg(all_ARG, 'a', "all", NULL, 0, 0)
|
||||
arg(autobackup_ARG, 'A', "autobackup", yes_no_arg, 0, 0)
|
||||
arg(activevolumegroups_ARG, 'A', "activevolumegroups", NULL, 0, 0)
|
||||
arg(background_ARG, 'b', "background", NULL, 0, 0)
|
||||
arg(backgroundfork_ARG, 'b', "background", NULL, 0, 0)
|
||||
arg(basevgname_ARG, 'n', "basevgname", string_arg, 0, 0)
|
||||
arg(blockdevice_ARG, 'b', "blockdevice", NULL, 0, 0)
|
||||
arg(chunksize_ARG, 'c', "chunksize", size_kb_arg, 0, 0)
|
||||
arg(clustered_ARG, 'c', "clustered", yes_no_arg, 0, 0)
|
||||
arg(colon_ARG, 'c', "colon", NULL, 0, 0)
|
||||
arg(columns_ARG, 'C', "columns", NULL, 0, 0)
|
||||
arg(contiguous_ARG, 'C', "contiguous", yes_no_arg, 0, 0)
|
||||
arg(debug_ARG, 'd', "debug", NULL, ARG_COUNTABLE, 0)
|
||||
arg(exported_ARG, 'e', "exported", NULL, 0, 0)
|
||||
arg(physicalextent_ARG, 'E', "physicalextent", NULL, 0, 0)
|
||||
arg(file_ARG, 'f', "file", string_arg, 0, 0)
|
||||
arg(force_ARG, 'f', "force", NULL, ARG_COUNTABLE, 0)
|
||||
arg(full_ARG, 'f', "full", NULL, 0, 0)
|
||||
arg(help_ARG, 'h', "help", NULL, 0, 0)
|
||||
arg(cache_ARG, 'H', "cache", NULL, 0, 0)
|
||||
arg(history_ARG, 'H', "history", NULL, 0, 0)
|
||||
arg(help2_ARG, '?', "", NULL, 0, 0)
|
||||
arg(import_ARG, 'i', "import", NULL, 0, 0)
|
||||
arg(interval_ARG, 'i', "interval", int_arg, 0, 0)
|
||||
arg(iop_version_ARG, 'i', "iop_version", NULL, 0, 0)
|
||||
arg(stripes_ARG, 'i', "stripes", int_arg, 0, 0)
|
||||
arg(stripesize_ARG, 'I', "stripesize", size_kb_arg, 0, 0)
|
||||
arg(logicalvolume_ARG, 'l', "logicalvolume", int_arg, 0, 0)
|
||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", int_arg, 0, 0)
|
||||
arg(extents_ARG, 'l', "extents", int_arg_with_sign_and_percent, 0, 0)
|
||||
arg(list_ARG, 'l', "list", NULL, 0, 0)
|
||||
arg(lvmpartition_ARG, 'l', "lvmpartition", NULL, 0, 0)
|
||||
arg(logicalextent_ARG, 'L', "logicalextent", int_arg_with_sign, 0, 0)
|
||||
arg(size_ARG, 'L', "size", size_mb_arg, 0, 0)
|
||||
arg(persistent_ARG, 'M', "persistent", yes_no_arg, 0, 0)
|
||||
arg(major_ARG, 'j', "major", int_arg, ARG_GROUPABLE, 0)
|
||||
arg(setactivationskip_ARG, 'k', "setactivationskip", yes_no_arg, 0, 0)
|
||||
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", NULL, 0, 0)
|
||||
arg(maps_ARG, 'm', "maps", NULL, 0, 0)
|
||||
arg(mirrors_ARG, 'm', "mirrors", int_arg_with_sign, 0, 0)
|
||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_arg, 0, 0)
|
||||
arg(name_ARG, 'n', "name", string_arg, 0, 0)
|
||||
arg(nofsck_ARG, 'n', "nofsck", NULL, 0, 0)
|
||||
arg(novolumegroup_ARG, 'n', "novolumegroup", NULL, 0, 0)
|
||||
arg(oldpath_ARG, 'n', "oldpath", NULL, 0, 0)
|
||||
arg(options_ARG, 'o', "options", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(sort_ARG, 'O', "sort", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", int_arg, 0, 0)
|
||||
arg(permission_ARG, 'p', "permission", permission_arg, 0, 0)
|
||||
arg(partial_ARG, 'P', "partial", NULL, 0, 0)
|
||||
arg(physicalvolume_ARG, 'P', "physicalvolume", NULL, 0, 0)
|
||||
arg(quiet_ARG, 'q', "quiet", NULL, ARG_COUNTABLE, 0)
|
||||
arg(readahead_ARG, 'r', "readahead", readahead_arg, 0, 0)
|
||||
arg(resizefs_ARG, 'r', "resizefs", NULL, 0, 0)
|
||||
arg(reset_ARG, 'R', "reset", NULL, 0, 0)
|
||||
arg(regionsize_ARG, 'R', "regionsize", size_mb_arg, 0, 0)
|
||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0, 0)
|
||||
arg(snapshot_ARG, 's', "snapshot", NULL, 0, 0)
|
||||
arg(short_ARG, 's', "short", NULL, 0, 0)
|
||||
arg(stdin_ARG, 's', "stdin", NULL, 0, 0)
|
||||
arg(select_ARG, 'S', "select", string_arg, ARG_GROUPABLE, 0)
|
||||
arg(test_ARG, 't', "test", NULL, 0, 0)
|
||||
arg(thin_ARG, 'T', "thin", NULL, 0, 0)
|
||||
arg(uuid_ARG, 'u', "uuid", NULL, 0, 0)
|
||||
arg(uuidstr_ARG, 'u', "uuid", string_arg, 0, 0)
|
||||
arg(uuidlist_ARG, 'U', "uuidlist", NULL, 0, 0)
|
||||
arg(verbose_ARG, 'v', "verbose", NULL, ARG_COUNTABLE, 0)
|
||||
arg(volumegroup_ARG, 'V', "volumegroup", NULL, 0, 0)
|
||||
arg(virtualsize_ARG, 'V', "virtualsize", size_mb_arg, 0, 0)
|
||||
arg(wipesignatures_ARG, 'W', "wipesignatures", yes_no_arg, 0, 0)
|
||||
arg(allocatable_ARG, 'x', "allocatable", yes_no_arg, 0, 0)
|
||||
arg(resizeable_ARG, 'x', "resizeable", yes_no_arg, 0, 0)
|
||||
arg(yes_ARG, 'y', "yes", NULL, 0, 0)
|
||||
arg(zero_ARG, 'Z', "zero", yes_no_arg, 0, 0)
|
||||
arg(activate_ARG, 'a', "activate", activation_VAL, 0, 0)
|
||||
arg(all_ARG, 'a', "all", 0, 0, 0)
|
||||
arg(autobackup_ARG, 'A', "autobackup", bool_VAL, 0, 0)
|
||||
arg(activevolumegroups_ARG, 'A', "activevolumegroups", 0, 0, 0)
|
||||
arg(background_ARG, 'b', "background", 0, 0, 0)
|
||||
arg(backgroundfork_ARG, 'b', "background", 0, 0, 0)
|
||||
arg(basevgname_ARG, 'n', "basevgname", string_VAL, 0, 0)
|
||||
arg(blockdevice_ARG, 'b', "blockdevice", 0, 0, 0)
|
||||
arg(chunksize_ARG, 'c', "chunksize", sizekb_VAL, 0, 0)
|
||||
arg(clustered_ARG, 'c', "clustered", bool_VAL, 0, 0)
|
||||
arg(colon_ARG, 'c', "colon", 0, 0, 0)
|
||||
arg(columns_ARG, 'C', "columns", 0, 0, 0)
|
||||
arg(contiguous_ARG, 'C', "contiguous", bool_VAL, 0, 0)
|
||||
arg(debug_ARG, 'd', "debug", 0, ARG_COUNTABLE, 0)
|
||||
arg(exported_ARG, 'e', "exported", 0, 0, 0)
|
||||
arg(physicalextent_ARG, 'E', "physicalextent", 0, 0, 0)
|
||||
arg(file_ARG, 'f', "file", string_VAL, 0, 0)
|
||||
arg(force_ARG, 'f', "force", 0, ARG_COUNTABLE, 0)
|
||||
arg(full_ARG, 'f', "full", 0, 0, 0)
|
||||
arg(help_ARG, 'h', "help", 0, ARG_COUNTABLE, 0)
|
||||
arg(cache_ARG, 'H', "cache", 0, 0, 0)
|
||||
arg(history_ARG, 'H', "history", 0, 0, 0)
|
||||
arg(help2_ARG, '?', "", 0, 0, 0)
|
||||
arg(import_ARG, 'i', "import", 0, 0, 0)
|
||||
arg(interval_ARG, 'i', "interval", number_VAL, 0, 0)
|
||||
arg(iop_version_ARG, 'i', "iop_version", 0, 0, 0)
|
||||
arg(stripes_ARG, 'i', "stripes", number_VAL, 0, 0)
|
||||
arg(stripesize_ARG, 'I', "stripesize", sizekb_VAL, 0, 0)
|
||||
arg(logicalvolume_ARG, 'l', "logicalvolume", number_VAL, 0, 0)
|
||||
arg(maxlogicalvolumes_ARG, 'l', "maxlogicalvolumes", number_VAL, 0, 0)
|
||||
arg(extents_ARG, 'l', "extents", numsignedper_VAL, 0, 0)
|
||||
arg(list_ARG, 'l', "list", 0, 0, 0)
|
||||
arg(lvmpartition_ARG, 'l', "lvmpartition", 0, 0, 0)
|
||||
arg(size_ARG, 'L', "size", sizemb_VAL, 0, 0)
|
||||
arg(persistent_ARG, 'M', "persistent", bool_VAL, 0, 0)
|
||||
arg(major_ARG, 'j', "major", number_VAL, ARG_GROUPABLE, 0)
|
||||
arg(setactivationskip_ARG, 'k', "setactivationskip", bool_VAL, 0, 0)
|
||||
arg(ignoreactivationskip_ARG, 'K', "ignoreactivationskip", 0, 0, 0)
|
||||
arg(maps_ARG, 'm', "maps", 0, 0, 0)
|
||||
arg(mirrors_ARG, 'm', "mirrors", numsigned_VAL, 0, 0)
|
||||
arg(metadatatype_ARG, 'M', "metadatatype", metadatatype_VAL, 0, 0)
|
||||
arg(name_ARG, 'n', "name", string_VAL, 0, 0)
|
||||
arg(nofsck_ARG, 'n', "nofsck", 0, 0, 0)
|
||||
arg(novolumegroup_ARG, 'n', "novolumegroup", 0, 0, 0)
|
||||
arg(oldpath_ARG, 'n', "oldpath", 0, 0, 0)
|
||||
arg(options_ARG, 'o', "options", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(sort_ARG, 'O', "sort", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(maxphysicalvolumes_ARG, 'p', "maxphysicalvolumes", number_VAL, 0, 0)
|
||||
arg(permission_ARG, 'p', "permission", permission_VAL, 0, 0)
|
||||
arg(partial_ARG, 'P', "partial", 0, 0, 0)
|
||||
arg(physicalvolume_ARG, 'P', "physicalvolume", 0, 0, 0)
|
||||
arg(quiet_ARG, 'q', "quiet", 0, ARG_COUNTABLE, 0)
|
||||
arg(readahead_ARG, 'r', "readahead", readahead_VAL, 0, 0)
|
||||
arg(resizefs_ARG, 'r', "resizefs", 0, 0, 0)
|
||||
arg(reset_ARG, 'R', "reset", 0, 0, 0)
|
||||
arg(regionsize_ARG, 'R', "regionsize", sizemb_VAL, 0, 0)
|
||||
arg(physicalextentsize_ARG, 's', "physicalextentsize", sizemb_VAL, 0, 0)
|
||||
arg(snapshot_ARG, 's', "snapshot", 0, 0, 0)
|
||||
arg(short_ARG, 's', "short", 0, 0, 0)
|
||||
arg(stdin_ARG, 's', "stdin", 0, 0, 0)
|
||||
arg(select_ARG, 'S', "select", string_VAL, ARG_GROUPABLE, 0)
|
||||
arg(test_ARG, 't', "test", 0, 0, 0)
|
||||
arg(thin_ARG, 'T', "thin", 0, 0, 0)
|
||||
arg(uuid_ARG, 'u', "uuid", 0, 0, 0)
|
||||
arg(uuidstr_ARG, 'u', "uuid", string_VAL, 0, 0)
|
||||
arg(uuidlist_ARG, 'U', "uuidlist", 0, 0, 0)
|
||||
arg(verbose_ARG, 'v', "verbose", 0, ARG_COUNTABLE, 0)
|
||||
arg(volumegroup_ARG, 'V', "volumegroup", 0, 0, 0)
|
||||
arg(virtualsize_ARG, 'V', "virtualsize", sizemb_VAL, 0, 0)
|
||||
arg(wipesignatures_ARG, 'W', "wipesignatures", bool_VAL, 0, 0)
|
||||
arg(allocatable_ARG, 'x', "allocatable", bool_VAL, 0, 0)
|
||||
arg(resizeable_ARG, 'x', "resizeable", bool_VAL, 0, 0)
|
||||
arg(yes_ARG, 'y', "yes", 0, 0, 0)
|
||||
arg(zero_ARG, 'Z', "zero", bool_VAL, 0, 0)
|
||||
|
||||
/* this should always be last */
|
||||
arg(ARG_COUNT, '-', "", NULL, 0, 0)
|
||||
arg(ARG_COUNT, '-', "", 0, 0, 0)
|
||||
/* *INDENT-ON* */
|
||||
|
3
tools/command-lines-count.h
Normal file
3
tools/command-lines-count.h
Normal file
@@ -0,0 +1,3 @@
|
||||
/* Do not edit. This file is generated by scripts/create-commands */
|
||||
/* using command definitions from scripts/command-lines.in */
|
||||
#define COMMAND_COUNT 146
|
8409
tools/command-lines.h
Normal file
8409
tools/command-lines.h
Normal file
File diff suppressed because it is too large
Load Diff
169
tools/command.h
Normal file
169
tools/command.h
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
* Copyright (C) 2004-2015 Red Hat, Inc. All rights reserved.
|
||||
*
|
||||
* This file is part of LVM2.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use,
|
||||
* modify, copy, or redistribute it subject to the terms and conditions
|
||||
* of the GNU Lesser General Public License v.2.1.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _LVM_COMMAND_H
|
||||
#define _LVM_COMMAND_H
|
||||
|
||||
struct cmd_context;
|
||||
|
||||
/* old per-command-name function */
|
||||
typedef int (*command_fn) (struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
/* new per-command-line-id functions */
|
||||
typedef int (*command_line_fn) (struct cmd_context *cmd, int argc, char **argv);
|
||||
|
||||
struct command_function {
|
||||
int command_line_enum;
|
||||
command_line_fn fn;
|
||||
};
|
||||
|
||||
struct command_name {
|
||||
const char *name;
|
||||
const char *desc; /* general command description from commands.h */
|
||||
unsigned int flags;
|
||||
|
||||
/* union of {required,optional}_opt_args for all commands with this name */
|
||||
int valid_args[ARG_COUNT];
|
||||
int num_args;
|
||||
};
|
||||
|
||||
/*
|
||||
* Command defintion
|
||||
*
|
||||
* A command is defined in terms of a command name,
|
||||
* required options (+args), optional options (+args),
|
||||
* required positional args, optional positional args.
|
||||
*
|
||||
* A positional arg always has non-zero pos_arg.def.types.
|
||||
* The first positional arg has pos_arg.pos of 1.
|
||||
*/
|
||||
|
||||
/* arg_def flags */
|
||||
#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;
|
||||
}
|
||||
|
||||
static inline uint64_t val_enum_to_bit(int val_enum)
|
||||
{
|
||||
return 1 << val_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 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_ */
|
||||
};
|
||||
|
||||
/* Description of an option and the value that follows it. */
|
||||
|
||||
struct opt_arg {
|
||||
int opt; /* option, e.g. foo_ARG */
|
||||
struct arg_def def; /* defines accepted values */
|
||||
};
|
||||
|
||||
/* Description of a position and the value that exists there. */
|
||||
|
||||
struct pos_arg {
|
||||
int pos; /* position, e.g. first is 1 */
|
||||
struct arg_def def; /* defines accepted values */
|
||||
};
|
||||
|
||||
/*
|
||||
* CMD_RO_ARGS needs to accomodate a list of options,
|
||||
* of which one is required after which the rest are
|
||||
* optional.
|
||||
*/
|
||||
#define CMD_RO_ARGS 64 /* required opt args */
|
||||
#define CMD_OO_ARGS 150 /* optional opt args */
|
||||
#define CMD_RP_ARGS 8 /* required positional args */
|
||||
#define CMD_OP_ARGS 8 /* optional positional args */
|
||||
|
||||
/*
|
||||
* one or more from required_opt_args is required,
|
||||
* then the rest are optional.
|
||||
*/
|
||||
#define CMD_FLAG_ONE_REQUIRED_OPT 1
|
||||
|
||||
/* a register of the lvm commands */
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *desc; /* specific command description from command-lines.h */
|
||||
const char *usage; /* excludes common options like --help, --debug */
|
||||
const char *usage_common; /* includes commmon options like --help, --debug */
|
||||
const char *command_line_id;
|
||||
int command_line_enum; /* <command_line_id>_CMD */
|
||||
|
||||
struct command_name *cname;
|
||||
|
||||
command_fn fn; /* old style */
|
||||
struct command_function *functions; /* new style */
|
||||
|
||||
unsigned int flags; /* copied from command_name.flags from commands.h */
|
||||
|
||||
unsigned int cmd_flags; /* CMD_FLAG_ */
|
||||
|
||||
/* definitions of opt/pos args */
|
||||
|
||||
/* required args following an --opt */
|
||||
struct opt_arg required_opt_args[CMD_RO_ARGS];
|
||||
|
||||
/* optional args following an --opt */
|
||||
struct opt_arg optional_opt_args[CMD_OO_ARGS];
|
||||
|
||||
/* required positional args */
|
||||
struct pos_arg required_pos_args[CMD_RP_ARGS];
|
||||
|
||||
/* optional positional args */
|
||||
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
||||
|
||||
int ro_count;
|
||||
int oo_count;
|
||||
int rp_count;
|
||||
int op_count;
|
||||
|
||||
/* used for processing current position */
|
||||
int pos_count;
|
||||
};
|
||||
|
||||
#endif
|
1426
tools/commands.h
1426
tools/commands.h
File diff suppressed because it is too large
Load Diff
@@ -750,6 +750,60 @@ static int _lvchange_tag(struct cmd_context *cmd, struct logical_volume *lv, int
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _lvchange_rebuild(struct logical_volume *lv)
|
||||
{
|
||||
int pv_count, i = 0;
|
||||
char **rebuild_pvs;
|
||||
const char *tmp_str;
|
||||
struct dm_list *rebuild_pvh = NULL;
|
||||
struct arg_value_group_list *group;
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
struct lv_segment *raid_seg = first_seg(lv);
|
||||
|
||||
if (!seg_is_raid(raid_seg) || seg_is_any_raid0(raid_seg)) {
|
||||
log_error("--rebuild can only be used with 'raid4/5/6/10' segment types.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(pv_count = arg_count(cmd, rebuild_ARG))) {
|
||||
log_error("No --rebuild found!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!arg_is_set(cmd, yes_ARG) &&
|
||||
yes_no_prompt("Do you really want to rebuild %u PVs "
|
||||
"of logical volume %s [y/n]: ",
|
||||
pv_count, display_lvname(lv)) == 'n') {
|
||||
log_error("Logical volume %s not rebuild.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* rebuild can be specified more than once */
|
||||
if (!(rebuild_pvs = dm_pool_alloc(vg->vgmem, sizeof(char *) * pv_count)))
|
||||
return_0;
|
||||
|
||||
dm_list_iterate_items(group, &cmd->arg_value_groups) {
|
||||
if (!grouped_arg_is_set(group->arg_values, rebuild_ARG))
|
||||
continue;
|
||||
|
||||
if (!(tmp_str = grouped_arg_str_value(group->arg_values,
|
||||
rebuild_ARG, NULL)))
|
||||
return_0;
|
||||
|
||||
if (!(rebuild_pvs[i++] = dm_pool_strdup(cmd->mem, tmp_str)))
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!(rebuild_pvh = create_pv_list(cmd->mem, vg,
|
||||
pv_count, rebuild_pvs, 0)))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
/* Rebuild PVs listed on @rebuild_pvh */
|
||||
return lv_raid_rebuild(lv, rebuild_pvh);
|
||||
}
|
||||
|
||||
static int _lvchange_writemostly(struct logical_volume *lv)
|
||||
{
|
||||
int s, pv_count, i = 0;
|
||||
@@ -1132,6 +1186,14 @@ static int _lvchange_single(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
docmds++;
|
||||
}
|
||||
|
||||
/* rebuild selected PVs */
|
||||
if (arg_is_set(cmd, rebuild_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
return_ECMD_FAILED;
|
||||
doit += _lvchange_rebuild(lv);
|
||||
docmds++;
|
||||
}
|
||||
|
||||
/* change writemostly/writebehind */
|
||||
if (arg_is_set(cmd, writemostly_ARG) || arg_is_set(cmd, writebehind_ARG)) {
|
||||
if (!archive(lv->vg))
|
||||
@@ -1245,6 +1307,7 @@ int lvchange(struct cmd_context *cmd, int argc, char **argv)
|
||||
errorwhenfull_ARG,
|
||||
maxrecoveryrate_ARG,
|
||||
minrecoveryrate_ARG,
|
||||
rebuild_ARG,
|
||||
resync_ARG,
|
||||
syncaction_ARG,
|
||||
writebehind_ARG,
|
||||
|
@@ -38,12 +38,10 @@
|
||||
*/
|
||||
|
||||
struct lvconvert_params {
|
||||
/* Exactly one of these options is chosen */
|
||||
/* Exactly one of these 12 command categories is determined */
|
||||
int merge; /* Either merge_snapshot or merge_mirror is also set */
|
||||
int cache;
|
||||
int corelog;
|
||||
int mirrorlog;
|
||||
int mirrors_supplied; /* When type_str is not set, this may be set with keep_mimages for --splitmirrors */
|
||||
int keep_mimages; /* --splitmirrors */
|
||||
int repair;
|
||||
int replace;
|
||||
int snapshot;
|
||||
@@ -52,9 +50,16 @@ struct lvconvert_params {
|
||||
int splitsnapshot;
|
||||
int thin;
|
||||
int uncache;
|
||||
const char *type_str; /* When this is set, mirrors_supplied may optionally also be set */
|
||||
int other_conversion; /* Everything else */
|
||||
|
||||
const struct segment_type *segtype;
|
||||
int corelog; /* Equivalent to --mirrorlog core */
|
||||
int mirrorlog; /* Only one of corelog and mirrorlog may be set */
|
||||
|
||||
int mirrors_supplied; /* When type_str is not set, this may be set with keep_mimages for --splitmirrors */
|
||||
const char *type_str; /* When this is set, mirrors_supplied may optionally also be set */
|
||||
/* Holds what you asked for based on --type or other arguments, else "" */
|
||||
|
||||
const struct segment_type *segtype; /* Holds what segment type you will get */
|
||||
|
||||
int merge_snapshot; /* merge is also set */
|
||||
int merge_mirror; /* merge is also set */
|
||||
@@ -79,9 +84,9 @@ struct lvconvert_params {
|
||||
|
||||
uint32_t mirrors;
|
||||
sign_t mirrors_sign;
|
||||
uint32_t keep_mimages; /* --splitmirrors */
|
||||
uint32_t stripes;
|
||||
uint32_t stripe_size;
|
||||
uint32_t stripe_size_supplied;
|
||||
uint32_t read_ahead;
|
||||
cache_mode_t cache_mode; /* cache */
|
||||
const char *policy_name; /* cache */
|
||||
@@ -154,9 +159,9 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
|
||||
}
|
||||
|
||||
if (!strstr((*pargv)[0], "_rimage_")) { /* Snapshot */
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)))
|
||||
return_0;
|
||||
lp->type_str = SEG_TYPE_NAME_SNAPSHOT;
|
||||
lp->merge_snapshot = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -273,52 +278,22 @@ static int _lvconvert_name_params(struct lvconvert_params *lp,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _check_conversion_type(struct cmd_context *cmd, const char *type_str)
|
||||
{
|
||||
if (!type_str || !*type_str)
|
||||
return 1;
|
||||
|
||||
if (!strcmp(type_str, "mirror")) {
|
||||
if (!arg_is_set(cmd, mirrors_ARG)) {
|
||||
log_error("Conversions to --type mirror require -m/--mirrors");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: Check thin-pool and thin more thoroughly! */
|
||||
if (!strcmp(type_str, "snapshot") || !strcmp(type_str, "linear") ||
|
||||
!strcmp(type_str, "striped") ||
|
||||
!strncmp(type_str, "raid", 4) ||
|
||||
!strcmp(type_str, "cache-pool") || !strcmp(type_str, "cache") ||
|
||||
!strcmp(type_str, "thin-pool") || !strcmp(type_str, "thin"))
|
||||
return 1;
|
||||
|
||||
log_error("Conversion using --type %s is not supported.", type_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -s/--snapshot and --type snapshot are synonyms */
|
||||
static int _snapshot_type_requested(struct cmd_context *cmd, const char *type_str)
|
||||
{
|
||||
return (arg_is_set(cmd, snapshot_ARG) || !strcmp(type_str, "snapshot"));
|
||||
return (arg_is_set(cmd, snapshot_ARG) || !strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT));
|
||||
}
|
||||
|
||||
static int _raid0_type_requested(struct cmd_context *cmd, const char *type_str)
|
||||
static int _raid0_type_requested(const char *type_str)
|
||||
{
|
||||
return (!strcmp(type_str, "raid0") || !strcmp(type_str, "raid0_meta"));
|
||||
return (!strcmp(type_str, SEG_TYPE_NAME_RAID0) || !strcmp(type_str, SEG_TYPE_NAME_RAID0_META));
|
||||
}
|
||||
|
||||
/* mirror/raid* (1,10,4,5,6 and their variants) reshape */
|
||||
static int _mirror_or_raid_type_requested(struct cmd_context *cmd, const char *type_str)
|
||||
{
|
||||
return (arg_is_set(cmd, mirrors_ARG) || !strcmp(type_str, "mirror") ||
|
||||
(!strncmp(type_str, "raid", 4) && !_raid0_type_requested(cmd, type_str)));
|
||||
}
|
||||
|
||||
static int _striped_type_requested(struct cmd_context *cmd, const char *type_str)
|
||||
{
|
||||
return (!strcmp(type_str, SEG_TYPE_NAME_STRIPED) || !strcmp(type_str, SEG_TYPE_NAME_LINEAR));
|
||||
return (arg_is_set(cmd, mirrors_ARG) || !strcmp(type_str, SEG_TYPE_NAME_MIRROR) ||
|
||||
(!strncmp(type_str, SEG_TYPE_NAME_RAID, 4) && !_raid0_type_requested(type_str)));
|
||||
}
|
||||
|
||||
static int _linear_type_requested(const char *type_str)
|
||||
@@ -326,35 +301,57 @@ static int _linear_type_requested(const char *type_str)
|
||||
return (!strcmp(type_str, SEG_TYPE_NAME_LINEAR));
|
||||
}
|
||||
|
||||
static int _striped_type_requested(const char *type_str)
|
||||
{
|
||||
return (!strcmp(type_str, SEG_TYPE_NAME_STRIPED) || _linear_type_requested(type_str));
|
||||
}
|
||||
|
||||
static int _check_conversion_type(struct cmd_context *cmd, const char *type_str)
|
||||
{
|
||||
if (!type_str || !*type_str)
|
||||
return 1;
|
||||
|
||||
/* FIXME: Check thin-pool and thin more thoroughly! */
|
||||
if (!strcmp(type_str, SEG_TYPE_NAME_SNAPSHOT) || _striped_type_requested(type_str) ||
|
||||
!strncmp(type_str, SEG_TYPE_NAME_RAID, 4) || !strcmp(type_str, SEG_TYPE_NAME_MIRROR) ||
|
||||
!strcmp(type_str, SEG_TYPE_NAME_CACHE_POOL) || !strcmp(type_str, SEG_TYPE_NAME_CACHE) ||
|
||||
!strcmp(type_str, SEG_TYPE_NAME_THIN_POOL) || !strcmp(type_str, SEG_TYPE_NAME_THIN))
|
||||
return 1;
|
||||
|
||||
log_error("Conversion using --type %s is not supported.", type_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _read_pool_params(struct cmd_context *cmd, int *pargc, char ***pargv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
int cachepool = 0;
|
||||
int thinpool = 0;
|
||||
struct segment_type *segtype;
|
||||
|
||||
if ((lp->pool_data_name = arg_str_value(cmd, cachepool_ARG, NULL))) {
|
||||
if (lp->type_str[0] &&
|
||||
strcmp(lp->type_str, "cache") &&
|
||||
strcmp(lp->type_str, "cache-pool")) {
|
||||
strcmp(lp->type_str, SEG_TYPE_NAME_CACHE) &&
|
||||
strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL)) {
|
||||
log_error("--cachepool argument is only valid with "
|
||||
"the cache or cache-pool segment type.");
|
||||
return 0;
|
||||
}
|
||||
cachepool = 1;
|
||||
lp->type_str = "cache-pool";
|
||||
} else if (!strcmp(lp->type_str, "cache-pool"))
|
||||
lp->type_str = SEG_TYPE_NAME_CACHE_POOL;
|
||||
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL))
|
||||
cachepool = 1;
|
||||
else if ((lp->pool_data_name = arg_str_value(cmd, thinpool_ARG, NULL))) {
|
||||
if (lp->type_str[0] &&
|
||||
strcmp(lp->type_str, "thin") &&
|
||||
strcmp(lp->type_str, "thin-pool")) {
|
||||
strcmp(lp->type_str, SEG_TYPE_NAME_THIN) &&
|
||||
strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL)) {
|
||||
log_error("--thinpool argument is only valid with "
|
||||
"the thin or thin-pool segment type.");
|
||||
return 0;
|
||||
}
|
||||
thinpool = 1;
|
||||
lp->type_str = "thin-pool";
|
||||
} else if (!strcmp(lp->type_str, "thin-pool"))
|
||||
lp->type_str = SEG_TYPE_NAME_THIN_POOL;
|
||||
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL))
|
||||
thinpool = 1;
|
||||
|
||||
if (lp->cache && !cachepool) {
|
||||
@@ -388,10 +385,10 @@ static int _read_pool_params(struct cmd_context *cmd, int *pargc, char ***pargv,
|
||||
splitmirrors_ARG, splitsnapshot_ARG, -1))
|
||||
return_0;
|
||||
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
|
||||
if (!(segtype = get_segtype_from_string(cmd, lp->type_str)))
|
||||
return_0;
|
||||
|
||||
if (!get_pool_params(cmd, lp->segtype, &lp->passed_args,
|
||||
if (!get_pool_params(cmd, segtype, &lp->passed_args,
|
||||
&lp->pool_metadata_size,
|
||||
&lp->poolmetadataspare,
|
||||
&lp->chunk_size, &lp->discards,
|
||||
@@ -440,7 +437,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
|
||||
lp->type_str = arg_str_value(cmd, type_ARG, "");
|
||||
|
||||
if (arg_is_set(cmd, type_ARG) && !_check_conversion_type(cmd, lp->type_str))
|
||||
if (*lp->type_str && !_check_conversion_type(cmd, lp->type_str))
|
||||
return_0;
|
||||
|
||||
/* If --repair, check for incompatible args. */
|
||||
@@ -448,7 +445,6 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
if (arg_outside_list_is_set(cmd, "cannot be used with --repair",
|
||||
repair_ARG,
|
||||
alloc_ARG, usepolicies_ARG,
|
||||
stripes_long_ARG, stripesize_ARG,
|
||||
force_ARG, noudevsync_ARG, test_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
@@ -505,30 +501,29 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
if (arg_is_set(cmd, cache_ARG))
|
||||
lp->cache = 1;
|
||||
|
||||
if (!strcmp(lp->type_str, "cache"))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE))
|
||||
lp->cache = 1;
|
||||
else if (lp->cache) {
|
||||
if (lp->type_str[0]) {
|
||||
log_error("--cache is incompatible with --type %s", lp->type_str);
|
||||
return 0;
|
||||
}
|
||||
lp->type_str = "cache";
|
||||
lp->type_str = SEG_TYPE_NAME_CACHE;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, thin_ARG))
|
||||
lp->thin = 1;
|
||||
|
||||
if (!strcmp(lp->type_str, "thin"))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN))
|
||||
lp->thin = 1;
|
||||
else if (lp->thin) {
|
||||
if (lp->type_str[0]) {
|
||||
log_error("--thin is incompatible with --type %s", lp->type_str);
|
||||
return 0;
|
||||
}
|
||||
lp->type_str = "thin";
|
||||
lp->type_str = SEG_TYPE_NAME_THIN;
|
||||
}
|
||||
|
||||
/* May set lp->segtype */
|
||||
if (!_read_pool_params(cmd, &argc, &argv, lp))
|
||||
return_0;
|
||||
|
||||
@@ -594,12 +589,12 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
!lp->splitcache && !lp->split && !lp->snapshot && !lp->uncache && !lp->cache && !lp->thin &&
|
||||
!lp->replace && !lp->repair && !lp->mirrorlog && !lp->corelog &&
|
||||
(arg_is_set(cmd, stripes_long_ARG) || arg_is_set(cmd, stripesize_ARG)))
|
||||
lp->type_str = "striped";
|
||||
lp->type_str = SEG_TYPE_NAME_STRIPED;
|
||||
|
||||
if ((_snapshot_type_requested(cmd, lp->type_str) || lp->merge) &&
|
||||
(lp->mirrorlog || _mirror_or_raid_type_requested(cmd, lp->type_str) ||
|
||||
lp->repair || arg_is_set(cmd, thinpool_ARG) || _raid0_type_requested(cmd, lp->type_str) ||
|
||||
_striped_type_requested(cmd, lp->type_str))) {
|
||||
lp->repair || arg_is_set(cmd, thinpool_ARG) || _raid0_type_requested(lp->type_str) ||
|
||||
_striped_type_requested(lp->type_str))) {
|
||||
log_error("--snapshot/--type snapshot or --merge argument "
|
||||
"cannot be mixed with --mirrors/--type mirror/--type raid*/--stripes/--type striped/--type linear, "
|
||||
"--mirrorlog, --repair or --thinpool.");
|
||||
@@ -607,8 +602,8 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
|
||||
if ((arg_is_set(cmd, stripes_long_ARG) || arg_is_set(cmd, stripesize_ARG)) &&
|
||||
!(_mirror_or_raid_type_requested(cmd, lp->type_str) || _striped_type_requested(cmd, lp->type_str) ||
|
||||
_raid0_type_requested(cmd, lp->type_str) || lp->repair || arg_is_set(cmd, thinpool_ARG))) {
|
||||
!(_mirror_or_raid_type_requested(cmd, lp->type_str) || _striped_type_requested(lp->type_str) ||
|
||||
_raid0_type_requested(lp->type_str) || lp->repair || arg_is_set(cmd, thinpool_ARG))) {
|
||||
log_error("--stripes or --stripesize argument is only valid "
|
||||
"with --mirrors/--type mirror/--type raid*/--type striped/--type linear, --repair and --thinpool");
|
||||
return 0;
|
||||
@@ -625,6 +620,14 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
|
||||
lp->alloc = (alloc_policy_t) arg_uint_value(cmd, alloc_ARG, ALLOC_INHERIT);
|
||||
|
||||
/* We should have caught all these cases already. */
|
||||
if (lp->merge + lp->splitsnapshot + lp->splitcache + lp->split + lp->uncache +
|
||||
lp->cache + lp->thin + lp->keep_mimages + lp->snapshot + lp->replace + lp->repair > 1) {
|
||||
log_error(INTERNAL_ERROR "Unexpected combination of incompatible options selected.");
|
||||
return 0;
|
||||
} else
|
||||
lp->other_conversion = 1;
|
||||
|
||||
/*
|
||||
* Final checking of each case:
|
||||
* lp->merge
|
||||
@@ -634,9 +637,11 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
* lp->uncache
|
||||
* lp->cache
|
||||
* lp->thin
|
||||
* lp->keep_mimages
|
||||
* lp->snapshot
|
||||
* lp->replace
|
||||
* --type mirror|raid lp->repair lp->mirrorlog lp->corelog
|
||||
* lp->repair
|
||||
* --type mirror|raid lp->mirrorlog lp->corelog
|
||||
* --type raid0|striped
|
||||
*/
|
||||
if (lp->merge) { /* Snapshot or mirror merge */
|
||||
@@ -693,11 +698,7 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
}
|
||||
log_verbose("Setting chunk size to %s.", display_size(cmd, lp->chunk_size));
|
||||
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, SEG_TYPE_NAME_SNAPSHOT)))
|
||||
return_0;
|
||||
|
||||
lp->zero = (lp->segtype->flags & SEG_CANNOT_BE_ZEROED)
|
||||
? 0 : arg_int_value(cmd, zero_ARG, 1);
|
||||
lp->type_str = SEG_TYPE_NAME_SNAPSHOT;
|
||||
|
||||
} else if (lp->replace) { /* RAID device replacement */
|
||||
lp->replace_pv_count = arg_count(cmd, replace_ARG);
|
||||
@@ -719,8 +720,10 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
tmp_str)))
|
||||
return_0;
|
||||
}
|
||||
} else if (_mirror_or_raid_type_requested(cmd, lp->type_str) ||
|
||||
lp->repair || lp->mirrorlog || lp->corelog) { /* Mirrors (and some RAID functions) */
|
||||
} else if (lp->repair)
|
||||
;
|
||||
else if (_mirror_or_raid_type_requested(cmd, lp->type_str) ||
|
||||
lp->mirrorlog || lp->corelog) { /* Mirrors (and some RAID functions) */
|
||||
if (arg_is_set(cmd, chunksize_ARG)) {
|
||||
log_error("--chunksize is only available with snapshots or pools.");
|
||||
return 0;
|
||||
@@ -771,49 +774,22 @@ static int _read_params(struct cmd_context *cmd, int argc, char **argv,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Default is never striped, regardless of existing LV configuration. */
|
||||
if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size))
|
||||
return_0;
|
||||
|
||||
/* FIXME man page says in one place that --type and --mirrors can't be mixed */
|
||||
if (lp->mirrors_supplied && !lp->mirrors) {
|
||||
if (lp->mirrors_supplied && !lp->mirrors)
|
||||
/* down-converting to linear/stripe? */
|
||||
if (!(lp->segtype =
|
||||
get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED)))
|
||||
return_0;
|
||||
} else if (arg_is_set(cmd, type_ARG)) {
|
||||
/* changing mirror type? */
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, arg_str_value(cmd, type_ARG, find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL)))))
|
||||
return_0;
|
||||
}
|
||||
} else if (_raid0_type_requested(cmd, lp->type_str) || _striped_type_requested(cmd, lp->type_str)) { /* striped or linear or raid0 */
|
||||
lp->type_str = SEG_TYPE_NAME_STRIPED;
|
||||
|
||||
} else if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str)) { /* striped or linear or raid0 */
|
||||
if (arg_from_list_is_set(cmd, "cannot be used with --type raid0 or --type striped or --type linear",
|
||||
chunksize_ARG, corelog_ARG, mirrors_ARG, mirrorlog_ARG, regionsize_ARG, zero_ARG,
|
||||
-1))
|
||||
return_0;
|
||||
|
||||
if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size))
|
||||
return_0;
|
||||
|
||||
/* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
|
||||
/* The default keeps existing number of stripes, handled inside the library code */
|
||||
if (!arg_is_set(cmd, stripes_long_ARG) && !_linear_type_requested(lp->type_str))
|
||||
lp->stripes = 0;
|
||||
|
||||
if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
|
||||
return_0;
|
||||
} /* else segtype will default to current type */
|
||||
|
||||
lp->force = arg_count(cmd, force_ARG);
|
||||
lp->yes = arg_count(cmd, yes_ARG);
|
||||
|
||||
if (activation() && lp->segtype && lp->segtype->ops->target_present &&
|
||||
!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel.", lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!_lvconvert_name_params(lp, cmd, &argc, &argv))
|
||||
return_0;
|
||||
|
||||
@@ -1382,7 +1358,7 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
|
||||
uint32_t new_log_count)
|
||||
{
|
||||
uint32_t region_size;
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
struct logical_volume *layer_lv;
|
||||
uint32_t old_mimage_count = lv_mirror_count(lv);
|
||||
uint32_t old_log_count = _get_log_count(lv);
|
||||
@@ -1395,14 +1371,12 @@ static int _lvconvert_mirrors_aux(struct cmd_context *cmd,
|
||||
|
||||
region_size = adjusted_mirror_region_size(lv->vg->extent_size,
|
||||
lv->le_count,
|
||||
lp->region_size, 0,
|
||||
lp->region_size ? : seg->region_size, 0,
|
||||
vg_is_clustered(lv->vg));
|
||||
|
||||
if (!operable_pvs)
|
||||
operable_pvs = lp->pvh;
|
||||
|
||||
seg = first_seg(lv);
|
||||
|
||||
/*
|
||||
* Up-convert from linear to mirror
|
||||
*/
|
||||
@@ -1622,6 +1596,10 @@ static int _lvconvert_mirrors_repair(struct cmd_context *cmd,
|
||||
failed_mimages = _failed_mirrors_count(lv);
|
||||
failed_logs = _failed_logs_count(lv);
|
||||
|
||||
/* Retain existing region size in case we need it later */
|
||||
if (!lp->region_size)
|
||||
lp->region_size = first_seg(lv)->region_size;
|
||||
|
||||
if (!mirror_remove_missing(cmd, lv, 0))
|
||||
return_0;
|
||||
|
||||
@@ -1717,12 +1695,16 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
|
||||
struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type;
|
||||
uint32_t old_mimage_count;
|
||||
uint32_t old_log_count;
|
||||
uint32_t new_mimage_count;
|
||||
uint32_t new_log_count;
|
||||
|
||||
if ((lp->corelog || lp->mirrorlog) && *lp->type_str && strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
|
||||
log_error("--corelog and --mirrorlog are only compatible with mirror devices");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->merge_mirror) {
|
||||
log_error("Unable to merge mirror images"
|
||||
"of segment type 'mirror'.");
|
||||
@@ -1746,8 +1728,7 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((new_type = arg_str_value(cmd, type_ARG, NULL)) &&
|
||||
!strcmp(new_type, SEG_TYPE_NAME_LINEAR)) {
|
||||
if (_linear_type_requested(lp->type_str)) {
|
||||
if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) {
|
||||
log_error("Cannot specify mirrors with linear type.");
|
||||
return 0;
|
||||
@@ -1786,6 +1767,9 @@ static int _lvconvert_mirrors(struct cmd_context *cmd,
|
||||
if (!lp->need_polling)
|
||||
log_print_unless_silent("Logical volume %s converted.",
|
||||
display_lvname(lv));
|
||||
else
|
||||
log_print_unless_silent("Logical volume %s being converted.",
|
||||
display_lvname(lv));
|
||||
|
||||
backup(lv->vg);
|
||||
|
||||
@@ -1837,18 +1821,13 @@ static void _lvconvert_raid_repair_ask(struct cmd_context *cmd,
|
||||
|
||||
static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type;
|
||||
int replace = 0, image_count = 0;
|
||||
struct dm_list *failed_pvs;
|
||||
struct cmd_context *cmd = lv->vg->cmd;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
dm_percent_t sync_percent;
|
||||
|
||||
if (!lp->segtype)
|
||||
lp->segtype = seg->segtype;
|
||||
|
||||
if ((new_type = arg_str_value(cmd, type_ARG, NULL)) &&
|
||||
!strcmp(new_type, SEG_TYPE_NAME_LINEAR)) {
|
||||
if (_linear_type_requested(lp->type_str)) {
|
||||
if (arg_is_set(cmd, mirrors_ARG) && (arg_uint_value(cmd, mirrors_ARG, 0) != 0)) {
|
||||
log_error("Cannot specify mirrors with linear type.");
|
||||
return 0;
|
||||
@@ -1858,25 +1837,36 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
}
|
||||
|
||||
/* Can only change image count for raid1 and linear */
|
||||
if (lp->mirrors_supplied && !seg_is_mirrored(seg) && !seg_is_linear(seg)) {
|
||||
log_error("'--mirrors/-m' is not compatible with %s.",
|
||||
lvseg_name(seg));
|
||||
return 0;
|
||||
if (lp->mirrors_supplied) {
|
||||
if (_raid0_type_requested(lp->type_str)) {
|
||||
log_error("--mirrors/-m is not compatible with conversion to %s.",
|
||||
lp->type_str);
|
||||
return 0;
|
||||
}
|
||||
if (!seg_is_mirrored(seg) && !seg_is_linear(seg)) {
|
||||
log_error("--mirrors/-m is not compatible with %s.",
|
||||
lvseg_name(seg));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_lvconvert_validate_thin(lv, lp))
|
||||
return_0;
|
||||
|
||||
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype)) {
|
||||
log_error("Unable to convert %s from %s to %s.",
|
||||
display_lvname(lv), lvseg_name(seg),
|
||||
lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
if (!_is_valid_raid_conversion(seg->segtype, lp->segtype))
|
||||
goto try_new_takeover_or_reshape;
|
||||
|
||||
if (seg_is_linear(seg) && !lp->merge_mirror && !lp->mirrors_supplied) {
|
||||
log_error("Raid conversions require -m/--mirrors.");
|
||||
return 0;
|
||||
if (_raid0_type_requested(lp->type_str)) {
|
||||
log_error("Linear LV %s cannot be converted to %s.",
|
||||
display_lvname(lv), lp->type_str);
|
||||
return 0;
|
||||
} else if (!strcmp(lp->type_str, SEG_TYPE_NAME_RAID1)) {
|
||||
log_error("Raid conversions of LV %s require -m/--mirrors.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
goto try_new_takeover_or_reshape;
|
||||
}
|
||||
|
||||
/* Change number of RAID1 images */
|
||||
@@ -1897,10 +1887,15 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
|
||||
/* --trackchanges requires --splitmirrors which always has SIGN_MINUS */
|
||||
if (lp->track_changes && lp->mirrors != 1) {
|
||||
log_error("Exactly one image must be split off from %s when tracking changes.",
|
||||
log_error("Exactly one image must be split off from %s when tracking changes.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ((lp->corelog || lp->mirrorlog) && strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
|
||||
log_error("--corelog and --mirrorlog are only compatible with mirror devices");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lp->merge_mirror)
|
||||
@@ -1912,18 +1907,44 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
if (lp->keep_mimages)
|
||||
return lv_raid_split(lv, lp->lv_split_name, image_count, lp->pvh);
|
||||
|
||||
if (lp->mirrors_supplied)
|
||||
return lv_raid_change_image_count(lv, image_count, lp->pvh);
|
||||
if (lp->mirrors_supplied) {
|
||||
if (!*lp->type_str || !strcmp(lp->type_str, SEG_TYPE_NAME_RAID1) || !strcmp(lp->type_str, SEG_TYPE_NAME_LINEAR) ||
|
||||
(!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED) && image_count == 1)) {
|
||||
if (image_count > DEFAULT_RAID1_MAX_IMAGES) {
|
||||
log_error("Only up to %u mirrors in %s LV %s supported currently.",
|
||||
DEFAULT_RAID1_MAX_IMAGES, lp->segtype->name, display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
if (!lv_raid_change_image_count(lv, image_count, lp->pvh))
|
||||
return_0;
|
||||
|
||||
log_print_unless_silent("Logical volume %s successfully converted.",
|
||||
display_lvname(lv));
|
||||
|
||||
return 1;
|
||||
}
|
||||
goto try_new_takeover_or_reshape;
|
||||
} else if (!lp->repair && !lp->replace && (!*lp->type_str || seg->segtype == lp->segtype)) {
|
||||
log_error("Conversion operation not yet supported.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((seg_is_linear(seg) || seg_is_striped(seg) || seg_is_mirrored(seg) || lv_is_raid(lv)) &&
|
||||
(lp->type_str && lp->type_str[0])) {
|
||||
/* Activation is required later which precludes existing unsupported raid0 segment */
|
||||
if (segtype_is_any_raid0(lp->segtype) &&
|
||||
!(lp->target_attr & RAID_FEATURE_RAID0)) {
|
||||
log_error("RAID module does not support RAID0.");
|
||||
return 0;
|
||||
}
|
||||
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size, lp->pvh))
|
||||
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
|
||||
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
|
||||
lp->region_size, lp->pvh))
|
||||
return_0;
|
||||
|
||||
log_print_unless_silent("Logical volume %s successfully converted.",
|
||||
display_lvname(lv));
|
||||
return 1;
|
||||
@@ -1941,8 +1962,7 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!seg_is_striped(seg) && !seg_is_any_raid0(seg) &&
|
||||
!lv_raid_percent(lv, &sync_percent)) {
|
||||
if (!seg_is_striped(seg) && !lv_raid_percent(lv, &sync_percent)) {
|
||||
log_error("Unable to determine sync status of %s.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
@@ -1984,8 +2004,27 @@ static int _lvconvert_raid(struct logical_volume *lv, struct lvconvert_params *l
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_error("Conversion operation not yet supported.");
|
||||
|
||||
try_new_takeover_or_reshape:
|
||||
|
||||
/* FIXME This needs changing globally. */
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
|
||||
/* Only let raid4 through for now. */
|
||||
if (lp->type_str && lp->type_str[0] && lp->segtype != seg->segtype &&
|
||||
((seg_is_raid4(seg) && seg_is_striped(lp) && lp->stripes > 1) ||
|
||||
(seg_is_striped(seg) && seg->area_count > 1 && seg_is_raid4(lp)))) {
|
||||
if (!lv_raid_convert(lv, lp->segtype, lp->yes, lp->force, lp->stripes, lp->stripe_size_supplied, lp->stripe_size,
|
||||
lp->region_size, lp->pvh))
|
||||
return_0;
|
||||
|
||||
log_print_unless_silent("Logical volume %s successfully converted.",
|
||||
display_lvname(lv));
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_error("Conversion operation not yet supported.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2420,9 +2459,6 @@ static int _lvconvert_merge_thin_snapshot(struct cmd_context *cmd,
|
||||
if (!archive(lv->vg))
|
||||
return_0;
|
||||
|
||||
// FIXME: allow origin to be specified
|
||||
// FIXME: verify snapshot is descendant of specified origin
|
||||
|
||||
/*
|
||||
* Prevent merge with open device(s) as it would likely lead
|
||||
* to application/filesystem failure. Merge on origin's next
|
||||
@@ -3146,7 +3182,8 @@ static int _lvconvert_pool(struct cmd_context *cmd,
|
||||
if (!_lvconvert_update_pool_params(pool_lv, lp))
|
||||
return_0;
|
||||
|
||||
if (!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size))
|
||||
if (!get_stripe_params(cmd, get_segtype_from_string(cmd, SEG_TYPE_NAME_STRIPED),
|
||||
&lp->stripes, &lp->stripe_size))
|
||||
return_0;
|
||||
|
||||
if (!archive(vg))
|
||||
@@ -3889,6 +3926,16 @@ static int _convert_raid_raid(struct cmd_context *cmd, struct logical_volume *lv
|
||||
return _lvconvert_raid(lv, lp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a raid* LV to a mirror LV.
|
||||
* lvconvert --type mirror LV
|
||||
*/
|
||||
static int _convert_raid_mirror(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
return _lvconvert_raid(lv, lp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a raid* LV to a striped LV.
|
||||
* lvconvert --type striped LV
|
||||
@@ -4081,8 +4128,6 @@ static int _convert_thin_volume(struct cmd_context *cmd, struct logical_volume *
|
||||
static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
|
||||
|
||||
if (arg_is_set(cmd, splitcache_ARG))
|
||||
return _convert_thin_pool_splitcache(cmd, lv, lp);
|
||||
|
||||
@@ -4092,7 +4137,7 @@ static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv
|
||||
if (arg_is_set(cmd, uncache_ARG))
|
||||
return _convert_thin_pool_uncache(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE)) || arg_is_set(cmd, cache_ARG))
|
||||
if (lp->cache)
|
||||
return _convert_thin_pool_cache(cmd, lv, lp);
|
||||
|
||||
if (arg_is_set(cmd, repair_ARG))
|
||||
@@ -4116,8 +4161,6 @@ static int _convert_thin_pool(struct cmd_context *cmd, struct logical_volume *lv
|
||||
static int _convert_cache_volume(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
|
||||
|
||||
if (arg_is_set(cmd, splitcache_ARG))
|
||||
return _convert_cache_volume_splitcache(cmd, lv, lp);
|
||||
|
||||
@@ -4132,7 +4175,7 @@ static int _convert_cache_volume(struct cmd_context *cmd, struct logical_volume
|
||||
|
||||
/* Using --thinpool is ambiguous and not preferred. */
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN_POOL)) || arg_is_set(cmd, thinpool_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || arg_is_set(cmd, thinpool_ARG))
|
||||
return _convert_cache_volume_thin_pool(cmd, lv, lp);
|
||||
|
||||
/* The --thinpool alternative for --type thin-pool is not preferred, so not shown. */
|
||||
@@ -4170,12 +4213,6 @@ static int _convert_cache_pool(struct cmd_context *cmd, struct logical_volume *l
|
||||
static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
|
||||
const struct segment_type *new_segtype = NULL;
|
||||
|
||||
if (new_type)
|
||||
new_segtype = get_segtype_from_string(cmd, new_type);
|
||||
|
||||
if (arg_is_set(cmd, mirrors_ARG))
|
||||
return _convert_mirror_number(cmd, lv, lp);
|
||||
|
||||
@@ -4188,10 +4225,10 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (arg_is_set(cmd, repair_ARG))
|
||||
return _convert_mirror_repair(cmd, lv, lp);
|
||||
|
||||
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_LINEAR))
|
||||
if (_linear_type_requested(lp->type_str))
|
||||
return _convert_mirror_linear(cmd, lv, lp);
|
||||
|
||||
if (new_type && new_segtype && segtype_is_raid(new_segtype))
|
||||
if (segtype_is_raid(lp->segtype))
|
||||
return _convert_mirror_raid(cmd, lv, lp);
|
||||
|
||||
/*
|
||||
@@ -4226,12 +4263,6 @@ static int _convert_mirror(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
|
||||
const struct segment_type *new_segtype = NULL;
|
||||
|
||||
if (new_type)
|
||||
new_segtype = get_segtype_from_string(cmd, new_type);
|
||||
|
||||
if (arg_is_set(cmd, mirrors_ARG))
|
||||
return _convert_raid_number(cmd, lv, lp);
|
||||
|
||||
@@ -4247,32 +4278,35 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
if (arg_is_set(cmd, replace_ARG))
|
||||
return _convert_raid_replace(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_SNAPSHOT)) || arg_is_set(cmd, snapshot_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_SNAPSHOT) || arg_is_set(cmd, snapshot_ARG))
|
||||
return _convert_raid_snapshot(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN)) || arg_is_set(cmd, thin_ARG))
|
||||
if (lp->thin)
|
||||
return _convert_raid_thin(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE)) || arg_is_set(cmd, cache_ARG))
|
||||
if (lp->cache)
|
||||
return _convert_raid_cache(cmd, lv, lp);
|
||||
|
||||
/* Using --thinpool is ambiguous and not preferred. */
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN_POOL)) || arg_is_set(cmd, thinpool_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || arg_is_set(cmd, thinpool_ARG))
|
||||
return _convert_raid_thin_pool(cmd, lv, lp);
|
||||
|
||||
/* Using --cachepool is ambiguous and not preferred. */
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE_POOL)) || arg_is_set(cmd, cachepool_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL) || arg_is_set(cmd, cachepool_ARG))
|
||||
return _convert_raid_cache_pool(cmd, lv, lp);
|
||||
|
||||
if (new_type && new_segtype && segtype_is_raid(new_segtype))
|
||||
if (segtype_is_raid(lp->segtype))
|
||||
return _convert_raid_raid(cmd, lv, lp);
|
||||
|
||||
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_STRIPED))
|
||||
if (segtype_is_mirror(lp->segtype))
|
||||
return _convert_raid_mirror(cmd, lv, lp);
|
||||
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_STRIPED))
|
||||
return _convert_raid_striped(cmd, lv, lp);
|
||||
|
||||
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_LINEAR))
|
||||
if (_linear_type_requested(lp->type_str))
|
||||
return _convert_raid_linear(cmd, lv, lp);
|
||||
|
||||
/* The --thinpool alternative for --type thin-pool is not preferred, so not shown. */
|
||||
@@ -4290,6 +4324,7 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
" --type thin-pool\n"
|
||||
" --type cache-pool\n"
|
||||
" --type raid*\n"
|
||||
" --type mirror\n"
|
||||
" --type striped\n"
|
||||
" --type linear\n");
|
||||
return 0;
|
||||
@@ -4298,40 +4333,35 @@ static int _convert_raid(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
const char *new_type = arg_str_value(cmd, type_ARG, NULL);
|
||||
const struct segment_type *new_segtype = NULL;
|
||||
const char *mirrors_type = find_config_tree_str(cmd, global_mirror_segtype_default_CFG, NULL);
|
||||
|
||||
if (new_type)
|
||||
new_segtype = get_segtype_from_string(cmd, new_type);
|
||||
|
||||
/* FIXME: add --merge-mirror to make this distinct from --merge-snapshot. */
|
||||
if (arg_is_set(cmd, merge_ARG))
|
||||
return _convert_striped_merge(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_SNAPSHOT)) || arg_is_set(cmd, snapshot_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_SNAPSHOT) || arg_is_set(cmd, snapshot_ARG))
|
||||
return _convert_striped_snapshot(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN)) || arg_is_set(cmd, thin_ARG))
|
||||
if (lp->thin)
|
||||
return _convert_striped_thin(cmd, lv, lp);
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE)) || arg_is_set(cmd, cache_ARG))
|
||||
if (lp->cache)
|
||||
return _convert_striped_cache(cmd, lv, lp);
|
||||
|
||||
/* Using --thinpool is ambiguous and not preferred. */
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_THIN_POOL)) || arg_is_set(cmd, thinpool_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_THIN_POOL) || arg_is_set(cmd, thinpool_ARG))
|
||||
return _convert_striped_thin_pool(cmd, lv, lp);
|
||||
|
||||
/* Using --cachepool is ambiguous and not preferred. */
|
||||
|
||||
if ((new_type && !strcmp(new_type, SEG_TYPE_NAME_CACHE_POOL)) || arg_is_set(cmd, cachepool_ARG))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_CACHE_POOL) || arg_is_set(cmd, cachepool_ARG))
|
||||
return _convert_striped_cache_pool(cmd, lv, lp);
|
||||
|
||||
if (new_type && !strcmp(new_type, SEG_TYPE_NAME_MIRROR))
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR))
|
||||
return _convert_striped_mirror(cmd, lv, lp);
|
||||
|
||||
if (new_type && new_segtype && segtype_is_raid(new_segtype))
|
||||
if (segtype_is_raid(lp->segtype))
|
||||
return _convert_striped_raid(cmd, lv, lp);
|
||||
|
||||
/* --mirrors can mean --type mirror or --type raid1 depending on config setting. */
|
||||
@@ -4359,6 +4389,7 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
}
|
||||
|
||||
/*
|
||||
* Main entry point.
|
||||
* lvconvert performs a specific <operation> on a specific <lv_type>.
|
||||
*
|
||||
* The <operation> is specified by command line args.
|
||||
@@ -4366,14 +4397,20 @@ static int _convert_striped(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
*
|
||||
* for each lvtype,
|
||||
* _convert_lvtype();
|
||||
* for each arg_is_set(operation)
|
||||
* _convert_lvtype_operation();
|
||||
* for each arg_is_set(operation)
|
||||
* _convert_lvtype_operation();
|
||||
*
|
||||
* FIXME: this code (identifying/routing each unique operation through
|
||||
* _convert_lvtype_op) was designed to work based on the new type that
|
||||
* the user entered after --type, not the final segment type in lp->type_str.
|
||||
* Sometimes the two differ because tricks are played with lp->type_str.
|
||||
* So, when the use of arg_type_str(type_ARG) here was replaced with
|
||||
* lp->type_str, some commands are no longer identified/routed correctly.
|
||||
*/
|
||||
static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
struct lvconvert_params *lp)
|
||||
{
|
||||
struct lv_segment *lv_seg = first_seg(lv);
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
@@ -4411,11 +4448,50 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up segtype either from type_str or else to match the existing one. */
|
||||
if (!*lp->type_str)
|
||||
lp->segtype = seg->segtype;
|
||||
else if (!(lp->segtype = get_segtype_from_string(cmd, lp->type_str)))
|
||||
return_0;
|
||||
|
||||
if (!strcmp(lp->type_str, SEG_TYPE_NAME_MIRROR)) {
|
||||
if (!lp->mirrors_supplied && !seg_is_raid1(seg)) {
|
||||
log_error("Conversions to --type mirror require -m/--mirrors");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (activation() && lp->segtype && lp->segtype->ops->target_present &&
|
||||
!lp->segtype->ops->target_present(cmd, NULL, &lp->target_attr)) {
|
||||
log_error("%s: Required device-mapper target(s) not "
|
||||
"detected in your kernel.", lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process striping parameters */
|
||||
/* FIXME This is incomplete */
|
||||
if (_mirror_or_raid_type_requested(cmd, lp->type_str) || _raid0_type_requested(lp->type_str) ||
|
||||
_striped_type_requested(lp->type_str) || lp->repair || lp->mirrorlog || lp->corelog) {
|
||||
/* FIXME Handle +/- adjustments too? */
|
||||
if (!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size))
|
||||
return_0;
|
||||
/* FIXME Move this into the get function */
|
||||
lp->stripe_size_supplied = arg_is_set(cmd, stripesize_ARG);
|
||||
|
||||
if (_raid0_type_requested(lp->type_str) || _striped_type_requested(lp->type_str))
|
||||
/* FIXME Shouldn't need to override get_stripe_params which defaults to 1 stripe (i.e. linear)! */
|
||||
/* The default keeps existing number of stripes, handled inside the library code */
|
||||
if (!arg_is_set(cmd, stripes_long_ARG))
|
||||
lp->stripes = 0;
|
||||
}
|
||||
|
||||
if (lp->snapshot)
|
||||
lp->zero = (lp->segtype->flags & SEG_CANNOT_BE_ZEROED) ? 0 : arg_int_value(cmd, zero_ARG, 1);
|
||||
|
||||
/*
|
||||
* Each LV type that can be converted.
|
||||
* (The existing type of the LV, not a requested type.)
|
||||
*/
|
||||
|
||||
if (lv_is_cow(lv)) {
|
||||
ret = _convert_cow_snapshot(cmd, lv, lp);
|
||||
goto out;
|
||||
@@ -4453,10 +4529,10 @@ static int _lvconvert(struct cmd_context *cmd, struct logical_volume *lv,
|
||||
|
||||
/*
|
||||
* FIXME: add lv_is_striped() and lv_is_linear()?
|
||||
* This does not include raid0.
|
||||
* This does not include raid0 which is caught by the test above.
|
||||
* If operations differ between striped and linear, split this case.
|
||||
*/
|
||||
if (segtype_is_striped(lv_seg->segtype) || segtype_is_linear(lv_seg->segtype)) {
|
||||
if (segtype_is_striped(seg->segtype) || segtype_is_linear(seg->segtype)) {
|
||||
ret = _convert_striped(cmd, lv, lp);
|
||||
goto out;
|
||||
}
|
||||
|
@@ -495,9 +495,7 @@ static int _read_raid_params(struct cmd_context *cmd,
|
||||
lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} else if (!lp->stripe_size)
|
||||
lp->stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
|
||||
}
|
||||
|
||||
if (arg_is_set(cmd, mirrors_ARG) && segtype_is_raid(lp->segtype) &&
|
||||
!segtype_is_raid1(lp->segtype) && !segtype_is_raid10(lp->segtype)) {
|
||||
@@ -529,8 +527,21 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
|
||||
struct lvcreate_params *lp)
|
||||
{
|
||||
int pagesize = lvm_getpagesize();
|
||||
unsigned max_images = segtype_is_raid(lp->segtype) ? DEFAULT_RAID_MAX_IMAGES :
|
||||
DEFAULT_MIRROR_MAX_IMAGES;
|
||||
unsigned max_images;
|
||||
|
||||
if (seg_is_raid(lp)) {
|
||||
if (seg_is_raid1(lp))
|
||||
max_images = DEFAULT_RAID1_MAX_IMAGES;
|
||||
else {
|
||||
max_images = DEFAULT_RAID_MAX_IMAGES;
|
||||
if (seg_is_raid4(lp) ||
|
||||
seg_is_any_raid5(lp))
|
||||
max_images--;
|
||||
else if (seg_is_any_raid6(lp))
|
||||
max_images -= 2;
|
||||
}
|
||||
} else
|
||||
max_images = DEFAULT_MIRROR_MAX_IMAGES;
|
||||
|
||||
/* Common mirror and raid params */
|
||||
if (arg_is_set(cmd, mirrors_ARG)) {
|
||||
@@ -558,13 +569,27 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
|
||||
/* Default to 2 mirrored areas if '--type mirror|raid1|raid10' */
|
||||
lp->mirrors = seg_is_mirrored(lp) ? 2 : 1;
|
||||
|
||||
if (max(lp->mirrors, lp->stripes) > max_images) {
|
||||
log_error("Only up to %u images in %s supported currently.",
|
||||
/* FIMXE: raid10 check has to change once we support data copies and odd numbers of stripes */
|
||||
if (seg_is_raid10(lp) && lp->mirrors * lp->stripes > max_images) {
|
||||
log_error("Only up to %u stripes in %s supported currently.",
|
||||
max_images, lp->segtype->name);
|
||||
return 0;
|
||||
} else if (seg_is_mirrored(lp)) {
|
||||
if (lp->mirrors > max_images) {
|
||||
log_error("Only up to %u mirrors in %s supported currently.",
|
||||
max_images, lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
} else if (lp->stripes > max_images) {
|
||||
log_error("Only up to %u stripes in %s supported currently.",
|
||||
max_images, lp->segtype->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lp->nosync = arg_is_set(cmd, nosync_ARG);
|
||||
if ((lp->nosync = arg_is_set(cmd, nosync_ARG)) && seg_is_any_raid6(lp)) {
|
||||
log_error("nosync option prohibited on RAID6");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(lp->region_size = arg_uint_value(cmd, regionsize_ARG, 0)) &&
|
||||
((lp->region_size = get_default_region_size(cmd)) <= 0)) {
|
||||
@@ -572,14 +597,6 @@ static int _read_mirror_and_raid_params(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME This is working around a bug in get_stripe_params() where
|
||||
* stripes is incorrectly assumed to be 1 when it is not supplied
|
||||
* leading to the actual value of stripesize getting lost.
|
||||
*/
|
||||
if (arg_is_set(cmd, stripesize_ARG))
|
||||
lp->stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
|
||||
|
||||
if (!is_power_of_2(lp->region_size)) {
|
||||
log_error("Region size (%" PRIu32 ") must be a power of 2",
|
||||
lp->region_size);
|
||||
@@ -1044,7 +1061,7 @@ static int _lvcreate_params(struct cmd_context *cmd,
|
||||
|
||||
if (!_lvcreate_name_params(cmd, &argc, &argv, lp) ||
|
||||
!_read_size_params(cmd, lp, lcp) ||
|
||||
!get_stripe_params(cmd, &lp->stripes, &lp->stripe_size) ||
|
||||
!get_stripe_params(cmd, lp->segtype, &lp->stripes, &lp->stripe_size) ||
|
||||
(lp->create_pool &&
|
||||
!get_pool_params(cmd, lp->segtype, &lp->passed_args,
|
||||
&lp->pool_metadata_size, &lp->pool_metadata_spare,
|
||||
@@ -1238,10 +1255,17 @@ static int _check_raid_parameters(struct volume_group *vg,
|
||||
struct lvcreate_cmdline_params *lcp)
|
||||
{
|
||||
unsigned devs = lcp->pv_count ? : dm_list_size(&vg->pvs);
|
||||
uint64_t page_sectors = lvm_getpagesize() >> SECTOR_SHIFT;
|
||||
struct cmd_context *cmd = vg->cmd;
|
||||
int old_stripes = !arg_is_set(cmd, stripes_ARG) &&
|
||||
find_config_tree_bool(cmd, allocation_raid_stripe_all_devices_CFG, NULL);
|
||||
|
||||
if (vg->extent_size < page_sectors) {
|
||||
log_error("Unable to create RAID LV: requires minimum VG extent size %s",
|
||||
display_size(vg->cmd, page_sectors));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we requested the previous behaviour by setting
|
||||
* "allocation/raid_stripe_all_devices = 1" and the
|
||||
|
140
tools/lvm.c
140
tools/lvm.c
@@ -45,9 +45,9 @@ static char *_list_cmds(const char *text, int state)
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (i < _cmdline->num_commands)
|
||||
if (!strncmp(text, _cmdline->commands[i++].name, len))
|
||||
return strdup(_cmdline->commands[i - 1].name);
|
||||
while (i < _cmdline->num_command_names)
|
||||
if (!strncmp(text, _cmdline->command_names[i++].name, len))
|
||||
return strdup(_cmdline->command_names[i - 1].name);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -57,7 +57,7 @@ static char *_list_args(const char *text, int state)
|
||||
{
|
||||
static int match_no = 0;
|
||||
static size_t len = 0;
|
||||
static struct command *com;
|
||||
static struct command_name *cname;
|
||||
|
||||
/* Initialise if this is a new completion attempt */
|
||||
if (!state) {
|
||||
@@ -65,40 +65,40 @@ static char *_list_args(const char *text, int state)
|
||||
int j;
|
||||
|
||||
match_no = 0;
|
||||
com = NULL;
|
||||
cname = NULL;
|
||||
len = strlen(text);
|
||||
|
||||
/* Find start of first word in line buffer */
|
||||
while (isspace(*s))
|
||||
s++;
|
||||
|
||||
/* Look for word in list of commands */
|
||||
for (j = 0; j < _cmdline->num_commands; j++) {
|
||||
/* Look for word in list of command names */
|
||||
for (j = 0; j < _cmdline->num_command_names; j++) {
|
||||
const char *p;
|
||||
char *q = s;
|
||||
|
||||
p = _cmdline->commands[j].name;
|
||||
p = _cmdline->command_names[j].name;
|
||||
while (*p == *q) {
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if ((!*p) && *q == ' ') {
|
||||
com = _cmdline->commands + j;
|
||||
cname = _cmdline->command_names + j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!com)
|
||||
if (!cname)
|
||||
return NULL;
|
||||
|
||||
/* Short form arguments */
|
||||
if (len < 3) {
|
||||
while (match_no < com->num_args) {
|
||||
while (match_no < cname->num_args) {
|
||||
char s[3];
|
||||
char c;
|
||||
if (!(c = (_cmdline->arg_props +
|
||||
com->valid_args[match_no++])->short_arg))
|
||||
cname->valid_args[match_no++])->short_arg))
|
||||
continue;
|
||||
|
||||
sprintf(s, "-%c", c);
|
||||
@@ -108,13 +108,13 @@ static char *_list_args(const char *text, int state)
|
||||
}
|
||||
|
||||
/* Long form arguments */
|
||||
if (match_no < com->num_args)
|
||||
match_no = com->num_args;
|
||||
if (match_no < cname->num_args)
|
||||
match_no = cname->num_args;
|
||||
|
||||
while (match_no - com->num_args < com->num_args) {
|
||||
while (match_no - cname->num_args < cname->num_args) {
|
||||
const char *l;
|
||||
l = (_cmdline->arg_props +
|
||||
com->valid_args[match_no++ - com->num_args])->long_arg;
|
||||
cname->valid_args[match_no++ - cname->num_args])->long_arg;
|
||||
if (*(l + 2) && !strncmp(text, l, len))
|
||||
return strdup(l);
|
||||
}
|
||||
@@ -181,66 +181,124 @@ static void _write_history(void)
|
||||
log_very_verbose("Couldn't write history to %s.", hist_file);
|
||||
}
|
||||
|
||||
static int _log_shell_command_status(struct cmd_context *cmd, int ret_code)
|
||||
{
|
||||
log_report_t log_state;
|
||||
|
||||
if (!cmd->cmd_report.log_rh)
|
||||
return 1;
|
||||
|
||||
log_state = log_get_report_state();
|
||||
|
||||
return report_cmdlog(cmd->cmd_report.log_rh, REPORT_OBJECT_CMDLOG_NAME,
|
||||
log_get_report_context_name(log_state.context),
|
||||
log_get_report_object_type_name(log_state.object_type),
|
||||
log_state.object_name, log_state.object_id,
|
||||
log_state.object_group, log_state.object_group_id,
|
||||
ret_code == ECMD_PROCESSED ? REPORT_OBJECT_CMDLOG_SUCCESS
|
||||
: REPORT_OBJECT_CMDLOG_FAILURE,
|
||||
stored_errno(), ret_code);
|
||||
}
|
||||
|
||||
static void _discard_log_report_content(struct cmd_context *cmd)
|
||||
{
|
||||
if (cmd->cmd_report.log_rh)
|
||||
dm_report_destroy_rows(cmd->cmd_report.log_rh);
|
||||
}
|
||||
|
||||
int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
|
||||
{
|
||||
int argc, ret;
|
||||
log_report_t saved_log_report_state = log_get_report_state();
|
||||
char *orig_command_log_selection = NULL;
|
||||
int is_lastlog_cmd = 0, argc, ret;
|
||||
char *input = NULL, *args[MAX_ARGS], **argv;
|
||||
|
||||
rl_readline_name = "lvm";
|
||||
rl_attempted_completion_function = (rl_completion_func_t *) _completion;
|
||||
|
||||
_read_history(cmd);
|
||||
|
||||
_cmdline = cmdline;
|
||||
|
||||
cmd->is_interactive = 1;
|
||||
|
||||
if (!report_format_init(cmd))
|
||||
return_ECMD_FAILED;
|
||||
|
||||
orig_command_log_selection = dm_pool_strdup(cmd->libmem, find_config_tree_str(cmd, log_command_log_selection_CFG, NULL));
|
||||
log_set_report_context(LOG_REPORT_CONTEXT_SHELL);
|
||||
log_set_report_object_type(LOG_REPORT_OBJECT_TYPE_CMD);
|
||||
|
||||
while (1) {
|
||||
report_reset_cmdlog_seqnum();
|
||||
if (cmd->cmd_report.log_rh) {
|
||||
/*
|
||||
* If previous command was lastlog, reset log report selection to
|
||||
* its original value as set by log/command_log_selection config setting.
|
||||
*/
|
||||
if (is_lastlog_cmd &&
|
||||
!dm_report_set_selection(cmd->cmd_report.log_rh, orig_command_log_selection))
|
||||
log_error("Failed to reset log report selection.");
|
||||
}
|
||||
|
||||
log_set_report(cmd->cmd_report.log_rh);
|
||||
log_set_report_object_name_and_id(NULL, NULL);
|
||||
|
||||
free(input);
|
||||
input = readline("lvm> ");
|
||||
|
||||
/* EOF */
|
||||
if (!input) {
|
||||
_discard_log_report_content(cmd);
|
||||
/* readline sends prompt to stdout */
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* empty line */
|
||||
if (!*input)
|
||||
if (!*input) {
|
||||
_discard_log_report_content(cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
add_history(input);
|
||||
|
||||
argv = args;
|
||||
|
||||
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
|
||||
_discard_log_report_content(cmd);
|
||||
log_error("Too many arguments, sorry.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!argc)
|
||||
if (!argc) {
|
||||
_discard_log_report_content(cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "lvm")) {
|
||||
argv++;
|
||||
argc--;
|
||||
}
|
||||
|
||||
if (!argc)
|
||||
if (!argc) {
|
||||
_discard_log_report_content(cmd);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_set_report_object_name_and_id(argv[0], NULL);
|
||||
|
||||
is_lastlog_cmd = !strcmp(argv[0], "lastlog");
|
||||
|
||||
if (!is_lastlog_cmd)
|
||||
_discard_log_report_content(cmd);
|
||||
|
||||
if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
|
||||
_discard_log_report_content(cmd);
|
||||
remove_history(history_length - 1);
|
||||
log_error("Exiting.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (cmd->log_rh && strcmp(argv[0], "lastlog")) {
|
||||
/* drop old log report */
|
||||
dm_report_free(cmd->log_rh);
|
||||
cmd->log_rh = NULL;
|
||||
}
|
||||
|
||||
ret = lvm_run_command(cmd, argc, argv);
|
||||
if (ret == ENO_SUCH_CMD)
|
||||
log_error("No such command '%s'. Try 'help'.",
|
||||
@@ -251,10 +309,38 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
|
||||
log_error("Command failed with status code %d.", ret);
|
||||
}
|
||||
_write_history();
|
||||
|
||||
if (!is_lastlog_cmd)
|
||||
_log_shell_command_status(cmd, ret);
|
||||
|
||||
log_set_report(NULL);
|
||||
dm_report_group_output_and_pop_all(cmd->cmd_report.report_group);
|
||||
|
||||
if (cmd->cmd_report.log_rh &&
|
||||
!(dm_report_group_push(cmd->cmd_report.report_group,
|
||||
cmd->cmd_report.log_rh,
|
||||
(void *) cmd->cmd_report.log_name))) {
|
||||
log_set_report(NULL);
|
||||
log_error("Failed to add log report.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
log_restore_report_state(saved_log_report_state);
|
||||
cmd->is_interactive = 0;
|
||||
|
||||
free(input);
|
||||
|
||||
if (cmd->cmd_report.report_group) {
|
||||
dm_report_group_destroy(cmd->cmd_report.report_group);
|
||||
cmd->cmd_report.report_group = NULL;
|
||||
}
|
||||
|
||||
if (cmd->cmd_report.log_rh) {
|
||||
dm_report_free(cmd->cmd_report.log_rh);
|
||||
cmd->cmd_report.report_group = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -19,10 +19,11 @@
|
||||
struct cmd_context;
|
||||
|
||||
struct cmdline_context {
|
||||
struct arg_props *arg_props;
|
||||
struct command *commands;
|
||||
int num_commands;
|
||||
int commands_size;
|
||||
struct arg_props *arg_props;
|
||||
struct command *commands;
|
||||
int num_commands;
|
||||
struct command_name *command_names;
|
||||
int num_command_names;
|
||||
};
|
||||
|
||||
int lvm2_main(int argc, char **argv);
|
||||
|
1134
tools/lvmcmdline.c
1134
tools/lvmcmdline.c
File diff suppressed because it is too large
Load Diff
@@ -144,6 +144,75 @@ static struct dm_list *_get_allocatable_pvs(struct cmd_context *cmd, int argc,
|
||||
return allocatable_pvs;
|
||||
}
|
||||
|
||||
/*
|
||||
* If @lv_name's a RAID SubLV, check for any PVs
|
||||
* on @trim_list holding it's sibling (rimage/rmeta)
|
||||
* and remove it from the @trim_list in order to allow
|
||||
* for pvmove collocation of DataLV/MetaLV pairs.
|
||||
*/
|
||||
static int _remove_sibling_pvs_from_trim_list(struct logical_volume *lv,
|
||||
const char *lv_name,
|
||||
struct dm_list *trim_list)
|
||||
{
|
||||
char *idx, *suffix, *sublv_name;
|
||||
size_t len;
|
||||
struct logical_volume *sublv;
|
||||
struct dm_list untrim_list, *pvh1, *pvh2;
|
||||
struct pv_list *pvl1, *pvl2;
|
||||
|
||||
/* Give up with success unless @lv_name _and_ valid raid segment type */
|
||||
if (!lv_name || !*lv_name ||
|
||||
!seg_is_raid(first_seg(lv)) ||
|
||||
seg_is_raid0(first_seg(lv)) ||
|
||||
!strcmp(lv->name, lv_name))
|
||||
return 1;
|
||||
|
||||
dm_list_init(&untrim_list);
|
||||
|
||||
if (!(suffix = first_substring(lv_name, "_rimage_", "_rmeta_", NULL)))
|
||||
return 0;
|
||||
|
||||
if (!(idx = strstr(suffix + 1, "_")))
|
||||
return 0;
|
||||
idx++;
|
||||
|
||||
/* + 2 for the longer rimage string */
|
||||
if (!(sublv_name = dm_pool_alloc(lv->vg->cmd->mem, strlen(lv_name + 2))))
|
||||
return_0;
|
||||
|
||||
/* Create the siblings name (e.g. "raidlv_rmeta_N" -> "raidlv_rimage_N" */
|
||||
len = suffix - lv_name;
|
||||
strncpy(sublv_name, lv_name, len);
|
||||
sprintf(sublv_name + len, strstr(suffix, "_rimage_") ? "_rmeta_%s" : "_rimage_%s", idx);
|
||||
|
||||
if (!(sublv = find_lv(lv->vg, sublv_name))) {
|
||||
log_error("Can't find sub LV %s?", sublv_name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
if (!get_pv_list_for_lv(lv->vg->cmd->mem, sublv, &untrim_list)) {
|
||||
log_error("Can't find PVs for sub LV %s?", sublv_name);
|
||||
return_0;
|
||||
}
|
||||
|
||||
dm_list_iterate(pvh1, &untrim_list) {
|
||||
pvl1 = dm_list_item(pvh1, struct pv_list);
|
||||
|
||||
dm_list_iterate(pvh2, trim_list) {
|
||||
pvl2 = dm_list_item(pvh2, struct pv_list);
|
||||
|
||||
if (pvl1->pv == pvl2->pv) {
|
||||
log_debug("Removing PV %s from trim list",
|
||||
pvl2->pv->dev->pvid);
|
||||
dm_list_del(&pvl2->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* _trim_allocatable_pvs
|
||||
* @alloc_list
|
||||
@@ -324,7 +393,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
if (lv == lv_mirr)
|
||||
continue;
|
||||
|
||||
if (lv_name && strcmp(lv->name, lv_name))
|
||||
if (lv_name && strcmp(lv->name, top_level_lv_name(vg, lv_name)))
|
||||
continue;
|
||||
|
||||
/*
|
||||
@@ -334,7 +403,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
*
|
||||
* Allow clustered mirror, but not raid mirror.
|
||||
*/
|
||||
if (vg_is_clustered(lv->vg) && !lv_is_mirror_type(lv))
|
||||
if (vg_is_clustered(vg) && !lv_is_mirror_type(lv))
|
||||
continue;
|
||||
|
||||
if (!lv_is_on_pvs(lv, source_pvl))
|
||||
@@ -351,8 +420,18 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
seg_is_mirrored(first_seg(lv))) {
|
||||
dm_list_init(&trim_list);
|
||||
|
||||
if (!get_pv_list_for_lv(lv->vg->cmd->mem,
|
||||
lv, &trim_list))
|
||||
if (!get_pv_list_for_lv(vg->cmd->mem, lv, &trim_list))
|
||||
return_NULL;
|
||||
|
||||
/*
|
||||
* Remove any PVs holding SubLV siblings to allow
|
||||
* for collocation (e.g. *rmeta_0 -> *rimage_0).
|
||||
*
|
||||
* Callee checks for lv_name and valid raid segment type.
|
||||
*
|
||||
* FIXME: don't rely on namespace
|
||||
*/
|
||||
if (!_remove_sibling_pvs_from_trim_list(lv, lv_name, &trim_list))
|
||||
return_NULL;
|
||||
|
||||
if (!_trim_allocatable_pvs(allocatable_pvs,
|
||||
@@ -370,6 +449,7 @@ static struct logical_volume *_set_up_pvmove_lv(struct cmd_context *cmd,
|
||||
lv = lvl->lv;
|
||||
if (lv == lv_mirr)
|
||||
continue;
|
||||
|
||||
if (lv_name) {
|
||||
if (strcmp(lv->name, lv_name) && !sub_lv_of(lv, lv_name))
|
||||
continue;
|
||||
|
101
tools/reporter.c
101
tools/reporter.c
@@ -1055,7 +1055,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
|
||||
goto_out;
|
||||
|
||||
if (!(args->log_only && (single_args->report_type != CMDLOG))) {
|
||||
if (!dm_report_group_push(handle->report_group, report_handle, (void *) single_args->report_name))
|
||||
if (!dm_report_group_push(cmd->cmd_report.report_group, report_handle, (void *) single_args->report_name))
|
||||
goto_out;
|
||||
report_in_group = 1;
|
||||
}
|
||||
@@ -1174,7 +1174,7 @@ static int _do_report(struct cmd_context *cmd, struct processing_handle *handle,
|
||||
unlock_vg(cmd, NULL, VG_GLOBAL);
|
||||
out:
|
||||
if (report_handle) {
|
||||
if (report_in_group && !dm_report_group_pop(handle->report_group))
|
||||
if (report_in_group && !dm_report_group_pop(cmd->cmd_report.report_group))
|
||||
stack;
|
||||
dm_report_free(report_handle);
|
||||
}
|
||||
@@ -1197,7 +1197,7 @@ static int _full_report_single(struct cmd_context *cmd,
|
||||
|
||||
args->full_report_vg = vg;
|
||||
|
||||
if (!args->log_only && !dm_report_group_push(handle->report_group, NULL, NULL))
|
||||
if (!args->log_only && !dm_report_group_push(cmd->cmd_report.report_group, NULL, NULL))
|
||||
goto out;
|
||||
|
||||
if (orphan) {
|
||||
@@ -1213,7 +1213,7 @@ static int _full_report_single(struct cmd_context *cmd,
|
||||
stack;
|
||||
}
|
||||
|
||||
if (!args->log_only && !dm_report_group_pop(handle->report_group))
|
||||
if (!args->log_only && !dm_report_group_pop(cmd->cmd_report.report_group))
|
||||
goto_out;
|
||||
out:
|
||||
args->full_report_vg = NULL;
|
||||
@@ -1367,15 +1367,15 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t
|
||||
handle->internal_report_for_select = 0;
|
||||
handle->include_historical_lvs = cmd->include_historical_lvs;
|
||||
|
||||
args.report_group_type = handle->report_group_type;
|
||||
args.log_only = handle->log_only;
|
||||
args.report_group_type = cmd->cmd_report.report_group_type;
|
||||
args.log_only = cmd->cmd_report.log_only;
|
||||
|
||||
if (!_config_report(cmd, &args, single_args)) {
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return_ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!args.log_only && !dm_report_group_push(handle->report_group, NULL, report_name)) {
|
||||
if (!args.log_only && !dm_report_group_push(cmd->cmd_report.report_group, NULL, report_name)) {
|
||||
log_error("Failed to add main report section to report group.");
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return ECMD_FAILED;
|
||||
@@ -1387,6 +1387,11 @@ static int _report(struct cmd_context *cmd, int argc, char **argv, report_type_t
|
||||
} else
|
||||
r = _do_report(cmd, handle, &args, single_args);
|
||||
|
||||
if (!args.log_only && !dm_report_group_pop(cmd->cmd_report.report_group)) {
|
||||
log_error("Failed to finalize main report section in report group.");
|
||||
r = ECMD_FAILED;
|
||||
}
|
||||
|
||||
destroy_processing_handle(cmd, handle);
|
||||
return r;
|
||||
}
|
||||
@@ -1433,9 +1438,7 @@ int devtypes(struct cmd_context *cmd, int argc, char **argv)
|
||||
#define REPORT_FORMAT_NAME_BASIC "basic"
|
||||
#define REPORT_FORMAT_NAME_JSON "json"
|
||||
|
||||
int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_group_type,
|
||||
struct dm_report_group **report_group, struct dm_report **log_rh,
|
||||
int *log_only, log_report_t *saved_log_report_state)
|
||||
int report_format_init(struct cmd_context *cmd)
|
||||
{
|
||||
int config_set = find_config_tree_node(cmd, report_output_format_CFG, NULL) != NULL;
|
||||
const char *config_format_str = find_config_tree_str(cmd, report_output_format_CFG, NULL);
|
||||
@@ -1446,7 +1449,7 @@ int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_g
|
||||
struct dm_report_group *new_report_group;
|
||||
struct dm_report *tmp_log_rh = NULL;
|
||||
|
||||
args.log_only = arg_is_set(cmd, logonly_ARG) || *log_rh;
|
||||
args.log_only = arg_is_set(cmd, logonly_ARG);
|
||||
report_command_log = args.log_only || find_config_tree_bool(cmd, log_report_command_log_CFG, NULL);
|
||||
|
||||
if (!format_str || !strcmp(format_str, REPORT_FORMAT_NAME_BASIC)) {
|
||||
@@ -1462,10 +1465,8 @@ int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_g
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (report_group_type)
|
||||
*report_group_type = args.report_group_type;
|
||||
if (log_only)
|
||||
*log_only = args.log_only;
|
||||
cmd->cmd_report.report_group_type = args.report_group_type;
|
||||
cmd->cmd_report.log_only = args.log_only;
|
||||
|
||||
if (!(new_report_group = dm_report_group_create(args.report_group_type, NULL))) {
|
||||
log_error("Failed to create report group.");
|
||||
@@ -1476,40 +1477,33 @@ int report_format_init(struct cmd_context *cmd, dm_report_group_type_t *report_g
|
||||
single_args = &args.single_args[REPORT_IDX_LOG];
|
||||
single_args->report_type = CMDLOG;
|
||||
|
||||
if (!*log_rh) {
|
||||
if (!_config_report(cmd, &args, single_args))
|
||||
goto_bad;
|
||||
if (!_config_report(cmd, &args, single_args))
|
||||
goto_bad;
|
||||
|
||||
if (!(tmp_log_rh = report_init(NULL, single_args->options, single_args->keys, &single_args->report_type,
|
||||
args.separator, args.aligned, args.buffered, args.headings,
|
||||
args.field_prefixes, args.quoted, args.columns_as_rows,
|
||||
single_args->selection, 1))) {
|
||||
log_error("Failed to create log report.");
|
||||
goto bad;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* We reusing existing log report handle.
|
||||
* Just get report's name and prefix now.
|
||||
*/
|
||||
if (!_set_report_prefix_and_name(&args, single_args))
|
||||
goto_bad;
|
||||
if (!(tmp_log_rh = report_init(NULL, single_args->options, single_args->keys, &single_args->report_type,
|
||||
args.separator, args.aligned, args.buffered, args.headings,
|
||||
args.field_prefixes, args.quoted, args.columns_as_rows,
|
||||
single_args->selection, 1))) {
|
||||
log_error("Failed to create log report.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (!(dm_report_group_push(new_report_group, tmp_log_rh ? : *log_rh, (void *) single_args->report_name))) {
|
||||
if (!(dm_report_group_push(new_report_group, tmp_log_rh, (void *) single_args->report_name))) {
|
||||
log_error("Failed to add log report to report group.");
|
||||
goto bad;
|
||||
}
|
||||
|
||||
cmd->cmd_report.log_rh = tmp_log_rh;
|
||||
if (!(cmd->cmd_report.log_name = dm_pool_strdup(cmd->libmem, single_args->report_name))) {
|
||||
log_error("Failed to set log report name for command context.");
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
|
||||
*report_group = new_report_group;
|
||||
if (tmp_log_rh)
|
||||
*log_rh = tmp_log_rh;
|
||||
cmd->cmd_report.report_group = new_report_group;
|
||||
cmd->cmd_report.saved_log_report_state = log_get_report_state();
|
||||
log_set_report(cmd->cmd_report.log_rh);
|
||||
|
||||
if (saved_log_report_state) {
|
||||
*saved_log_report_state = log_get_report_state();
|
||||
log_set_report(*log_rh);
|
||||
}
|
||||
return 1;
|
||||
bad:
|
||||
if (!dm_report_group_destroy(new_report_group))
|
||||
@@ -1519,35 +1513,22 @@ bad:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lastlog(struct cmd_context *cmd, int argc, char **argv)
|
||||
int lastlog(struct cmd_context *cmd, int argc __attribute((unused)), char **argv __attribute__((unused)))
|
||||
{
|
||||
struct dm_report_group *report_group = NULL;
|
||||
const char *selection;
|
||||
int r = ECMD_FAILED;
|
||||
|
||||
if (!cmd->log_rh) {
|
||||
if (!cmd->cmd_report.log_rh) {
|
||||
log_error("No log report stored.");
|
||||
goto out;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!report_format_init(cmd, NULL, &report_group, &cmd->log_rh, NULL, NULL))
|
||||
goto_out;
|
||||
|
||||
if (!_do_report_get_selection(cmd, CMDLOG, 1, NULL, &selection))
|
||||
goto_out;
|
||||
return_ECMD_FAILED;
|
||||
|
||||
if (!dm_report_set_selection(cmd->log_rh, selection)) {
|
||||
if (!dm_report_set_selection(cmd->cmd_report.log_rh, selection)) {
|
||||
log_error("Failed to set selection for log report.");
|
||||
goto out;
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
if (!dm_report_output(cmd->log_rh) ||
|
||||
!dm_report_group_pop(report_group))
|
||||
goto_out;
|
||||
|
||||
r = ECMD_PROCESSED;
|
||||
out:
|
||||
if (!dm_report_group_destroy(report_group))
|
||||
stack;
|
||||
return r;
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
138
tools/toollib.c
138
tools/toollib.c
@@ -1273,18 +1273,34 @@ int get_pool_params(struct cmd_context *cmd,
|
||||
/*
|
||||
* Generic stripe parameter checks.
|
||||
*/
|
||||
static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
|
||||
uint32_t *stripe_size)
|
||||
static int _validate_stripe_params(struct cmd_context *cmd, const struct segment_type *segtype,
|
||||
uint32_t *stripes, uint32_t *stripe_size)
|
||||
{
|
||||
if (*stripes == 1 && *stripe_size) {
|
||||
log_print_unless_silent("Ignoring stripesize argument with single stripe.");
|
||||
int stripe_size_required = segtype_supports_stripe_size(segtype);
|
||||
|
||||
if (!stripe_size_required && *stripe_size) {
|
||||
log_print_unless_silent("Ignoring stripesize argument for %s devices.", segtype->name);
|
||||
*stripe_size = 0;
|
||||
} else if (*stripes == 1 && (segtype_is_striped(segtype) || segtype_is_mirror(segtype))) {
|
||||
stripe_size_required = 0;
|
||||
if (*stripe_size) {
|
||||
log_print_unless_silent("Ignoring stripesize argument with single stripe.");
|
||||
*stripe_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (*stripes > 1 && !*stripe_size) {
|
||||
*stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
|
||||
log_print_unless_silent("Using default stripesize %s.",
|
||||
display_size(cmd, (uint64_t) *stripe_size));
|
||||
if (stripe_size_required) {
|
||||
if (!*stripe_size) {
|
||||
*stripe_size = find_config_tree_int(cmd, metadata_stripesize_CFG, NULL) * 2;
|
||||
log_print_unless_silent("Using default stripesize %s.",
|
||||
display_size(cmd, (uint64_t) *stripe_size));
|
||||
}
|
||||
|
||||
if (*stripe_size < STRIPE_SIZE_MIN || !is_power_of_2(*stripe_size)) {
|
||||
log_error("Invalid stripe size %s.",
|
||||
display_size(cmd, (uint64_t) *stripe_size));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (*stripes < 1 || *stripes > MAX_STRIPES) {
|
||||
@@ -1293,13 +1309,6 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*stripes > 1 && (*stripe_size < STRIPE_SIZE_MIN ||
|
||||
!is_power_of_2(*stripe_size))) {
|
||||
log_error("Invalid stripe size %s.",
|
||||
display_size(cmd, (uint64_t) *stripe_size));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1309,9 +1318,10 @@ static int _validate_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
|
||||
* power of 2, we must divide UINT_MAX by four and add 1 (to round it
|
||||
* up to the power of 2)
|
||||
*/
|
||||
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stripe_size)
|
||||
int get_stripe_params(struct cmd_context *cmd, const struct segment_type *segtype, uint32_t *stripes, uint32_t *stripe_size)
|
||||
{
|
||||
/* stripes_long_ARG takes precedence (for lvconvert) */
|
||||
/* FIXME Cope with relative +/- changes for lvconvert. */
|
||||
*stripes = arg_uint_value(cmd, arg_is_set(cmd, stripes_long_ARG) ? stripes_long_ARG : stripes_ARG, 1);
|
||||
|
||||
*stripe_size = arg_uint_value(cmd, stripesize_ARG, 0);
|
||||
@@ -1328,7 +1338,7 @@ int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes, uint32_t *stri
|
||||
}
|
||||
}
|
||||
|
||||
return _validate_stripe_params(cmd, stripes, stripe_size);
|
||||
return _validate_stripe_params(cmd, segtype, stripes, stripe_size);
|
||||
}
|
||||
|
||||
static int _validate_cachepool_params(const char *name,
|
||||
@@ -1746,15 +1756,13 @@ struct processing_handle *init_processing_handle(struct cmd_context *cmd, struct
|
||||
handle->internal_report_for_select = arg_is_set(cmd, select_ARG);
|
||||
handle->include_historical_lvs = cmd->include_historical_lvs;
|
||||
|
||||
if (!parent_handle) {
|
||||
if (!report_format_init(cmd, &handle->report_group_type, &handle->report_group,
|
||||
&handle->log_rh, &handle->log_only,
|
||||
&handle->saved_log_report_state)) {
|
||||
if (!parent_handle && !cmd->cmd_report.report_group) {
|
||||
if (!report_format_init(cmd)) {
|
||||
dm_pool_free(cmd->mem, handle);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
handle->saved_log_report_state = log_get_report_state();
|
||||
cmd->cmd_report.saved_log_report_state = log_get_report_state();
|
||||
|
||||
log_set_report_context(LOG_REPORT_CONTEXT_PROCESSING);
|
||||
return handle;
|
||||
@@ -1790,19 +1798,17 @@ void destroy_processing_handle(struct cmd_context *cmd, struct processing_handle
|
||||
if (handle->selection_handle && handle->selection_handle->selection_rh)
|
||||
dm_report_free(handle->selection_handle->selection_rh);
|
||||
|
||||
log_restore_report_state(handle->saved_log_report_state);
|
||||
log_restore_report_state(cmd->cmd_report.saved_log_report_state);
|
||||
|
||||
if (!dm_report_group_destroy(handle->report_group))
|
||||
stack;
|
||||
if (handle->log_rh) {
|
||||
if (cmd->is_interactive) {
|
||||
/*
|
||||
* Keep log report if we're interactive so
|
||||
* we can do further queries on this report.
|
||||
*/
|
||||
cmd->log_rh = handle->log_rh;
|
||||
} else
|
||||
dm_report_free(handle->log_rh);
|
||||
if (!cmd->is_interactive) {
|
||||
if (!dm_report_group_destroy(cmd->cmd_report.report_group))
|
||||
stack;
|
||||
cmd->cmd_report.report_group = NULL;
|
||||
|
||||
if (cmd->cmd_report.log_rh) {
|
||||
dm_report_free(cmd->cmd_report.log_rh);
|
||||
cmd->cmd_report.log_rh = NULL;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* TODO: think about better alternatives:
|
||||
@@ -2340,8 +2346,12 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
struct dm_str_list *sl;
|
||||
struct dm_list final_lvs;
|
||||
struct lv_list *final_lvl;
|
||||
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);
|
||||
|
||||
@@ -2350,6 +2360,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
stack;
|
||||
|
||||
dm_list_init(&final_lvs);
|
||||
dm_list_init(&found_arg_lvnames);
|
||||
|
||||
if (!vg_check_status(vg, EXPORTED_VG)) {
|
||||
ret_max = ECMD_FAILED;
|
||||
@@ -2443,6 +2454,7 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
if (lvargs_supplied && str_list_match_item(arg_lvnames, lvl->lv->name)) {
|
||||
/* Remove LV from list of unprocessed LV names */
|
||||
str_list_del(arg_lvnames, lvl->lv->name);
|
||||
str_list_add(cmd->mem, &found_arg_lvnames, lvl->lv->name);
|
||||
process_lv = 1;
|
||||
}
|
||||
|
||||
@@ -2490,6 +2502,64 @@ int process_each_lv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
|
||||
if (lv_is_removed(lvl->lv))
|
||||
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.)
|
||||
*/
|
||||
|
||||
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) {
|
||||
|
||||
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 on LV %s with type %s.", display_lvname(lv), seg->segtype->name);
|
||||
ret_max = ECMD_FAILED;
|
||||
} else {
|
||||
log_warn("Operation not permitted on LV %s with type %s.", display_lvname(lv), seg->segtype->name);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log_very_verbose("Processing LV %s in VG %s.", lvl->lv->name, vg->name);
|
||||
|
||||
ret = process_single_lv(cmd, lvl->lv, handle);
|
||||
|
@@ -73,11 +73,6 @@ struct processing_handle {
|
||||
int internal_report_for_select;
|
||||
int include_historical_lvs;
|
||||
struct selection_handle *selection_handle;
|
||||
dm_report_group_type_t report_group_type;
|
||||
struct dm_report_group *report_group;
|
||||
struct dm_report *log_rh;
|
||||
int log_only;
|
||||
log_report_t saved_log_report_state;
|
||||
void *custom_handle;
|
||||
};
|
||||
|
||||
@@ -201,8 +196,8 @@ int get_pool_params(struct cmd_context *cmd,
|
||||
thin_discards_t *discards,
|
||||
int *zero);
|
||||
|
||||
int get_stripe_params(struct cmd_context *cmd, uint32_t *stripes,
|
||||
uint32_t *stripe_size);
|
||||
int get_stripe_params(struct cmd_context *cmd, const struct segment_type *segtype,
|
||||
uint32_t *stripes, uint32_t *stripe_size);
|
||||
|
||||
int get_cache_params(struct cmd_context *cmd,
|
||||
cache_mode_t *cache_mode,
|
||||
|
@@ -50,20 +50,27 @@
|
||||
#define CMD_LEN 256
|
||||
#define MAX_ARGS 64
|
||||
|
||||
/* command functions */
|
||||
typedef int (*command_fn) (struct cmd_context * cmd, int argc, char **argv);
|
||||
/* define the enums for the values accepted by command line --options */
|
||||
enum {
|
||||
#define val(a, b, c, d) a ,
|
||||
#include "vals.h"
|
||||
#undef val
|
||||
};
|
||||
|
||||
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
|
||||
/* define the enums for the command line switches */
|
||||
/* define the enums for the command line --options */
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
};
|
||||
|
||||
/* command functions */
|
||||
#define xx(a, b...) int a(struct cmd_context *cmd, int argc, char **argv);
|
||||
#include "commands.h"
|
||||
#undef xx
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#define ARG_COUNTABLE 0x00000001 /* E.g. -vvvv */
|
||||
#define ARG_GROUPABLE 0x00000002 /* E.g. --addtag */
|
||||
|
||||
@@ -79,13 +86,13 @@ struct arg_values {
|
||||
/* void *ptr; // Currently not used. */
|
||||
};
|
||||
|
||||
/* a global table of possible arguments */
|
||||
/* a global table of possible --option's */
|
||||
struct arg_props {
|
||||
int arg_enum; /* foo_ARG from args.h */
|
||||
const char short_arg;
|
||||
char _padding[7];
|
||||
const char *long_arg;
|
||||
|
||||
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
|
||||
int val_enum; /* foo_VAL from vals.h */
|
||||
uint32_t flags;
|
||||
uint32_t prio;
|
||||
};
|
||||
@@ -96,6 +103,14 @@ struct arg_value_group_list {
|
||||
uint32_t prio;
|
||||
};
|
||||
|
||||
/* a global table of possible --option values */
|
||||
struct val_props {
|
||||
int val_enum; /* foo_VAL from vals.h */
|
||||
int (*fn) (struct cmd_context *cmd, struct arg_values *av);
|
||||
const char *name;
|
||||
const char *usage;
|
||||
};
|
||||
|
||||
#define CACHE_VGMETADATA 0x00000001
|
||||
#define PERMITTED_READ_ONLY 0x00000002
|
||||
/* Process all VGs if none specified on the command line. */
|
||||
@@ -118,19 +133,6 @@ struct arg_value_group_list {
|
||||
#define ENABLE_DUPLICATE_DEVS 0x00000400
|
||||
/* Command does not accept tags as args. */
|
||||
#define DISALLOW_TAG_ARGS 0x00000800
|
||||
|
||||
/* a register of the lvm commands */
|
||||
struct command {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
const char *usage;
|
||||
command_fn fn;
|
||||
|
||||
unsigned flags;
|
||||
|
||||
int num_args;
|
||||
int *valid_args;
|
||||
};
|
||||
|
||||
void usage(const char *name);
|
||||
|
||||
|
135
tools/vals.h
Normal file
135
tools/vals.h
Normal file
@@ -0,0 +1,135 @@
|
||||
|
||||
/*
|
||||
* Define value types which describe values accepted
|
||||
* by the --option's in args.h, and can also describe
|
||||
* the values accepted as positional args.
|
||||
*
|
||||
* Previously, accepted values were only "described"
|
||||
* by identifying the parsing function to use.
|
||||
*
|
||||
* Some standard val types are used by many options,
|
||||
* e.g. many options (aa_ARG, bb_ARG, cc_ARG) all
|
||||
* accept a number_VAL.
|
||||
*
|
||||
* Other special val types are used by only one option,
|
||||
* e.g. only mirrorlog_ARG accepts a mirrorlog_VAL.
|
||||
* This typically means that there are some specific
|
||||
* words that are recognized after the option.
|
||||
*
|
||||
* Some options currently take a standard val type,
|
||||
* (esp string_VAL), but they could be given their
|
||||
* own custom val type. The advantage of using a
|
||||
* custom val type is the possibility of validating
|
||||
* the value when parsing it with a custom parsing
|
||||
* function, and the possibility of displaying the
|
||||
* actual accepted values in the command usage.
|
||||
* Without a custom val type, the code must do ad hoc
|
||||
* validation of the string values, and the usage
|
||||
* output for the option will only say "String"
|
||||
* rather than giving the accepted string values.
|
||||
* Even without a custom parsing function, there is
|
||||
* reason to define a custom x_VAL enum so that a
|
||||
* more descriptive usage string can be specified
|
||||
* as opposed to just "String".
|
||||
*
|
||||
* Most of the val types defined here are used after
|
||||
* --option's, and are referenced in foo_ARG entries
|
||||
* in args.h. But, some val types are only used to
|
||||
* represent positional values in command definitions,
|
||||
* e.g. vg_VAL.
|
||||
*
|
||||
* val(a, b, c, d)
|
||||
*
|
||||
* a: foo_VAL enums
|
||||
* b: the function to parse and set the value
|
||||
* c: the name used to reference this value in command defs
|
||||
* d: what to display in usage output for this value
|
||||
*
|
||||
* command defintions will use --option NAME, where NAME
|
||||
* is shown in val() field c. NAME will be translated to
|
||||
* foo_VAL enum in field a, which is used in commands[]
|
||||
* structs.
|
||||
*
|
||||
* option definitions (arg.h) will reference foo_VAL enum
|
||||
* in field a.
|
||||
*
|
||||
* FIXME: for specialized val types, the set of recognized
|
||||
* 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.
|
||||
*
|
||||
* The usage text for an option is not always the full
|
||||
* set of words accepted for an option, but may be a
|
||||
* subset. i.e. an outdated word that no longer does
|
||||
* anything may not be shown, but may still be recognized
|
||||
* and ignored, or an option that shouldn't be used in
|
||||
* general isn't shown to avoid suggesting it.
|
||||
* e.g. for --activate we show the most common "y|n|ay"
|
||||
* without showing the lvmlockd variations "ey|sy" which
|
||||
* are not applicable in general.
|
||||
*
|
||||
* FIXME: are there some specialized or irrelevant
|
||||
* options included in the usage text below that should
|
||||
* be removed? Should "lvm1" be removed?
|
||||
*
|
||||
* For Number args that take optional units, a full usage
|
||||
* could be "Number[bBsSkKmMgGtTpPeE]" (with implied |),
|
||||
* but repeating this full specification produces cluttered
|
||||
* output, and doesn't indicate which unit is the default.
|
||||
* "Number[units]" would be cleaner, as would a subset of
|
||||
* common units, e.g. "Number[kmg...]", but neither helps
|
||||
* with default. "Number[k|unit]" and "Number[m|unit]" show
|
||||
* the default, and "unit" indicates that other units
|
||||
* are possible without listing them all. This also
|
||||
* suggests using the preferred lower case letters, because
|
||||
* --size and other option args treat upper/lower letters
|
||||
* the same, all as 1024 SI base. For this reason, we
|
||||
* 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(bool_VAL, yes_no_arg, "Bool", "y|n")
|
||||
val(number_VAL, int_arg, "Number", NULL)
|
||||
val(string_VAL, string_arg, "String", NULL)
|
||||
val(vg_VAL, string_arg, "VG", NULL)
|
||||
val(lv_VAL, string_arg, "LV", NULL)
|
||||
val(pv_VAL, string_arg, "PV", NULL)
|
||||
val(tag_VAL, tag_arg, "Tag", NULL)
|
||||
val(select_VAL, NULL, "Select", NULL) /* used only for command defs */
|
||||
val(activationmode_VAL, string_arg, "ActivationMode", "partial|degraded|complete")
|
||||
val(activation_VAL, activation_arg, "Active", "y|n|ay")
|
||||
val(cachemode_VAL, cachemode_arg, "CacheMode", "writethrough|writeback")
|
||||
val(discards_VAL, discards_arg, "Discards", "passdown|nopassdown|ignore")
|
||||
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(permission_VAL, permission_arg, "Permission", "rw|r")
|
||||
val(metadatatype_VAL, metadatatype_arg, "MetadataType", "lvm2|lvm1")
|
||||
val(units_VAL, string_arg, "Units", "hHbBsSkKmMgGtTpPeE")
|
||||
val(segtype_VAL, segtype_arg, "SegType", "linear|striped|snapshot|mirror|raid*|thin|cache|thin-pool|cache-pool")
|
||||
val(alloc_VAL, alloc_arg, "Alloc", "contiguous|cling|cling_by_tags|normal|anywhere|inherit")
|
||||
val(locktype_VAL, locktype_arg, "LockType", "sanlock|dlm|none")
|
||||
val(readahead_VAL, readahead_arg, "Readahead", "auto|none|NumberSectors")
|
||||
val(metadatacopies_VAL, metadatacopies_arg, "MetadataCopies", "all|unmanaged|Number")
|
||||
|
||||
/* this should always be last */
|
||||
val(VAL_COUNT, NULL, NULL, NULL)
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
@@ -331,7 +331,7 @@ static int _move_thins(struct volume_group *vg_from,
|
||||
data_lv = seg_lv(first_seg(seg->pool_lv), 0);
|
||||
|
||||
/* Ignore, if no allocations on PVs of @vg_to */
|
||||
if (!lv_is_on_pvs(data_lv, &vg_to->pvs) ||
|
||||
if (!lv_is_on_pvs(data_lv, &vg_to->pvs) &&
|
||||
(seg->external_lv && !lv_is_on_pvs(seg->external_lv, &vg_to->pvs)))
|
||||
continue;
|
||||
|
||||
|
Reference in New Issue
Block a user