mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-06 11:33:14 +03:00
Compare commits
89 Commits
v2_02_162
...
dev-lvmguy
Author | SHA1 | Date | |
---|---|---|---|
|
c6d7cd1489 | ||
|
eec8bd228c | ||
|
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 {
|
||||
@@ -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);
|
||||
|
||||
|
@@ -38,9 +38,6 @@ typedef enum {
|
||||
NEXT_AREA
|
||||
} area_use_t;
|
||||
|
||||
/* FIXME: remove RAID_METADATA_AREA_LEN macro after defining 'raid_log_extents'*/
|
||||
#define RAID_METADATA_AREA_LEN 1
|
||||
|
||||
/* FIXME These ended up getting used differently from first intended. Refactor. */
|
||||
/* Only one of A_CONTIGUOUS_TO_LVSEG, A_CLING_TO_LVSEG, A_CLING_TO_ALLOCED may be set */
|
||||
#define A_CONTIGUOUS_TO_LVSEG 0x01 /* Must be contiguous to an existing segment */
|
||||
@@ -119,6 +116,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 +167,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,
|
||||
@@ -876,22 +875,38 @@ dm_percent_t copy_percent(const struct logical_volume *lv)
|
||||
return denominator ? dm_make_percent(numerator, denominator) : DM_PERCENT_100;
|
||||
}
|
||||
|
||||
/* Round up extents to next stripe boundary for number of stripes */
|
||||
static uint32_t _round_to_stripe_boundary(struct volume_group *vg, uint32_t extents,
|
||||
uint32_t stripes, int extend)
|
||||
/*
|
||||
* Round up @extents to next stripe boundary number of
|
||||
* @stripes (if any) and/or to next RAID io boundary.
|
||||
*/
|
||||
uint32_t extents_round_to_boundary(struct volume_group *vg,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t extents,
|
||||
uint32_t stripes,
|
||||
int extend)
|
||||
{
|
||||
int ensure_raid_min = segtype_is_raid(segtype);
|
||||
uint32_t size_rest, new_extents = extents;
|
||||
|
||||
if (!stripes)
|
||||
return extents;
|
||||
do {
|
||||
/* Round up extents to stripe divisible amount if given @stripes */
|
||||
if (stripes > 1 && (size_rest = new_extents % stripes))
|
||||
new_extents += extend ? stripes - size_rest : -size_rest;
|
||||
|
||||
/* Round up extents to stripe divisible amount */
|
||||
if ((size_rest = extents % stripes)) {
|
||||
new_extents += extend ? stripes - size_rest : -size_rest;
|
||||
log_print_unless_silent("Rounding size %s (%d extents) up to stripe boundary size %s (%d extents).",
|
||||
if (ensure_raid_min) {
|
||||
/* Require multiples of 64 KiB to not fail in kernel RAID page size IO */
|
||||
if ((new_extents * vg->extent_size) % ((stripes ?: 1) * RAID_ALLOC_CHUNK_SECTORS))
|
||||
extend ? new_extents++ : new_extents--;
|
||||
else
|
||||
ensure_raid_min = 0;
|
||||
}
|
||||
} while (ensure_raid_min);
|
||||
|
||||
if (extents != new_extents)
|
||||
log_print_unless_silent("Rounding size %s (%d extents) up to %s i/o boundary size %s (%d extents).",
|
||||
display_size(vg->cmd, (uint64_t) extents * vg->extent_size), extents,
|
||||
segtype_is_raid(segtype) ? (stripes > 1 ? "stripe/RAID" : "RAID") : "stripe",
|
||||
display_size(vg->cmd, (uint64_t) new_extents * vg->extent_size), new_extents);
|
||||
}
|
||||
|
||||
return new_extents;
|
||||
}
|
||||
@@ -1254,7 +1269,7 @@ static int _lv_segment_reduce(struct lv_segment *seg, uint32_t reduction)
|
||||
*/
|
||||
static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
|
||||
{
|
||||
struct lv_segment *seg;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
uint32_t count = extents;
|
||||
uint32_t reduction;
|
||||
struct logical_volume *pool_lv;
|
||||
@@ -1265,6 +1280,9 @@ static int _lv_reduce(struct logical_volume *lv, uint32_t extents, int delete)
|
||||
clear_snapshot_merge(lv);
|
||||
}
|
||||
|
||||
if (!delete && seg)
|
||||
extents = extents_round_to_boundary(lv->vg, seg->segtype, extents, seg->area_count - seg->segtype->parity_devs, 0);
|
||||
|
||||
dm_list_iterate_back_items(seg, &lv->segments) {
|
||||
if (!count)
|
||||
break;
|
||||
@@ -1579,11 +1597,12 @@ static uint32_t _mirror_log_extents(uint32_t region_size, uint32_t pe_size, uint
|
||||
|
||||
/* Is there enough total space or should we give up immediately? */
|
||||
static int _sufficient_pes_free(struct alloc_handle *ah, struct dm_list *pvms,
|
||||
uint32_t allocated, uint32_t extents_still_needed)
|
||||
uint32_t allocated, uint32_t extents_still_needed,
|
||||
uint32_t extent_size)
|
||||
{
|
||||
uint32_t area_extents_needed = (extents_still_needed - allocated) * ah->area_count / ah->area_multiple;
|
||||
uint32_t parity_extents_needed = (extents_still_needed - allocated) * ah->parity_count / ah->area_multiple;
|
||||
uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * RAID_METADATA_AREA_LEN; /* One each */
|
||||
uint32_t metadata_extents_needed = ah->alloc_and_split_meta ? 0 : ah->metadata_area_count * lv_raid_metadata_area_len(extent_size);
|
||||
uint32_t total_extents_needed = area_extents_needed + parity_extents_needed + metadata_extents_needed;
|
||||
uint32_t free_pes = pv_maps_size(pvms);
|
||||
|
||||
@@ -3040,7 +3059,7 @@ static int _allocate(struct alloc_handle *ah,
|
||||
old_allocated = alloc_state.allocated;
|
||||
log_debug_alloc("Trying allocation using %s policy.", get_alloc_string(alloc));
|
||||
|
||||
if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents))
|
||||
if (!ah->approx_alloc && !_sufficient_pes_free(ah, pvms, alloc_state.allocated, ah->new_extents, vg->extent_size))
|
||||
goto_out;
|
||||
|
||||
_init_alloc_parms(ah, &alloc_parms, alloc, prev_lvseg,
|
||||
@@ -3233,7 +3252,7 @@ static struct alloc_handle *_alloc_init(struct cmd_context *cmd,
|
||||
ah->metadata_area_count = area_count;
|
||||
ah->alloc_and_split_meta = 1;
|
||||
|
||||
ah->log_len = RAID_METADATA_AREA_LEN;
|
||||
ah->log_len = existing_extents ? 0 : lv_raid_metadata_area_len(extent_size);
|
||||
|
||||
/*
|
||||
* We need 'log_len' extents for each
|
||||
@@ -3279,7 +3298,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)
|
||||
@@ -3936,6 +3955,35 @@ static int _lv_extend_layered_lv(struct alloc_handle *ah,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return maximum number of extents for size of MetaLV of RaidLV @lv with bitmap */
|
||||
#define RAID_HEADER_SIZE (2 * 4096) /* dm-raid superblock and bitmap superblock */
|
||||
static uint32_t _max_raid_extents(struct logical_volume *lv)
|
||||
{
|
||||
uint64_t max_image_size;
|
||||
uint64_t mlv_bytes; /* dm-raid superblock and bitmap superblock */
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
struct logical_volume *mlv;
|
||||
|
||||
if (!seg ||
|
||||
!seg_is_raid(seg) ||
|
||||
!seg->meta_areas ||
|
||||
!(mlv = seg_metalv(seg, 0)) ||
|
||||
!seg->region_size)
|
||||
return ~0U;
|
||||
|
||||
mlv_bytes = (mlv->le_count * lv->vg->extent_size) << SECTOR_SHIFT;
|
||||
if (mlv_bytes < RAID_HEADER_SIZE) {
|
||||
log_error("Metadata LV %s too small to even hold the RAID headers",
|
||||
display_lvname(mlv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subtract space for 2 headers (superblock and bitmap) */
|
||||
max_image_size = (mlv_bytes - RAID_HEADER_SIZE) * 8 * seg->region_size;
|
||||
|
||||
return max_image_size / lv->vg->extent_size * (seg_is_raid1(seg) ? 1 : seg->area_count - seg->segtype->parity_devs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Entry point for single-step LV allocation + extension.
|
||||
* Extents is the number of logical extents to append to the LV unless
|
||||
@@ -3980,6 +4028,8 @@ int lv_extend(struct logical_volume *lv,
|
||||
}
|
||||
/* FIXME log_count should be 1 for mirrors */
|
||||
|
||||
extents = extents_round_to_boundary(lv->vg, segtype, extents, stripes, 1);
|
||||
|
||||
if (!(ah = allocate_extents(lv->vg, lv, segtype, stripes, mirrors,
|
||||
log_count, region_size, extents,
|
||||
allocatable_pvs, alloc, approx_alloc, NULL)))
|
||||
@@ -3997,6 +4047,8 @@ int lv_extend(struct logical_volume *lv,
|
||||
stripe_size, 0u, 0)))
|
||||
stack;
|
||||
} else {
|
||||
uint32_t max_extents;
|
||||
|
||||
/*
|
||||
* For RAID, all the devices are AREA_LV.
|
||||
* However, for 'mirror on stripe' using non-RAID targets,
|
||||
@@ -4021,6 +4073,14 @@ int lv_extend(struct logical_volume *lv,
|
||||
stripes, stripe_size)))
|
||||
goto_out;
|
||||
|
||||
if ((max_extents = _max_raid_extents(lv)) < lv->le_count) {
|
||||
log_error("Can't extend LV %s larger than %s because of MetaLV size",
|
||||
display_lvname(lv),
|
||||
display_size(lv->vg->cmd, max_extents * lv->vg->extent_size));
|
||||
r = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are expanding an existing mirror, we can skip the
|
||||
* resync of the extension if the LV is currently in-sync
|
||||
@@ -7082,29 +7142,7 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
|
||||
}
|
||||
}
|
||||
|
||||
if (lp->stripe_size > vg->extent_size) {
|
||||
if (seg_is_raid(lp) && (vg->extent_size < STRIPE_SIZE_MIN)) {
|
||||
/*
|
||||
* FIXME: RAID will simply fail to load the table if
|
||||
* this is the case, but we should probably
|
||||
* honor the stripe minimum for regular stripe
|
||||
* volumes as well. Avoiding doing that now
|
||||
* only to minimize the change.
|
||||
*/
|
||||
log_error("The extent size in volume group %s is too "
|
||||
"small to support striped RAID volumes.",
|
||||
vg->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
log_print_unless_silent("Reducing requested stripe size %s to maximum, "
|
||||
"physical extent size %s.",
|
||||
display_size(cmd, (uint64_t) lp->stripe_size),
|
||||
display_size(cmd, (uint64_t) vg->extent_size));
|
||||
lp->stripe_size = vg->extent_size;
|
||||
}
|
||||
|
||||
lp->extents = _round_to_stripe_boundary(vg, lp->extents, lp->stripes, 1);
|
||||
lp->extents = extents_round_to_boundary(vg, lp->segtype, lp->extents, lp->stripes, 1);
|
||||
|
||||
if (!lp->extents && !seg_is_thin_volume(lp)) {
|
||||
log_error(INTERNAL_ERROR "Unable to create new logical volume with no extents.");
|
||||
|
@@ -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) {
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#define MAX_RESTRICTED_LVS 255 /* Used by FMT_RESTRICTED_LVIDS */
|
||||
#define MAX_EXTENT_SIZE ((uint32_t) -1)
|
||||
#define MIN_NON_POWER2_EXTENT_SIZE (128U * 2U) /* 128KB in sectors */
|
||||
#define RAID_ALLOC_CHUNK_SECTORS (64 * 2) /* Allocate RAID in these minimal chunks to ensure page io doesn't fail */
|
||||
|
||||
#define HISTORICAL_LV_PREFIX "-"
|
||||
|
||||
@@ -832,6 +833,12 @@ uint32_t extents_from_percent_size(struct volume_group *vg, const struct dm_list
|
||||
uint32_t extents, int roundup,
|
||||
percent_type_t percent, uint64_t size);
|
||||
|
||||
/* Round @extents to stripe and/or RAID io boundary */
|
||||
uint32_t extents_round_to_boundary(struct volume_group *vg,
|
||||
const struct segment_type *segtype,
|
||||
uint32_t extents, uint32_t stripes,
|
||||
int extend);
|
||||
|
||||
struct logical_volume *find_pool_lv(const struct logical_volume *lv);
|
||||
int pool_is_active(const struct logical_volume *pool_lv);
|
||||
int pool_supports_external_origin(const struct lv_segment *pool_seg, const struct logical_volume *external_lv);
|
||||
@@ -1190,7 +1197,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,12 +1207,16 @@ 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);
|
||||
int partial_raid_lv_supports_degraded_activation(const struct logical_volume *lv);
|
||||
uint32_t lv_raid_metadata_area_len(uint32_t extent_size);
|
||||
/* -- metadata/raid_manip.c */
|
||||
|
||||
/* ++ metadata/cache_manip.c */
|
||||
@@ -1269,6 +1280,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
|
||||
|
@@ -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"
|
||||
|
@@ -88,6 +88,7 @@ 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(raidrebuild_ARG, '\0', "raidrebuild", string_arg, ARG_GROUPABLE, 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)
|
||||
@@ -96,6 +97,7 @@ 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(rebuild_ARG, '\0', "rebuild", string_arg, ARG_GROUPABLE, 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)
|
||||
|
@@ -195,6 +195,7 @@ xx(lvchange,
|
||||
"\t[--activationmode {complete|degraded|partial}"
|
||||
"\t[--addtag <Tag>]\n"
|
||||
"\t[--alloc <AllocationPolicy>]\n"
|
||||
"\t[--rebuild PhysicalVolume]\n"
|
||||
"\t[-C|--contiguous {y|n}]\n"
|
||||
"\t[--cachemode <CacheMode>]\n"
|
||||
"\t[--cachepolicy <policyname>] [--cachesettings <parameter=value>]\n"
|
||||
@@ -244,10 +245,10 @@ xx(lvchange,
|
||||
ignoreskippedcluster_ARG, major_ARG, metadataprofile_ARG, minor_ARG,
|
||||
monitor_ARG, minrecoveryrate_ARG, maxrecoveryrate_ARG, noudevsync_ARG,
|
||||
partial_ARG, permission_ARG, persistent_ARG, poll_ARG,
|
||||
raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG, raidsyncaction_ARG,
|
||||
raidwritebehind_ARG, raidwritemostly_ARG, readahead_ARG, reportformat_ARG,
|
||||
resync_ARG, refresh_ARG, select_ARG, setactivationskip_ARG, syncaction_ARG,
|
||||
sysinit_ARG, test_ARG, writebehind_ARG, writemostly_ARG, zero_ARG)
|
||||
raidrebuild_ARG, raidminrecoveryrate_ARG, raidmaxrecoveryrate_ARG,
|
||||
raidsyncaction_ARG, raidwritebehind_ARG, raidwritemostly_ARG, readahead_ARG,
|
||||
reportformat_ARG, rebuild_ARG, resync_ARG, refresh_ARG, select_ARG, setactivationskip_ARG,
|
||||
syncaction_ARG, sysinit_ARG, test_ARG, writebehind_ARG, writemostly_ARG, zero_ARG)
|
||||
|
||||
#define COMMON_OPTS \
|
||||
"\t[--commandprofile <ProfileName>] [-d|--debug] [-h|-?|--help]\n" \
|
||||
@@ -259,6 +260,7 @@ xx(lvconvert,
|
||||
"lvconvert "
|
||||
"[-m|--mirrors <Mirrors> [--mirrorlog {disk|core|mirrored}|--corelog]]\n"
|
||||
"\t[--type <SegmentType>]\n"
|
||||
"\t[--rebuild PhysicalVolume]\n"
|
||||
"\t[--repair [--use-policies]]\n"
|
||||
"\t[--replace PhysicalVolume]\n"
|
||||
"\t[-R|--regionsize <MirrorLogRegionSize>]\n"
|
||||
|
@@ -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,
|
||||
|
108
tools/lvm.c
108
tools/lvm.c
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -63,12 +63,12 @@ static struct cmdline_context _cmdline;
|
||||
/* Command line args */
|
||||
unsigned arg_count(const struct cmd_context *cmd, int a)
|
||||
{
|
||||
return cmd->arg_values[a].count;
|
||||
return cmd->arg_values ? cmd->arg_values[a].count : 0;
|
||||
}
|
||||
|
||||
unsigned grouped_arg_count(const struct arg_values *av, int a)
|
||||
{
|
||||
return av[a].count;
|
||||
return av ? av[a].count : 0;
|
||||
}
|
||||
|
||||
unsigned arg_is_set(const struct cmd_context *cmd, int a)
|
||||
@@ -182,7 +182,7 @@ const char *arg_long_option_name(int a)
|
||||
|
||||
const char *arg_value(const struct cmd_context *cmd, int a)
|
||||
{
|
||||
return cmd->arg_values[a].value;
|
||||
return cmd->arg_values ? cmd->arg_values[a].value : NULL;
|
||||
}
|
||||
|
||||
const char *arg_str_value(const struct cmd_context *cmd, int a, const char *def)
|
||||
@@ -1167,6 +1167,7 @@ static int _get_settings(struct cmd_context *cmd)
|
||||
!_merge_synonym(cmd, allocation_ARG, resizeable_ARG) ||
|
||||
!_merge_synonym(cmd, virtualoriginsize_ARG, virtualsize_ARG) ||
|
||||
!_merge_synonym(cmd, available_ARG, activate_ARG) ||
|
||||
!_merge_synonym(cmd, raidrebuild_ARG, rebuild_ARG) ||
|
||||
!_merge_synonym(cmd, raidsyncaction_ARG, syncaction_ARG) ||
|
||||
!_merge_synonym(cmd, raidwritemostly_ARG, writemostly_ARG) ||
|
||||
!_merge_synonym(cmd, raidminrecoveryrate_ARG, minrecoveryrate_ARG) ||
|
||||
@@ -1394,6 +1395,7 @@ static int _prepare_profiles(struct cmd_context *cmd)
|
||||
cmd->profile_params->global_metadata_profile = profile;
|
||||
}
|
||||
|
||||
remove_config_tree_by_source(cmd, source);
|
||||
if (!override_config_tree_from_profile(cmd, profile)) {
|
||||
log_error(_failed_to_apply_profile_msg, source_name, name);
|
||||
return 0;
|
||||
@@ -1419,6 +1421,8 @@ static int _prepare_profiles(struct cmd_context *cmd)
|
||||
log_error(_failed_to_add_profile_msg, source_name, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
remove_config_tree_by_source(cmd, CONFIG_PROFILE_COMMAND);
|
||||
if (!override_config_tree_from_profile(cmd, profile)) {
|
||||
log_error(_failed_to_apply_profile_msg, source_name, name);
|
||||
return 0;
|
||||
@@ -1426,6 +1430,9 @@ static int _prepare_profiles(struct cmd_context *cmd)
|
||||
|
||||
log_debug(_setting_global_profile_msg, _command_profile_source_name, profile->name);
|
||||
cmd->profile_params->global_command_profile = profile;
|
||||
|
||||
if (!cmd->arg_values)
|
||||
cmd->profile_params->shell_profile = profile;
|
||||
}
|
||||
|
||||
|
||||
@@ -1437,6 +1444,7 @@ static int _prepare_profiles(struct cmd_context *cmd)
|
||||
log_error(_failed_to_add_profile_msg, source_name, name);
|
||||
return 0;
|
||||
}
|
||||
remove_config_tree_by_source(cmd, CONFIG_PROFILE_METADATA);
|
||||
if (!override_config_tree_from_profile(cmd, profile)) {
|
||||
log_error(_failed_to_apply_profile_msg, source_name, name);
|
||||
return 0;
|
||||
@@ -1733,10 +1741,13 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv)
|
||||
config_profile_metadata_cft = remove_config_tree_by_source(cmd, CONFIG_PROFILE_METADATA);
|
||||
cmd->profile_params->global_metadata_profile = NULL;
|
||||
|
||||
if (config_string_cft || config_profile_command_cft || config_profile_metadata_cft) {
|
||||
if (config_string_cft) {
|
||||
/* Move this? */
|
||||
if (!refresh_toolcontext(cmd))
|
||||
stack;
|
||||
} else if (config_profile_command_cft || config_profile_metadata_cft) {
|
||||
if (!process_profilable_config(cmd))
|
||||
stack;
|
||||
}
|
||||
|
||||
if (ret == EINVALID_CMD_LINE && !cmd->is_interactive)
|
||||
@@ -1834,6 +1845,39 @@ static int _check_standard_fds(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define LVM_OUT_FD_ENV_VAR_NAME "LVM_OUT_FD"
|
||||
#define LVM_ERR_FD_ENV_VAR_NAME "LVM_ERR_FD"
|
||||
#define LVM_REPORT_FD_ENV_VAR_NAME "LVM_REPORT_FD"
|
||||
|
||||
static int _do_get_custom_fd(const char *env_var_name, int *fd)
|
||||
{
|
||||
const char *str;
|
||||
char *endptr;
|
||||
long int tmp_fd;
|
||||
|
||||
*fd = -1;
|
||||
|
||||
if (!(str = getenv(env_var_name)))
|
||||
return 1;
|
||||
|
||||
errno = 0;
|
||||
tmp_fd = strtol(str, &endptr, 10);
|
||||
if (errno || *endptr || (tmp_fd < 0) || (tmp_fd > INT_MAX)) {
|
||||
log_error("%s: invalid file descriptor.", env_var_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*fd = tmp_fd;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _get_custom_fds(struct custom_fds *custom_fds)
|
||||
{
|
||||
return _do_get_custom_fd(LVM_OUT_FD_ENV_VAR_NAME, &custom_fds->out) &&
|
||||
_do_get_custom_fd(LVM_ERR_FD_ENV_VAR_NAME, &custom_fds->err) &&
|
||||
_do_get_custom_fd(LVM_REPORT_FD_ENV_VAR_NAME, &custom_fds->report);
|
||||
}
|
||||
|
||||
static const char *_get_cmdline(pid_t pid)
|
||||
{
|
||||
static char _proc_cmdline[32];
|
||||
@@ -1901,7 +1945,7 @@ static void _close_descriptor(int fd, unsigned suppress_warnings,
|
||||
fprintf(stderr, " Parent PID %" PRIpid_t ": %s\n", ppid, parent_cmdline);
|
||||
}
|
||||
|
||||
static int _close_stray_fds(const char *command)
|
||||
static int _close_stray_fds(const char *command, struct custom_fds *custom_fds)
|
||||
{
|
||||
#ifndef VALGRIND_POOL
|
||||
struct rlimit rlim;
|
||||
@@ -1935,17 +1979,27 @@ static int _close_stray_fds(const char *command)
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (fd = 3; fd < (int)rlim.rlim_cur; fd++)
|
||||
_close_descriptor(fd, suppress_warnings, command, ppid,
|
||||
parent_cmdline);
|
||||
for (fd = 3; fd < (int)rlim.rlim_cur; fd++) {
|
||||
if ((fd != custom_fds->out) &&
|
||||
(fd != custom_fds->err) &&
|
||||
(fd != custom_fds->report)) {
|
||||
_close_descriptor(fd, suppress_warnings, command, ppid,
|
||||
parent_cmdline);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
while ((dirent = readdir(d))) {
|
||||
fd = atoi(dirent->d_name);
|
||||
if (fd > 2 && fd != dirfd(d))
|
||||
if ((fd > 2) &&
|
||||
(fd != dirfd(d)) &&
|
||||
(fd != custom_fds->out) &&
|
||||
(fd != custom_fds->err) &&
|
||||
(fd != custom_fds->report)) {
|
||||
_close_descriptor(fd, suppress_warnings,
|
||||
command, ppid, parent_cmdline);
|
||||
}
|
||||
}
|
||||
|
||||
if (closedir(d))
|
||||
@@ -2107,6 +2161,7 @@ int lvm2_main(int argc, char **argv)
|
||||
{
|
||||
const char *base;
|
||||
int ret, alias = 0;
|
||||
struct custom_fds custom_fds;
|
||||
struct cmd_context *cmd;
|
||||
|
||||
if (!argv)
|
||||
@@ -2120,7 +2175,13 @@ int lvm2_main(int argc, char **argv)
|
||||
if (!_check_standard_fds())
|
||||
return -1;
|
||||
|
||||
if (!_close_stray_fds(base))
|
||||
if (!_get_custom_fds(&custom_fds))
|
||||
return -1;
|
||||
|
||||
if (!_close_stray_fds(base, &custom_fds))
|
||||
return -1;
|
||||
|
||||
if (!init_custom_log_streams(&custom_fds))
|
||||
return -1;
|
||||
|
||||
if (is_static() && strcmp(base, "lvm.static") &&
|
||||
@@ -2163,6 +2224,10 @@ int lvm2_main(int argc, char **argv)
|
||||
#ifdef READLINE_SUPPORT
|
||||
if (!alias && argc == 1) {
|
||||
_nonroot_warning();
|
||||
if (!_prepare_profiles(cmd)) {
|
||||
ret = ECMD_FAILED;
|
||||
goto out;
|
||||
}
|
||||
ret = lvm_shell(cmd, &_cmdline);
|
||||
goto out;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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:
|
||||
|
@@ -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,
|
||||
|
@@ -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