mirror of
git://sourceware.org/git/lvm2.git
synced 2025-09-29 13:44:18 +03:00
Compare commits
44 Commits
dev-dct-cm
...
dev-dct-cm
Author | SHA1 | Date | |
---|---|---|---|
|
0a0d991bb5 | ||
|
f98b4f3dc2 | ||
|
46ad67b31c | ||
|
6c0dbea70a | ||
|
4e9ca81960 | ||
|
bb1f0db3a6 | ||
|
40ef88f0da | ||
|
2700ee4217 | ||
|
bec892a24f | ||
|
c590594aa5 | ||
|
56ffa0f0dd | ||
|
c87d9704f8 | ||
|
f30977d4bf | ||
|
abb408a22a | ||
|
edda3f5202 | ||
|
78df117bdf | ||
|
1e551f4c78 | ||
|
773ebc72bb | ||
|
33760d3dcc | ||
|
b020ce3b6e | ||
|
6f25f2f719 | ||
|
1f5dde38a7 | ||
|
dc5bb12956 | ||
|
ee784fd28f | ||
|
377288fe03 | ||
|
95d5877f7a | ||
|
4fd41cf67f | ||
|
9f65a3f0c5 | ||
|
e75f0b7c77 | ||
|
96a1943fb8 | ||
|
14902d1739 | ||
|
95d68f1d0e | ||
|
62be9c8de4 | ||
|
e1943fc07f | ||
|
1053d46aff | ||
|
dd19b56985 | ||
|
77997c7673 | ||
|
2aee4769b4 | ||
|
95e3dd5fb1 | ||
|
9491ab41cd | ||
|
eacff5c189 | ||
|
a7e1f973cc | ||
|
75568294be | ||
|
6fe6e8053a |
@@ -1,5 +1,11 @@
|
||||
Version 2.02.169 -
|
||||
=====================================
|
||||
Add missing udev sync when flushing dirty cache content.
|
||||
vgchange -p accepts only uint32 numbers.
|
||||
Report thin LV date for merged LV when the merge is in progress.
|
||||
Detect if snapshot merge really started before polling for progress.
|
||||
Checking LV for merging origin requires also it has merged snapshot.
|
||||
Extend validation of metadata processing.
|
||||
Enable usage of cached volumes as snapshot origin LV.
|
||||
Fix displayed lv name when splitting snapshot (2.02.146).
|
||||
Warn about command not making metadata backup just once per command.
|
||||
|
@@ -1,5 +1,6 @@
|
||||
Version 1.02.138 -
|
||||
=====================================
|
||||
Thin dmeventd plugin reacts faster on lvextend failure path with umount.
|
||||
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
|
||||
Do not try call callback when reverting activation on error path.
|
||||
Fix file mapping for extents with physically adjacent extents.
|
||||
|
@@ -328,6 +328,7 @@ void process_event(struct dm_task *dmt,
|
||||
char *params;
|
||||
int needs_policy = 0;
|
||||
int needs_umount = 0;
|
||||
struct dm_task *new_dmt = NULL;
|
||||
|
||||
#if THIN_DEBUG
|
||||
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
|
||||
@@ -346,6 +347,28 @@ void process_event(struct dm_task *dmt,
|
||||
goto out;
|
||||
|
||||
stack;
|
||||
|
||||
/*
|
||||
* Rather update oldish status
|
||||
* since after 'command' processing
|
||||
* percentage info could have changed a lot.
|
||||
* If we would get above UMOUNT_THRESH
|
||||
* we would wait for next sigalarm.
|
||||
*/
|
||||
if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
|
||||
goto_out;
|
||||
|
||||
if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
|
||||
goto_out;
|
||||
|
||||
/* Non-blocking status read */
|
||||
if (!dm_task_no_flush(new_dmt))
|
||||
log_warn("WARNING: Can't set no_flush for dm status.");
|
||||
|
||||
if (!dm_task_run(new_dmt))
|
||||
goto_out;
|
||||
|
||||
dmt = new_dmt;
|
||||
}
|
||||
|
||||
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||
@@ -433,6 +456,9 @@ out:
|
||||
device, state->fails);
|
||||
pthread_kill(pthread_self(), SIGALRM);
|
||||
}
|
||||
|
||||
if (new_dmt)
|
||||
dm_task_destroy(new_dmt);
|
||||
}
|
||||
|
||||
int register_device(const char *device,
|
||||
|
@@ -618,7 +618,7 @@ class Lv(LvCommon):
|
||||
rc, out, err = cmdhandler.activate_deactivate(
|
||||
'lvchange', lv_name, activate, control_flags, options)
|
||||
if rc == 0:
|
||||
dbo.refresh()
|
||||
cfg.load()
|
||||
return '/'
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
@@ -667,7 +667,7 @@ class Lv(LvCommon):
|
||||
rc, out, err = cmdhandler.lv_tag(
|
||||
lv_name, tags_add, tags_del, tag_options)
|
||||
if rc == 0:
|
||||
dbo.refresh()
|
||||
cfg.load()
|
||||
return '/'
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
|
@@ -19,7 +19,6 @@ from .utils import log_error, mt_async_result
|
||||
class RequestEntry(object):
|
||||
def __init__(self, tmo, method, arguments, cb, cb_error,
|
||||
return_tuple=True, job_state=None):
|
||||
self.tmo = tmo
|
||||
self.method = method
|
||||
self.arguments = arguments
|
||||
self.cb = cb
|
||||
@@ -35,31 +34,38 @@ class RequestEntry(object):
|
||||
self._return_tuple = return_tuple
|
||||
self._job_state = job_state
|
||||
|
||||
if self.tmo < 0:
|
||||
if tmo < 0:
|
||||
# Client is willing to block forever
|
||||
pass
|
||||
elif tmo == 0:
|
||||
self._return_job()
|
||||
else:
|
||||
self.timer_id = GLib.timeout_add_seconds(
|
||||
tmo, RequestEntry._request_timeout, self)
|
||||
# Note: using 990 instead of 1000 for second to ms conversion to
|
||||
# account for overhead. Goal is to return just before the
|
||||
# timeout amount has expired. Better to be a little early than
|
||||
# late.
|
||||
self.timer_id = GLib.timeout_add(
|
||||
tmo * 990, RequestEntry._request_timeout, self)
|
||||
|
||||
@staticmethod
|
||||
def _request_timeout(r):
|
||||
"""
|
||||
Method which gets called when the timer runs out!
|
||||
:param r: RequestEntry which timed out
|
||||
:return: Nothing
|
||||
:return: Result of timer_expired
|
||||
"""
|
||||
r.timer_expired()
|
||||
return r.timer_expired()
|
||||
|
||||
def _return_job(self):
|
||||
# Return job is only called when we create a request object or when
|
||||
# we pop a timer. In both cases we are running in the correct context
|
||||
# and do not need to schedule the call back in main context.
|
||||
self._job = Job(self, self._job_state)
|
||||
cfg.om.register_object(self._job, True)
|
||||
if self._return_tuple:
|
||||
mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
|
||||
self.cb(('/', self._job.dbus_object_path()))
|
||||
else:
|
||||
mt_async_result(self.cb, self._job.dbus_object_path())
|
||||
self.cb(self._job.dbus_object_path())
|
||||
|
||||
def run_cmd(self):
|
||||
try:
|
||||
|
@@ -727,7 +727,7 @@ class Vg(AutomatedProperties):
|
||||
rc, out, err = cmdhandler.vg_tag(
|
||||
vg_name, tags_add, tags_del, tag_options)
|
||||
if rc == 0:
|
||||
dbo.refresh()
|
||||
cfg.load()
|
||||
return '/'
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
@@ -780,7 +780,7 @@ class Vg(AutomatedProperties):
|
||||
if dbo:
|
||||
rc, out, err = method(vg_name, value, options)
|
||||
if rc == 0:
|
||||
dbo.refresh()
|
||||
cfg.load()
|
||||
return '/'
|
||||
else:
|
||||
raise dbus.exceptions.DBusException(
|
||||
|
@@ -358,6 +358,10 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
int pv_uses_vg(struct physical_volume *pv,
|
||||
struct volume_group *vg)
|
||||
{
|
||||
@@ -1936,7 +1940,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
||||
/* FIXME specify events */
|
||||
if (!monitor_fn(seg, 0)) {
|
||||
log_error("%s: %s segment monitoring function failed.",
|
||||
display_lvname(lv), seg->segtype->name);
|
||||
display_lvname(lv), lvseg_name(seg));
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
@@ -2573,6 +2577,77 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Remove any existing, closed mapped device by @name */
|
||||
static int _remove_dm_dev_by_name(const char *name)
|
||||
{
|
||||
int r = 0;
|
||||
struct dm_task *dmt;
|
||||
struct dm_info info;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
|
||||
return_0;
|
||||
|
||||
/* Check, if the device exists. */
|
||||
if (dm_task_set_name(dmt, name) && dm_task_run(dmt) && dm_task_get_info(dmt, &info)) {
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
/* Ignore non-existing or open dm devices */
|
||||
if (!info.exists || info.open_count)
|
||||
return 1;
|
||||
|
||||
if (!(dmt = dm_task_create(DM_DEVICE_REMOVE)))
|
||||
return_0;
|
||||
|
||||
if (dm_task_set_name(dmt, name))
|
||||
r = dm_task_run(dmt);
|
||||
}
|
||||
|
||||
dm_task_destroy(dmt);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Work all segments of @lv removing any existing, closed "*-missing_N_0" sub devices. */
|
||||
static int _lv_remove_any_missing_subdevs(struct logical_volume *lv)
|
||||
{
|
||||
if (lv) {
|
||||
uint32_t seg_no = 0;
|
||||
char name[257];
|
||||
struct lv_segment *seg;
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
if (seg->area_count != 1)
|
||||
return_0;
|
||||
if (dm_snprintf(name, sizeof(name), "%s-%s-missing_%u_0", seg->lv->vg->name, seg->lv->name, seg_no) < 0)
|
||||
return 0;
|
||||
if (!_remove_dm_dev_by_name(name))
|
||||
return 0;
|
||||
|
||||
seg_no++;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Remove any "*-missing_*" sub devices added by the activation layer for an rmate/rimage missing PV mapping */
|
||||
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
|
||||
{
|
||||
uint32_t s;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_LV &&
|
||||
!_lv_remove_any_missing_subdevs(seg_lv(seg, s)))
|
||||
return 0;
|
||||
if (seg->meta_areas && seg_metatype(seg, s) == AREA_LV &&
|
||||
!_lv_remove_any_missing_subdevs(seg_metalv(seg, s)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Does PV use VG somewhere in its construction?
|
||||
* Returns 1 on failure.
|
||||
|
@@ -124,6 +124,8 @@ int lv_deactivate(struct cmd_context *cmd, const char *lvid_s, const struct logi
|
||||
|
||||
int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv);
|
||||
|
||||
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv);
|
||||
|
||||
/*
|
||||
* Returns 1 if info structure has been populated, else 0 on failure.
|
||||
* When lvinfo* is NULL, it returns 1 if the device is locally active, 0 otherwise.
|
||||
|
@@ -2493,7 +2493,7 @@ static int _add_target_to_dtree(struct dev_manager *dm,
|
||||
|
||||
if (!seg->segtype->ops->add_target_line) {
|
||||
log_error(INTERNAL_ERROR "_emit_target cannot handle "
|
||||
"segment type %s.", seg->segtype->name);
|
||||
"segment type %s.", lvseg_name(seg));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -398,7 +398,7 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
||||
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||
log_error("Segment type %s in LV %s: "
|
||||
"unsupported by format1",
|
||||
seg->segtype->name, lv->name);
|
||||
lvseg_name(seg), lv->name);
|
||||
return 0;
|
||||
}
|
||||
if (seg_type(seg, s) != AREA_PV) {
|
||||
|
@@ -326,7 +326,7 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv)
|
||||
lv_is_cow(origin_lv) || lv_is_merging_cow(origin_lv) ||
|
||||
lv_is_virtual(origin_lv)) {
|
||||
log_error("Cache is not supported with %s segment type of the original logical volume %s.",
|
||||
first_seg(origin_lv)->segtype->name, display_lvname(origin_lv));
|
||||
lvseg_name(first_seg(origin_lv)), display_lvname(origin_lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -424,9 +424,15 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
|
||||
|
||||
/* Switch to cleaner policy to flush the cache */
|
||||
cache_seg->cleaner_policy = 1;
|
||||
/* Reaload kernel with "cleaner" policy */
|
||||
/* Reload cache volume with "cleaner" policy */
|
||||
if (!lv_update_and_reload_origin(cache_lv))
|
||||
return_0;
|
||||
|
||||
if (!sync_local_dev_names(cache_lv->vg->cmd)) {
|
||||
log_error("Failed to sync local devices when clearing cache volume %s.",
|
||||
display_lvname(cache_lv));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -436,6 +442,12 @@ int lv_cache_wait_for_clean(struct logical_volume *cache_lv, int *is_clean)
|
||||
if (1) {
|
||||
if (!lv_refresh_suspend_resume(lock_lv))
|
||||
return_0;
|
||||
|
||||
if (!sync_local_dev_names(cache_lv->vg->cmd)) {
|
||||
log_error("Failed to sync local devices after final clearing of cache %s.",
|
||||
display_lvname(cache_lv));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
cache_seg->cleaner_policy = 0;
|
||||
|
@@ -1418,35 +1418,19 @@ static int _lv_refresh_suspend_resume(const struct logical_volume *lv)
|
||||
|
||||
int lv_refresh_suspend_resume(const struct logical_volume *lv)
|
||||
{
|
||||
/*
|
||||
* FIXME:
|
||||
*
|
||||
* in case of RAID, refresh the SubLVs before
|
||||
* refreshing the top-level one in order to cope
|
||||
* with transient failures of SubLVs.
|
||||
*/
|
||||
if (lv_is_raid(lv)) {
|
||||
if (vg_is_clustered(lv->vg) &&
|
||||
lv_is_active_remotely(lv)) {
|
||||
if (!_lv_refresh_suspend_resume(lv))
|
||||
return 0;
|
||||
} else {
|
||||
uint32_t s;
|
||||
struct lv_segment *seg = first_seg(lv);
|
||||
if (!_lv_refresh_suspend_resume(lv))
|
||||
return 0;
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_LV &&
|
||||
!_lv_refresh_suspend_resume(seg_lv(seg, s)))
|
||||
return 0;
|
||||
if (seg->meta_areas &&
|
||||
seg_metatype(seg, s) == AREA_LV &&
|
||||
!_lv_refresh_suspend_resume(seg_metalv(seg, s)))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Remove any transiently activated error
|
||||
* devices which arean't used any more.
|
||||
*/
|
||||
if (lv_is_raid(lv) && !lv_deactivate_any_missing_subdevs(lv)) {
|
||||
log_error("Failed to remove temporary SubLVs from %s", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _lv_refresh_suspend_resume(lv);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3482,7 +3466,7 @@ int lv_add_segment(struct alloc_handle *ah,
|
||||
region_size))
|
||||
return_0;
|
||||
|
||||
if ((segtype->flags & SEG_CAN_SPLIT) && !lv_merge_segments(lv)) {
|
||||
if (segtype_can_split(segtype) && !lv_merge_segments(lv)) {
|
||||
log_error("Couldn't merge segments after extending "
|
||||
"logical volume.");
|
||||
return 0;
|
||||
@@ -4611,7 +4595,7 @@ static int _lvresize_adjust_policy(const struct logical_volume *lv,
|
||||
|
||||
if (!policy_amount) {
|
||||
log_error("Can't extend %s with %s autoextend percent set to 0%%.",
|
||||
display_lvname(lv), first_seg(lv)->segtype->name);
|
||||
display_lvname(lv), lvseg_name(first_seg(lv)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7063,7 +7047,7 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
|
||||
struct logical_volume *lv, int warn)
|
||||
{
|
||||
/* Unzeroable segment */
|
||||
if (first_seg(lv)->segtype->flags & SEG_CANNOT_BE_ZEROED)
|
||||
if (seg_cannot_be_zeroed(first_seg(lv)))
|
||||
return 0;
|
||||
|
||||
/* Thin snapshot need not to be zeroed */
|
||||
|
@@ -71,6 +71,13 @@ int lv_merge_segments(struct logical_volume *lv)
|
||||
if (error_count++ > ERROR_MAX) \
|
||||
goto out
|
||||
|
||||
#define seg_error(msg) { \
|
||||
log_error("LV %s, segment %u invalid: %s for %s segment.", \
|
||||
seg->lv->name, seg_count, (msg), lvseg_name(seg)); \
|
||||
if ((*error_count)++ > ERROR_MAX) \
|
||||
return; \
|
||||
}
|
||||
|
||||
/*
|
||||
* RAID segment property checks.
|
||||
*
|
||||
@@ -188,44 +195,10 @@ static void _check_non_raid_seg_members(struct lv_segment *seg, int *error_count
|
||||
{
|
||||
if (seg->origin) /* snap and thin */
|
||||
raid_seg_error("non-zero origin LV");
|
||||
if (seg->indirect_origin) /* thin */
|
||||
raid_seg_error("non-zero indirect_origin LV");
|
||||
if (seg->merge_lv) /* thin */
|
||||
raid_seg_error("non-zero merge LV");
|
||||
if (seg->cow) /* snap */
|
||||
raid_seg_error("non-zero cow LV");
|
||||
if (!dm_list_empty(&seg->origin_list)) /* snap */
|
||||
raid_seg_error("non-zero origin_list");
|
||||
if (seg->log_lv)
|
||||
raid_seg_error("non-zero log LV");
|
||||
if (seg->segtype_private)
|
||||
raid_seg_error("non-zero segtype_private");
|
||||
/* thin members */
|
||||
if (seg->metadata_lv)
|
||||
raid_seg_error("non-zero metadata LV");
|
||||
if (seg->transaction_id)
|
||||
raid_seg_error("non-zero transaction_id");
|
||||
if (seg->zero_new_blocks)
|
||||
raid_seg_error("non-zero zero_new_blocks");
|
||||
if (seg->discards)
|
||||
raid_seg_error("non-zero discards");
|
||||
if (!dm_list_empty(&seg->thin_messages))
|
||||
raid_seg_error("non-zero thin_messages list");
|
||||
if (seg->external_lv)
|
||||
raid_seg_error("non-zero external LV");
|
||||
if (seg->pool_lv)
|
||||
raid_seg_error("non-zero pool LV");
|
||||
if (seg->device_id)
|
||||
raid_seg_error("non-zero device_id");
|
||||
/* cache members */
|
||||
if (seg->cache_mode)
|
||||
raid_seg_error("non-zero cache_mode");
|
||||
if (seg->policy_name)
|
||||
raid_seg_error("non-zero policy_name");
|
||||
if (seg->policy_settings)
|
||||
raid_seg_error("non-zero policy_settings");
|
||||
if (seg->cleaner_policy)
|
||||
raid_seg_error("non-zero cleaner_policy");
|
||||
/* replicator members (deprecated) */
|
||||
if (seg->replicator)
|
||||
raid_seg_error("non-zero replicator");
|
||||
@@ -249,9 +222,6 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
|
||||
uint32_t area_len, s;
|
||||
|
||||
/* General checks applying to all RAIDs */
|
||||
if (!seg_is_raid(seg))
|
||||
raid_seg_error("erroneous RAID check");
|
||||
|
||||
if (!seg->area_count)
|
||||
raid_seg_error("zero area count");
|
||||
|
||||
@@ -276,9 +246,6 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
|
||||
return;
|
||||
}
|
||||
|
||||
if (seg->chunk_size)
|
||||
raid_seg_error_val("non-zero chunk_size", seg->chunk_size);
|
||||
|
||||
/* FIXME: should we check any non-RAID segment struct members at all? */
|
||||
_check_non_raid_seg_members(seg, error_count);
|
||||
|
||||
@@ -329,6 +296,169 @@ static void _check_raid_seg(struct lv_segment *seg, int *error_count)
|
||||
}
|
||||
/* END: RAID segment property checks. */
|
||||
|
||||
static void _check_lv_segment(struct logical_volume *lv, struct lv_segment *seg,
|
||||
unsigned seg_count, int *error_count)
|
||||
{
|
||||
struct lv_segment *seg2;
|
||||
|
||||
if (lv_is_mirror_image(lv) &&
|
||||
(!(seg2 = find_mirror_seg(seg)) || !seg_is_mirrored(seg2)))
|
||||
seg_error("mirror image is not mirrored");
|
||||
|
||||
if (seg_is_cache(seg)) {
|
||||
if (!lv_is_cache(lv))
|
||||
seg_error("is not flagged as cache LV");
|
||||
|
||||
if (!seg->pool_lv) {
|
||||
seg_error("is missing cache pool LV");
|
||||
} else if (!lv_is_cache_pool(seg->pool_lv))
|
||||
seg_error("is not referencing cache pool LV");
|
||||
} else { /* !cache */
|
||||
if (seg->cleaner_policy)
|
||||
seg_error("sets cleaner_policy");
|
||||
}
|
||||
|
||||
if (seg_is_cache_pool(seg)) {
|
||||
if (!dm_list_empty(&seg->lv->segs_using_this_lv)) {
|
||||
switch (seg->cache_mode) {
|
||||
case CACHE_MODE_WRITETHROUGH:
|
||||
case CACHE_MODE_WRITEBACK:
|
||||
case CACHE_MODE_PASSTHROUGH:
|
||||
break;
|
||||
default:
|
||||
seg_error("has invalid cache's feature flag")
|
||||
}
|
||||
if (!seg->policy_name)
|
||||
seg_error("is missing cache policy name");
|
||||
}
|
||||
} else { /* !cache_pool */
|
||||
if (seg->cache_mode)
|
||||
seg_error("sets cache mode");
|
||||
if (seg->policy_name)
|
||||
seg_error("sets policy name");
|
||||
if (seg->policy_settings)
|
||||
seg_error("sets policy settings");
|
||||
}
|
||||
|
||||
if (!seg_can_error_when_full(seg) && lv_is_error_when_full(lv))
|
||||
seg_error("does not support flag ERROR_WHEN_FULL.");
|
||||
|
||||
if (seg_is_mirrored(seg)) {
|
||||
/* Check mirror log - which is attached to the mirrored seg */
|
||||
if (seg->log_lv) {
|
||||
if (!lv_is_mirror_log(seg->log_lv))
|
||||
seg_error("log LV is not a mirror log");
|
||||
|
||||
if (!(seg2 = first_seg(seg->log_lv)) || (find_mirror_seg(seg2) != seg))
|
||||
seg_error("log LV does not point back to mirror segment");
|
||||
}
|
||||
} else { /* !mirrored */
|
||||
if (seg->log_lv) {
|
||||
if (lv_is_raid_image(lv))
|
||||
seg_error("log LV is not a mirror log or a RAID image");
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_raid(seg))
|
||||
_check_raid_seg(seg, error_count);
|
||||
|
||||
if (seg_is_pool(seg)) {
|
||||
if ((seg->area_count != 1) || (seg_type(seg, 0) != AREA_LV)) {
|
||||
seg_error("is missing a pool data LV");
|
||||
} else if (!(seg2 = first_seg(seg_lv(seg, 0))) || (find_pool_seg(seg2) != seg))
|
||||
seg_error("data LV does not refer back to pool LV");
|
||||
|
||||
if (!seg->metadata_lv) {
|
||||
seg_error("is missing a pool metadata LV");
|
||||
} else if (!(seg2 = first_seg(seg->metadata_lv)) || (find_pool_seg(seg2) != seg))
|
||||
seg_error("metadata LV does not refer back to pool LV");
|
||||
|
||||
if (!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size))
|
||||
seg_error("has invalid chunk size.");
|
||||
} else { /* !thin_pool && !cache_pool */
|
||||
if (seg->metadata_lv)
|
||||
seg_error("must not have pool metadata LV set");
|
||||
}
|
||||
|
||||
if (seg_is_thin_pool(seg)) {
|
||||
if (!lv_is_thin_pool(lv))
|
||||
seg_error("is not flagged as thin pool LV");
|
||||
|
||||
if (lv_is_thin_volume(lv))
|
||||
seg_error("is a thin volume that must not contain thin pool segment");
|
||||
} else { /* !thin_pool */
|
||||
if (seg->zero_new_blocks)
|
||||
seg_error("sets zero_new_blocks");
|
||||
if (seg->discards)
|
||||
seg_error("sets discards");
|
||||
if (!dm_list_empty(&seg->thin_messages))
|
||||
seg_error("sets thin_messages list");
|
||||
}
|
||||
|
||||
if (seg_is_thin_volume(seg)) {
|
||||
if (!lv_is_thin_volume(lv))
|
||||
seg_error("is not flagged as thin volume LV");
|
||||
|
||||
if (lv_is_thin_pool(lv))
|
||||
seg_error("is a thin pool that must not contain thin volume segment");
|
||||
|
||||
if (!seg->pool_lv) {
|
||||
seg_error("is missing thin pool LV");
|
||||
} else if (!lv_is_thin_pool(seg->pool_lv))
|
||||
seg_error("is not referencing thin pool LV");
|
||||
|
||||
if (seg->device_id > DM_THIN_MAX_DEVICE_ID)
|
||||
seg_error("has too large device id");
|
||||
|
||||
if (seg->external_lv &&
|
||||
!lv_is_external_origin(seg->external_lv))
|
||||
seg_error("external LV is not flagged as a external origin LV");
|
||||
|
||||
if (seg->merge_lv) {
|
||||
if (!lv_is_thin_volume(seg->merge_lv))
|
||||
seg_error("merge LV is not flagged as a thin LV");
|
||||
|
||||
if (!lv_is_merging_origin(seg->merge_lv))
|
||||
seg_error("merge LV is not flagged as merging");
|
||||
}
|
||||
} else { /* !thin */
|
||||
if (seg->device_id)
|
||||
seg_error("sets device_id");
|
||||
if (seg->external_lv)
|
||||
seg_error("sets external LV");
|
||||
if (seg->merge_lv)
|
||||
seg_error("sets merge LV");
|
||||
if (seg->indirect_origin)
|
||||
seg_error("sets indirect_origin LV");
|
||||
}
|
||||
|
||||
/* Some multi-seg vars excluded here */
|
||||
if (!seg_is_cache(seg) &&
|
||||
!seg_is_thin_volume(seg)) {
|
||||
if (seg->pool_lv)
|
||||
seg_error("sets pool LV");
|
||||
}
|
||||
|
||||
if (!seg_is_pool(seg) &&
|
||||
/* FIXME: format_pool/import_export.c _add_linear_seg() sets chunk_size */
|
||||
!seg_is_linear(seg) &&
|
||||
!seg_is_snapshot(seg)) {
|
||||
if (seg->chunk_size)
|
||||
seg_error("sets chunk_size");
|
||||
}
|
||||
|
||||
if (!seg_is_thin_pool(seg) &&
|
||||
!seg_is_thin_volume(seg)) {
|
||||
if (seg->transaction_id)
|
||||
seg_error("sets transaction_id");
|
||||
}
|
||||
|
||||
if (!seg_unknown(seg)) {
|
||||
if (seg->segtype_private)
|
||||
seg_error("set segtype_private");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that an LV's segments are consecutive, complete and don't overlap.
|
||||
*/
|
||||
@@ -336,7 +466,7 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
{
|
||||
struct lv_segment *seg, *seg2;
|
||||
uint32_t le = 0;
|
||||
unsigned seg_count = 0, seg_found;
|
||||
unsigned seg_count = 0, seg_found, external_lv_found = 0;
|
||||
uint32_t area_multiplier, s;
|
||||
struct seg_list *sl;
|
||||
struct glv_list *glvl;
|
||||
@@ -344,80 +474,15 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
struct replicator_site *rsite;
|
||||
struct replicator_device *rdev;
|
||||
|
||||
/* Check LV flags match first segment type */
|
||||
if (complete_vg) {
|
||||
if (lv_is_thin_volume(lv)) {
|
||||
if (dm_list_size(&lv->segments) != 1) {
|
||||
log_error("LV %s is thin volume without exactly one segment.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
} else if (!seg_is_thin_volume(first_seg(lv))) {
|
||||
log_error("LV %s is thin volume without first thin volume segment.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
if (dm_list_size(&lv->segments) != 1) {
|
||||
log_error("LV %s is thin pool volume without exactly one segment.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
} else if (!seg_is_thin_pool(first_seg(lv))) {
|
||||
log_error("LV %s is thin pool without first thin pool segment.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_is_pool_data(lv) &&
|
||||
(!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
|
||||
seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV ||
|
||||
seg_lv(seg2, 0) != lv)) {
|
||||
log_error("LV %s: segment 1 pool data LV does not point back to same LV",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_pool_metadata(lv)) {
|
||||
if (!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
|
||||
seg2->metadata_lv != lv) {
|
||||
log_error("LV %s: segment 1 pool metadata LV does not point back to same LV",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (lv_is_thin_pool_metadata(lv) &&
|
||||
!strstr(lv->name, "_tmeta")) {
|
||||
log_error("LV %s: thin pool metadata LV does not use _tmeta",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
} else if (lv_is_cache_pool_metadata(lv) &&
|
||||
!strstr(lv->name, "_cmeta")) {
|
||||
log_error("LV %s: cache pool metadata LV does not use _cmeta",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (lv_is_external_origin(lv)) {
|
||||
seg_found = 0;
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv)
|
||||
if (sl->seg->external_lv == lv)
|
||||
seg_found++;
|
||||
if (seg_found != lv->external_count) {
|
||||
log_error("LV %s: external origin count does not match.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dm_list_iterate_items(seg, &lv->segments) {
|
||||
seg_count++;
|
||||
|
||||
if (complete_vg && seg_is_raid(seg))
|
||||
_check_raid_seg(seg, &error_count);
|
||||
|
||||
if (seg->lv != lv) {
|
||||
log_error("LV %s invalid: segment %u is referencing different LV.",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (seg->le != le) {
|
||||
log_error("LV %s invalid: segment %u should begin at "
|
||||
"LE %" PRIu32 " (found %" PRIu32 ").",
|
||||
@@ -435,186 +500,6 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_error_when_full(lv) &&
|
||||
!seg_can_error_when_full(seg)) {
|
||||
log_error("LV %s: segment %u (%s) does not support flag "
|
||||
"ERROR_WHEN_FULL.", lv->name, seg_count, seg->segtype->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (complete_vg && seg->log_lv &&
|
||||
!seg_is_mirrored(seg) && lv_is_raid_image(lv)) {
|
||||
log_error("LV %s: segment %u log LV %s is not a "
|
||||
"mirror log or a RAID image",
|
||||
lv->name, seg_count, seg->log_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check mirror log - which is attached to the mirrored seg
|
||||
*/
|
||||
if (complete_vg && seg->log_lv && seg_is_mirrored(seg)) {
|
||||
if (!lv_is_mirror_log(seg->log_lv)) {
|
||||
log_error("LV %s: segment %u log LV %s is not "
|
||||
"a mirror log",
|
||||
lv->name, seg_count, seg->log_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (!(seg2 = first_seg(seg->log_lv)) ||
|
||||
find_mirror_seg(seg2) != seg) {
|
||||
log_error("LV %s: segment %u log LV does not "
|
||||
"point back to mirror segment",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (complete_vg && lv_is_mirror_image(lv)) {
|
||||
if (!(seg2 = find_mirror_seg(seg)) ||
|
||||
!seg_is_mirrored(seg2)) {
|
||||
log_error("LV %s: segment %u mirror image "
|
||||
"is not mirrored",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the various thin segment types */
|
||||
if (complete_vg) {
|
||||
if (seg_is_thin_pool(seg)) {
|
||||
if (!lv_is_thin_pool(lv)) {
|
||||
log_error("LV %s is missing thin pool flag for segment %u",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_thin_volume(lv)) {
|
||||
log_error("LV %s is a thin volume that must not contain thin pool segment %u",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
}
|
||||
if (seg_is_cache_pool(seg) &&
|
||||
!dm_list_empty(&seg->lv->segs_using_this_lv)) {
|
||||
switch (seg->cache_mode) {
|
||||
case CACHE_MODE_WRITETHROUGH:
|
||||
case CACHE_MODE_WRITEBACK:
|
||||
case CACHE_MODE_PASSTHROUGH:
|
||||
break;
|
||||
default:
|
||||
log_error("LV %s has invalid cache's feature flag.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (!seg->policy_name) {
|
||||
log_error("LV %s is missing cache policy name.", lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
if (seg_is_pool(seg)) {
|
||||
if (seg->area_count != 1 ||
|
||||
seg_type(seg, 0) != AREA_LV) {
|
||||
log_error("LV %s: %s segment %u is missing a pool data LV",
|
||||
lv->name, seg->segtype->name, seg_count);
|
||||
inc_error_count;
|
||||
} else if (!(seg2 = first_seg(seg_lv(seg, 0))) || find_pool_seg(seg2) != seg) {
|
||||
log_error("LV %s: %s segment %u data LV does not refer back to pool LV",
|
||||
lv->name, seg->segtype->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (!seg->metadata_lv) {
|
||||
log_error("LV %s: %s segment %u is missing a pool metadata LV",
|
||||
lv->name, seg->segtype->name, seg_count);
|
||||
inc_error_count;
|
||||
} else if (!(seg2 = first_seg(seg->metadata_lv)) ||
|
||||
find_pool_seg(seg2) != seg) {
|
||||
log_error("LV %s: %s segment %u metadata LV does not refer back to pool LV",
|
||||
lv->name, seg->segtype->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (!validate_pool_chunk_size(lv->vg->cmd, seg->segtype, seg->chunk_size)) {
|
||||
log_error("LV %s: %s segment %u has invalid chunk size %u.",
|
||||
lv->name, seg->segtype->name, seg_count, seg->chunk_size);
|
||||
inc_error_count;
|
||||
}
|
||||
} else {
|
||||
if (seg->metadata_lv) {
|
||||
log_error("LV %s: segment %u must not have pool metadata LV set",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_thin_volume(seg)) {
|
||||
if (!lv_is_thin_volume(lv)) {
|
||||
log_error("LV %s is missing thin volume flag for segment %u",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_thin_pool(lv)) {
|
||||
log_error("LV %s is a thin pool that must not contain thin volume segment %u",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (!seg->pool_lv) {
|
||||
log_error("LV %s: segment %u is missing thin pool LV",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
} else if (!lv_is_thin_pool(seg->pool_lv)) {
|
||||
log_error("LV %s: thin volume segment %u pool LV is not flagged as a pool LV",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (seg->device_id > DM_THIN_MAX_DEVICE_ID) {
|
||||
log_error("LV %s: thin volume segment %u has too large device id %u",
|
||||
lv->name, seg_count, seg->device_id);
|
||||
inc_error_count;
|
||||
}
|
||||
if (seg->external_lv && (seg->external_lv->status & LVM_WRITE)) {
|
||||
log_error("LV %s: external origin %s is writable.",
|
||||
lv->name, seg->external_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (seg->merge_lv) {
|
||||
if (!lv_is_thin_volume(seg->merge_lv)) {
|
||||
log_error("LV %s: thin volume segment %u merging LV %s is not flagged as a thin LV",
|
||||
lv->name, seg_count, seg->merge_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (!lv_is_merging_origin(seg->merge_lv)) {
|
||||
log_error("LV %s: merging LV %s is not flagged as merging.",
|
||||
lv->name, seg->merge_lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
} else if (seg_is_cache(seg)) {
|
||||
if (!lv_is_cache(lv)) {
|
||||
log_error("LV %s is missing cache flag for segment %u",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
if (!seg->pool_lv) {
|
||||
log_error("LV %s: segment %u is missing cache_pool LV",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
} else {
|
||||
if (seg->pool_lv) {
|
||||
log_error("LV %s: segment %u must not have pool LV set",
|
||||
lv->name, seg_count);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (seg_is_snapshot(seg)) {
|
||||
if (seg->cow && seg->cow == seg->origin) {
|
||||
log_error("LV %s: segment %u has same LV %s for "
|
||||
@@ -627,6 +512,9 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
if (seg_is_replicator(seg) && !check_replicator_segment(seg))
|
||||
inc_error_count;
|
||||
|
||||
if (complete_vg)
|
||||
_check_lv_segment(lv, seg, seg_count, &error_count);
|
||||
|
||||
for (s = 0; s < seg->area_count; s++) {
|
||||
if (seg_type(seg, s) == AREA_UNASSIGNED) {
|
||||
log_error("LV %s: segment %u has unassigned "
|
||||
@@ -708,6 +596,12 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
le += seg->len;
|
||||
}
|
||||
|
||||
if (le != lv->le_count) {
|
||||
log_error("LV %s: inconsistent LE count %u != %u",
|
||||
lv->name, le, lv->le_count);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||
seg = sl->seg;
|
||||
seg_found = 0;
|
||||
@@ -768,6 +662,10 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
/* Validation of external origin counter */
|
||||
if (seg->external_lv == lv)
|
||||
external_lv_found++;
|
||||
}
|
||||
|
||||
dm_list_iterate_items(glvl, &lv->indirect_glvs) {
|
||||
@@ -789,10 +687,51 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
||||
}
|
||||
}
|
||||
|
||||
if (le != lv->le_count) {
|
||||
log_error("LV %s: inconsistent LE count %u != %u",
|
||||
lv->name, le, lv->le_count);
|
||||
inc_error_count;
|
||||
/* Check LV flags match first segment type */
|
||||
if (complete_vg) {
|
||||
if ((seg_count != 1) &&
|
||||
(lv_is_cache(lv) ||
|
||||
lv_is_cache_pool(lv) ||
|
||||
lv_is_raid(lv) ||
|
||||
lv_is_snapshot(lv) ||
|
||||
lv_is_thin_pool(lv) ||
|
||||
lv_is_thin_volume(lv))) {
|
||||
log_error("LV %s must have exactly one segment.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_pool_data(lv) &&
|
||||
(!(seg2 = first_seg(lv)) || !(seg2 = find_pool_seg(seg2)) ||
|
||||
seg2->area_count != 1 || seg_type(seg2, 0) != AREA_LV ||
|
||||
seg_lv(seg2, 0) != lv)) {
|
||||
log_error("LV %s: segment 1 pool data LV does not point back to same LV",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_thin_pool_metadata(lv) && !strstr(lv->name, "_tmeta")) {
|
||||
log_error("LV %s: thin pool metadata LV does not use _tmeta.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
} else if (lv_is_cache_pool_metadata(lv) && !strstr(lv->name, "_cmeta")) {
|
||||
log_error("LV %s: cache pool metadata LV does not use _cmeta.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
|
||||
if (lv_is_external_origin(lv)) {
|
||||
if (lv->external_count != external_lv_found) {
|
||||
log_error("LV %s: external origin count does not match.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
if (lv->status & LVM_WRITE) {
|
||||
log_error("LV %s: external origin cant't be writable.",
|
||||
lv->name);
|
||||
inc_error_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
@@ -198,7 +198,7 @@
|
||||
#define lv_is_partial(lv) (((lv)->status & PARTIAL_LV) ? 1 : 0)
|
||||
#define lv_is_virtual(lv) (((lv)->status & VIRTUAL) ? 1 : 0)
|
||||
#define lv_is_merging(lv) (((lv)->status & MERGING) ? 1 : 0)
|
||||
#define lv_is_merging_origin(lv) (lv_is_merging(lv))
|
||||
#define lv_is_merging_origin(lv) (lv_is_merging(lv) && (lv)->snapshot)
|
||||
#define lv_is_snapshot(lv) (((lv)->status & SNAPSHOT) ? 1 : 0)
|
||||
#define lv_is_converting(lv) (((lv)->status & CONVERTING) ? 1 : 0)
|
||||
#define lv_is_external_origin(lv) (((lv)->external_count > 0) ? 1 : 0)
|
||||
|
@@ -5447,6 +5447,19 @@ int vg_flag_write_locked(struct volume_group *vg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _access_vg_clustered(struct cmd_context *cmd, const struct volume_group *vg)
|
||||
{
|
||||
if (vg_is_clustered(vg) && !locking_is_clustered()) {
|
||||
if (!cmd->ignore_clustered_vgs)
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
else
|
||||
log_verbose("Skipping clustered volume group %s", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Performs a set of checks against a VG according to bits set in status
|
||||
* and returns FAILED_* bits for those that aren't acceptable.
|
||||
@@ -5458,15 +5471,9 @@ static uint32_t _vg_bad_status_bits(const struct volume_group *vg,
|
||||
{
|
||||
uint32_t failure = 0;
|
||||
|
||||
if ((status & CLUSTERED) &&
|
||||
(vg_is_clustered(vg)) && !locking_is_clustered()) {
|
||||
if (!vg->cmd->ignore_clustered_vgs)
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
else
|
||||
log_verbose("Skipping clustered volume group %s", vg->name);
|
||||
if ((status & CLUSTERED) && !_access_vg_clustered(vg->cmd, vg))
|
||||
/* Return because other flags are considered undefined. */
|
||||
return FAILED_CLUSTERED;
|
||||
}
|
||||
|
||||
if ((status & EXPORTED_VG) &&
|
||||
vg_is_exported(vg)) {
|
||||
@@ -5555,19 +5562,6 @@ static int _allow_extra_system_id(struct cmd_context *cmd, const char *system_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _access_vg_clustered(struct cmd_context *cmd, struct volume_group *vg)
|
||||
{
|
||||
if (vg_is_clustered(vg) && !locking_is_clustered()) {
|
||||
if (!cmd->ignore_clustered_vgs)
|
||||
log_error("Skipping clustered volume group %s", vg->name);
|
||||
else
|
||||
log_verbose("Skipping clustered volume group %s", vg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg,
|
||||
uint32_t lockd_state, uint32_t *failure)
|
||||
{
|
||||
|
@@ -2724,15 +2724,6 @@ static const char *_get_segtype_alias(const struct segment_type *segtype)
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Return "linear" for striped segtype with 1 area instead of "striped" */
|
||||
static const char *_get_segtype_name(const struct segment_type *segtype, unsigned new_image_count)
|
||||
{
|
||||
if (!segtype || (segtype_is_striped(segtype) && new_image_count == 1))
|
||||
return "linear";
|
||||
|
||||
return segtype->name;
|
||||
}
|
||||
|
||||
static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype)
|
||||
{
|
||||
unsigned possible_conversions = 0;
|
||||
@@ -2753,7 +2744,7 @@ static int _log_possible_conversion_types(const struct logical_volume *lv, const
|
||||
|
||||
log_error("Converting %s from %s%s%s%s is "
|
||||
"directly possible to the following layout%s:",
|
||||
display_lvname(lv), _get_segtype_name(seg->segtype, seg->area_count),
|
||||
display_lvname(lv), lvseg_name(seg),
|
||||
*alias ? " (same as " : "", alias, *alias ? ")" : "",
|
||||
possible_conversions > 1 ? "s" : "");
|
||||
|
||||
|
@@ -144,6 +144,12 @@ 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_can_split(segtype) ((segtype)->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
#define segtype_cannot_be_zeroed(segtype) ((segtype)->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
||||
#define segtype_monitored(segtype) ((segtype)->flags & SEG_MONITORED ? 1 : 0)
|
||||
#define segtype_only_exclusive(segtype) ((segtype)->flags & SEG_ONLY_EXCLUSIVE ? 1 : 0)
|
||||
#define segtype_can_error_when_full(segtype) ((segtype)->flags & SEG_CAN_ERROR_WHEN_FULL ? 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) || \
|
||||
@@ -188,11 +194,11 @@ struct dev_manager;
|
||||
#define seg_is_thin_volume(seg) segtype_is_thin_volume((seg)->segtype)
|
||||
#define seg_is_virtual(seg) segtype_is_virtual((seg)->segtype)
|
||||
#define seg_unknown(seg) segtype_is_unknown((seg)->segtype)
|
||||
#define seg_can_split(seg) ((seg)->segtype->flags & SEG_CAN_SPLIT ? 1 : 0)
|
||||
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
||||
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
|
||||
#define seg_only_exclusive(seg) ((seg)->segtype->flags & SEG_ONLY_EXCLUSIVE ? 1 : 0)
|
||||
#define seg_can_error_when_full(seg) ((seg)->segtype->flags & SEG_CAN_ERROR_WHEN_FULL ? 1 : 0)
|
||||
#define seg_can_split(seg) segtype_can_split((seg)->segtype)
|
||||
#define seg_cannot_be_zeroed(seg) segtype_cannot_be_zeroed((seg)->segtype)
|
||||
#define seg_monitored(seg) segtype_monitored((seg)->segtype)
|
||||
#define seg_only_exclusive(seg) segtype_only_exclusive((seg)->segtype)
|
||||
#define seg_can_error_when_full(seg) segtype_can_error_when_full((seg)->segtype)
|
||||
|
||||
struct segment_type {
|
||||
struct dm_list list; /* Internal */
|
||||
|
@@ -878,7 +878,7 @@ Count of writes merged this interval.
|
||||
.B write_sector_count
|
||||
Count of 512 byte sectors written this interval.
|
||||
.TP
|
||||
.B write_nsecs
|
||||
.B write_time
|
||||
Accumulated duration of all write requests (ns).
|
||||
.TP
|
||||
.B in_progress_count
|
||||
|
258
man/lvm.8.in
258
man/lvm.8.in
@@ -45,6 +45,9 @@ A file containing a simple script with one command per line
|
||||
can also be given on the command line. The script can also be
|
||||
executed directly if the first line is #! followed by the absolute
|
||||
path of \fBlvm\fP.
|
||||
.P
|
||||
Additional hyphens within option names are ignored. For example,
|
||||
\fB\-\-readonly\fP and \fB\-\-read\-only\fP are both accepted.
|
||||
.
|
||||
.SH BUILT-IN COMMANDS
|
||||
.
|
||||
@@ -238,261 +241,6 @@ The following commands are not implemented in LVM2 but might be
|
||||
in the future:
|
||||
.BR lvmsadc ", " lvmsar ", " pvdata .
|
||||
.
|
||||
.SH OPTIONS
|
||||
.
|
||||
The following options are available for many of the commands.
|
||||
They are implemented generically and documented here rather
|
||||
than repeated on individual manual pages.
|
||||
.P
|
||||
Additional hyphens within option names are ignored. For example,
|
||||
\fB\-\-readonly\fP and \fB\-\-read\-only\fP are both accepted.
|
||||
.
|
||||
.HP
|
||||
.BR \-h | \-? | \-\-help
|
||||
.br
|
||||
Display the help text.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-version
|
||||
.br
|
||||
Display version information.
|
||||
.
|
||||
.HP
|
||||
.BR \-v | \-\-verbose
|
||||
.br
|
||||
Set verbose level. Repeat from 1 to 3 times to increase the detail
|
||||
of messages sent to stdout and stderr. Overrides config file setting.
|
||||
.
|
||||
.HP
|
||||
.BR \-d | \-\-debug
|
||||
.br
|
||||
Set debug level. Repeat from 1 to 6 times to increase the detail of
|
||||
messages sent to the log file and/or syslog (if configured).
|
||||
Overrides config file setting.
|
||||
.
|
||||
.HP
|
||||
.BR \-q | \-\-quiet
|
||||
.br
|
||||
Suppress output and log messages.
|
||||
Overrides \fB\-d\fP and \fB\-v\fP.
|
||||
Repeat once to also suppress any prompts with answer 'no'.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-yes
|
||||
.br
|
||||
Don't prompt for confirmation interactively but instead always assume the
|
||||
answer is 'yes'. Take great care if you use this!
|
||||
.
|
||||
.HP
|
||||
.BR \-t | \-\-test
|
||||
.br
|
||||
Run in test mode. Commands will not update metadata.
|
||||
This is implemented by disabling all metadata writing but nevertheless
|
||||
returning success to the calling function. This may lead to unusual
|
||||
error messages in multi-stage operations if a tool relies on reading
|
||||
back metadata it believes has changed but hasn't.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-driverloaded
|
||||
.RB { y | n }
|
||||
.br
|
||||
Whether or not the device-mapper kernel driver is loaded.
|
||||
If you set this to \fBn\fP, no attempt will be made to contact the driver.
|
||||
.
|
||||
.HP
|
||||
.BR \-A | \-\-autobackup
|
||||
.RB { y | n }
|
||||
.br
|
||||
Whether or not to metadata should be backed up automatically after a change.
|
||||
You are strongly advised not to disable this!
|
||||
See \fBvgcfgbackup\fP(8).
|
||||
.
|
||||
.HP
|
||||
.BR \-P | \-\-partial
|
||||
.br
|
||||
When set, the tools will do their best to provide access to Volume Groups
|
||||
that are only partially available (one or more Physical Volumes belonging
|
||||
to the Volume Group are missing from the system). Where part of a logical
|
||||
volume is missing, \fI\%/dev/ioerror\fP will be substituted, and you could use
|
||||
\fBdmsetup\fP(8) to set this up to return I/O errors when accessed,
|
||||
or create it as a large block device of nulls. Metadata may not be
|
||||
changed with this option. To insert a replacement Physical Volume
|
||||
of the same or large size use \fBpvcreate \-u\fP to set the uuid to
|
||||
match the original followed by \fBvgcfgrestore\fP(8).
|
||||
.
|
||||
.HP
|
||||
.BR \-S | \-\-select
|
||||
.IR Selection
|
||||
.br
|
||||
For reporting commands, display only rows that match \fISelection\fP criteria.
|
||||
All rows are displayed with the additional "selected" column (\fB-o selected\fP)
|
||||
showing 1 if the row matches the \fISelection\fP and 0 otherwise. For non-reporting
|
||||
commands which process LVM entities, the selection can be used to match items
|
||||
to process. See \fBSelection\fP section in \fBlvmreport\fP(7) man page for more
|
||||
information about the way the selection criteria are constructed.
|
||||
.
|
||||
.HP
|
||||
.BR \-M | \-\-metadatatype
|
||||
.IR Type
|
||||
.br
|
||||
Specifies which \fItype\fP of on-disk metadata to use, such as \fBlvm1\fP
|
||||
or \fBlvm2\fP, which can be abbreviated to \fB1\fP or \fB2\fP respectively.
|
||||
The default (\fBlvm2\fP) can be changed by setting \fBformat\fP
|
||||
in the \fBglobal\fP section of the config file \fBlvm.conf\fP(5).
|
||||
.
|
||||
.HP
|
||||
.BR \-\-ignorelockingfailure
|
||||
.br
|
||||
This lets you proceed with read-only metadata operations such as
|
||||
\fBlvchange \-ay\fP and \fBvgchange \-ay\fP even if the locking module fails.
|
||||
One use for this is in a system init script if the lock directory
|
||||
is mounted read-only when the script runs.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-ignoreskippedcluster
|
||||
.br
|
||||
Use to avoid exiting with an non-zero status code if the command is run
|
||||
without clustered locking and some clustered Volume Groups have to be
|
||||
skipped over.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-readonly
|
||||
.br
|
||||
Run the command in a special read-only mode which will read on-disk
|
||||
metadata without needing to take any locks. This can be used to peek
|
||||
inside metadata used by a virtual machine image while the virtual
|
||||
machine is running.
|
||||
It can also be used to peek inside the metadata of clustered Volume
|
||||
Groups when clustered locking is not configured or running. No attempt
|
||||
will be made to communicate with the device-mapper kernel driver, so
|
||||
this option is unable to report whether or not Logical Volumes are
|
||||
actually in use.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-foreign
|
||||
.br
|
||||
Cause the command to access foreign VGs, that would otherwise be skipped.
|
||||
It can be used to report or display a VG that is owned by another host.
|
||||
This option can cause a command to perform poorly because lvmetad caching
|
||||
is not used and metadata is read from disks.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-shared
|
||||
.br
|
||||
Cause the command to access shared VGs, that would otherwise be skipped
|
||||
when lvmlockd is not being used. It can be used to report or display a
|
||||
lockd VG without locking. Applicable only if LVM is compiled with lockd
|
||||
support.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-addtag
|
||||
.IR Tag
|
||||
.br
|
||||
Add the tag \fITag\fP to a PV, VG or LV.
|
||||
Supply this argument multiple times to add more than one tag at once.
|
||||
A tag is a word that can be used to group LVM2 objects of the same type
|
||||
together.
|
||||
Tags can be given on the command line in place of PV, VG or LV
|
||||
arguments. Tags should be prefixed with @ to avoid ambiguity.
|
||||
Each tag is expanded by replacing it with all objects possessing
|
||||
that tag which are of the type expected by its position on the command line.
|
||||
PVs can only possess tags while they are part of a Volume Group:
|
||||
PV tags are discarded if the PV is removed from the VG.
|
||||
As an example, you could tag some LVs as \fBdatabase\fP and others
|
||||
as \fBuserdata\fP and then activate the database ones
|
||||
with \fBlvchange \-ay @database\fP.
|
||||
Objects can possess multiple tags simultaneously.
|
||||
Only the new LVM2 metadata format supports tagging: objects using the
|
||||
LVM1 metadata format cannot be tagged because the on-disk format does not
|
||||
support it.
|
||||
Characters allowed in tags are:
|
||||
.BR A - Z
|
||||
.BR a - z
|
||||
.BR 0 - 9
|
||||
.BR "_ + . -"
|
||||
and as of version 2.02.78 the following characters are also accepted:
|
||||
.BR "/ = ! : # &" .
|
||||
.
|
||||
.HP
|
||||
.BR \-\-deltag
|
||||
.IR Tag
|
||||
.br
|
||||
Delete the tag \fITag\fP from a PV, VG or LV, if it's present.
|
||||
Supply this argument multiple times to remove more than one tag at once.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-alloc
|
||||
.RB { anywhere | contiguous | cling | inherit | normal }
|
||||
.br
|
||||
Selects the allocation policy when a command needs to allocate
|
||||
Physical Extents from the Volume Group.
|
||||
Each Volume Group and Logical Volume has an allocation policy defined.
|
||||
The default for a Volume Group is \fBnormal\fP which applies
|
||||
common-sense rules such as not placing parallel stripes on the same
|
||||
Physical Volume. The default for a Logical Volume is \fBinherit\fP
|
||||
which applies the same policy as for the Volume Group. These policies can
|
||||
be changed using \fBlvchange\fP(8) and \fBvgchange\fP(8) or overridden
|
||||
on the command line of any command that performs allocation.
|
||||
The \fBcontiguous\fP policy requires that new Physical Extents be placed adjacent
|
||||
to existing Physical Extents.
|
||||
The \fBcling\fP policy places new Physical Extents on the same Physical
|
||||
Volume as existing Physical Extents in the same stripe of the Logical Volume.
|
||||
If there are sufficient free Physical Extents to satisfy
|
||||
an allocation request but \fBnormal\fP doesn't use them,
|
||||
\fBanywhere\fP will - even if that reduces performance by
|
||||
placing two stripes on the same Physical Volume.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-commandprofile
|
||||
.IR ProfileName
|
||||
.br
|
||||
Selects the command configuration profile to use when processing an LVM command.
|
||||
See also \fBlvm.conf\fP(5) for more information about \fBcommand profile config\fP and
|
||||
the way it fits with other LVM configuration methods. Using \fB\-\-commandprofile\fP
|
||||
option overrides any command profile specified via \fBLVM_COMMAND_PROFILE\fP
|
||||
environment variable.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-metadataprofile
|
||||
.IR ProfileName
|
||||
.br
|
||||
Selects the metadata configuration profile to use when processing an LVM command.
|
||||
When using metadata profile during Volume Group or Logical Volume creation,
|
||||
the metadata profile name is saved in metadata. When such Volume Group or Logical
|
||||
Volume is processed next time, the metadata profile is automatically applied
|
||||
and the use of \fB\-\-metadataprofile\fP option is not necessary. See also
|
||||
\fBlvm.conf\fP(5) for more information about \fBmetadata profile config\fP and the
|
||||
way it fits with other LVM configuration methods.
|
||||
.
|
||||
.HP
|
||||
.BR \-\-profile
|
||||
.IR ProfileName
|
||||
.br
|
||||
A short form of \fB\-\-metadataprofile\fP for \fBvgcreate\fP, \fBlvcreate\fP,
|
||||
\fBvgchange\fP and \fBlvchange\fP command and a short form of \fB\-\-commandprofile\fP
|
||||
for any other command (with the exception of \fBlvmconfig\fP command where the
|
||||
\fB\-\-profile\fP has special meaning, see \fBlvmconfig\fP(8) for more information).
|
||||
.
|
||||
.HP
|
||||
.BR \-\-reportformat
|
||||
.IR {basic|json}
|
||||
.br
|
||||
Overrides current output format for reports which is defined globally by
|
||||
\fBreport/output_format\fP configuration setting in \fBlvm.conf\fP(5).
|
||||
The \fBbasic\fP format is the original format with columns and rows and
|
||||
if there is more than one report per command, each report is prefixed
|
||||
with report's name for identification. The \fBjson\fP stands for report
|
||||
output in JSON format.
|
||||
.HP
|
||||
.BR \-\-config
|
||||
.IR ConfigurationString
|
||||
.br
|
||||
Uses the ConfigurationString as direct string representation of the configuration
|
||||
to override the existing configuration. The ConfigurationString is of exactly
|
||||
the same format as used in any LVM configuration file. See \fBlvm.conf\fP(5)
|
||||
for more information about \fBdirect config override on command line\fP and the
|
||||
way it fits with other LVM configuration methods.
|
||||
.
|
||||
.SH VALID NAMES
|
||||
.
|
||||
The valid characters for VG and LV names are:
|
||||
|
@@ -16,6 +16,7 @@ from collections import OrderedDict
|
||||
import dbus
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||
@@ -188,10 +189,15 @@ class RemoteInterface(object):
|
||||
|
||||
def __init__(
|
||||
self, dbus_object, interface, introspect,
|
||||
properties=None):
|
||||
properties=None, timelimit=-1):
|
||||
self.dbus_object = dbus_object
|
||||
self.interface = interface
|
||||
self.introspect = introspect
|
||||
self.tmo = 0
|
||||
|
||||
if timelimit >= 0:
|
||||
self.tmo = float(timelimit)
|
||||
self.tmo *= 1.10
|
||||
|
||||
self.dbus_interface = dbus.Interface(self.dbus_object, self.interface)
|
||||
self._set_props(properties)
|
||||
@@ -203,7 +209,19 @@ class RemoteInterface(object):
|
||||
return functools.partial(self, item)
|
||||
|
||||
def _wrapper(self, _method_name, *args, **kwargs):
|
||||
|
||||
# Lets see how long a method takes to execute, in call cases we should
|
||||
# return something when the time limit has been reached.
|
||||
start = time.time()
|
||||
result = getattr(self.dbus_interface, _method_name)(*args, **kwargs)
|
||||
end = time.time()
|
||||
|
||||
diff = end - start
|
||||
|
||||
if self.tmo > 0.0:
|
||||
if diff > self.tmo:
|
||||
std_err_print("\n Time exceeded: %f > %f %s" %
|
||||
(diff, self.tmo, _method_name))
|
||||
|
||||
if self.introspect:
|
||||
if 'RETURN_VALUE' in self.introspect[
|
||||
@@ -236,13 +254,14 @@ class ClientProxy(object):
|
||||
short_name = ClientProxy._intf_short_name(interface)
|
||||
self.short_interface_names.append(short_name)
|
||||
ro = RemoteInterface(self.dbus_object, interface, introspect,
|
||||
properties)
|
||||
properties, timelimit=self.tmo)
|
||||
setattr(self, short_name, ro)
|
||||
|
||||
def __init__(self, bus, object_path, interface_prop_hash=None,
|
||||
interfaces=None):
|
||||
interfaces=None, timelimit=-1):
|
||||
self.object_path = object_path
|
||||
self.short_interface_names = []
|
||||
self.tmo = timelimit
|
||||
self.dbus_object = bus.get_object(
|
||||
BUS_NAME, self.object_path, introspect=False)
|
||||
|
||||
|
@@ -1491,6 +1491,27 @@ wait_pvmove_lv_ready() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Holds device open with sleep which automatically expires after given timeout
|
||||
# Prints PID of running holding sleep process in background
|
||||
hold_device_open() {
|
||||
local vgname=$1
|
||||
local lvname=$2
|
||||
local sec=${3:-20} # default 20sec
|
||||
|
||||
sleep $sec < "$DM_DEV_DIR/$vgname/$lvname" >/dev/null 2>&1 &
|
||||
SLEEP_PID=$!
|
||||
# wait till device is openned
|
||||
for i in $(seq 1 50) ; do
|
||||
if test "$(dmsetup info --noheadings -c -o open $vgname-$lvname)" -ne 0 ; then
|
||||
echo "$SLEEP_PID"
|
||||
return
|
||||
fi
|
||||
sleep .1
|
||||
done
|
||||
|
||||
die "$vgname-$lvname expected to be openned, but it's not!"
|
||||
}
|
||||
|
||||
# return total memory size in kB units
|
||||
total_mem() {
|
||||
while IFS=":" read -r a b ; do
|
||||
|
69
test/shell/lvchange-raid-transient-failures.sh
Normal file
69
test/shell/lvchange-raid-transient-failures.sh
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/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 10 1 || skip
|
||||
aux prepare_vg 6
|
||||
|
||||
#
|
||||
# FIXME: add multi-segment leg tests
|
||||
#
|
||||
|
||||
function _check_raid
|
||||
{
|
||||
local vg=$1
|
||||
shift
|
||||
local lv=$1
|
||||
shift
|
||||
local fail=$1
|
||||
shift
|
||||
local good=$1
|
||||
shift
|
||||
local devs=$*
|
||||
|
||||
aux wait_for_sync $vg $lv
|
||||
aux disable_dev --error --silent $devs
|
||||
mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
|
||||
check raid_leg_status $vg $lv "$fail"
|
||||
aux enable_dev --silent $devs
|
||||
lvs -a -o +devices $vg | tee out
|
||||
not grep unknown out
|
||||
lvchange --refresh $vg/$lv
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
|
||||
aux wait_for_sync $vg $lv
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
|
||||
check raid_leg_status $vg $lv "$good"
|
||||
}
|
||||
|
||||
# raid1 with transiently failing devices
|
||||
lv=4way
|
||||
lvcreate -aey --type raid1 -m 3 --ignoremonitoring -L 1 -n $lv $vg
|
||||
_check_raid $vg $lv "ADAD" "AAAA" $dev2 $dev4
|
||||
lvremove -y $vg/$lv
|
||||
|
||||
# raid6 with transiently failing devices
|
||||
lv=6way
|
||||
lvcreate -aey --type raid6 -i 4 --ignoremonitoring -L 1 -n $lv $vg
|
||||
_check_raid $vg $lv "ADADAA" "AAAAAA" $dev2 $dev4
|
||||
lvremove -y $vg/$lv
|
||||
|
||||
# raid10 with transiently failing devices
|
||||
lv=6way
|
||||
lvcreate -aey --type raid10 -i 3 -m 1 --ignoremonitoring -L 1 -n $lv $vg
|
||||
_check_raid $vg $lv "ADADDA" "AAAAAA" $dev2 $dev4 $dev5
|
||||
lvremove -y $vg/$lv
|
||||
|
||||
vgremove -f $vg
|
@@ -32,7 +32,8 @@ get_image_pvs() {
|
||||
aux have_raid 1 3 0 || skip
|
||||
|
||||
aux prepare_pvs 9
|
||||
vgcreate -s 256k $vg $(cat DEVICES)
|
||||
# vgcreate -s 256k $vg $(cat DEVICES)
|
||||
vgcreate -s 2m $vg $(cat DEVICES)
|
||||
|
||||
###########################################
|
||||
# RAID1 convert tests
|
||||
@@ -135,15 +136,27 @@ lvconvert --yes --splitmirrors 1 --name $lv2 $vg/$lv1 "$dev2"
|
||||
lvremove -ff $vg
|
||||
|
||||
###########################################
|
||||
# RAID1 split + trackchanges / merge
|
||||
# RAID1 split + trackchanges / merge with content check
|
||||
###########################################
|
||||
# 3-way to 2-way/linear
|
||||
lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
|
||||
lvcreate --type raid1 -m 2 -l 1 -n $lv1 $vg
|
||||
mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
|
||||
aux wait_for_sync $vg $lv1
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
|
||||
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
|
||||
check lv_exists $vg $lv1
|
||||
check linear $vg ${lv1}_rimage_2
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
|
||||
dd of="$DM_DEV_DIR/$vg/$lv1" if=/dev/zero bs=512 oflag=direct count=`blockdev --getsz "$DM_DEV_DIR/$vg/$lv1"`
|
||||
not fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
|
||||
fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
|
||||
# FIXME: needed on tiny loop but not on real block backend ?
|
||||
lvchange --refresh $vg/$lv1
|
||||
lvconvert --merge $vg/${lv1}_rimage_2
|
||||
aux wait_for_sync $vg $lv1
|
||||
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
|
||||
not fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
|
||||
# FIXME: ensure no residual devices
|
||||
lvremove -ff $vg
|
||||
|
||||
|
@@ -50,6 +50,12 @@ not lvconvert --thin --thinpool $vg/tpool $vg/$lv1
|
||||
# Switch to 'writethrough' - this should be supported
|
||||
lvchange --cachemode writethrough $vg/$lv1
|
||||
|
||||
# FIXME
|
||||
# systemd on fc23 'strikes-in' and unmounts mnt
|
||||
# ATM the reason is unclear (bug in systemd, bad udev rules?)
|
||||
# as a workaround mount again and 'WARN' test
|
||||
should not mount "$DM_DEV_DIR/$vg/$lv1" mnt
|
||||
|
||||
lvconvert --thin $vg/$lv1 --originname extorg --thinpool $vg/tpool
|
||||
|
||||
# check cache exist as extorg-real
|
||||
|
@@ -29,9 +29,7 @@ snap_and_merge() {
|
||||
sync
|
||||
lvs -a $vg
|
||||
|
||||
# keep device open to prevent instant merge
|
||||
sleep 20 < "$DM_DEV_DIR/$vg/$lv1" &
|
||||
SLEEP_PID=$!
|
||||
SLEEP_PID=$(aux hold_device_open $vg $lv1 20)
|
||||
|
||||
# initiate background merge
|
||||
lvconvert -b --mergesnapshot $vg/$lv2
|
||||
|
@@ -24,16 +24,6 @@ fill() {
|
||||
die "Snapshot does not fit $1"
|
||||
}
|
||||
|
||||
# Wait until device is opened
|
||||
wait_for_open_() {
|
||||
for i in $(seq 1 50) ; do
|
||||
test $(dmsetup info --noheadings -c -o open $1) -ne 0 && return
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
die "$1 expected to be openned, but it's not!"
|
||||
}
|
||||
|
||||
cleanup_tail()
|
||||
{
|
||||
test -z "$SLEEP_PID" || kill $SLEEP_PID || true
|
||||
@@ -125,10 +115,7 @@ lvchange -ay $vg1
|
||||
check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
|
||||
|
||||
# Test removal of opened (but unmounted) snapshot (device busy) for a while
|
||||
sleep 120 < "$DM_DEV_DIR/$vg1/$lv1" &
|
||||
SLEEP_PID=$!
|
||||
|
||||
wait_for_open_ "$vg1-$lv1"
|
||||
SLEEP_PID=$(aux hold_device_open $vg1 $lv1 60)
|
||||
|
||||
# Opened virtual snapshot device is not removable
|
||||
# it should retry device removal for a few seconds
|
||||
|
@@ -72,18 +72,18 @@ touch "$mntusedir/file$$"
|
||||
sync
|
||||
|
||||
# Running 'keeper' process sleep holds the block device still in use
|
||||
sleep 60 < "$mntusedir/file$$" &
|
||||
sleep 60 < "$mntusedir/file$$" >/dev/null 2>&1 &
|
||||
PID_SLEEP=$!
|
||||
|
||||
lvs -a $vg
|
||||
# Fill pool above 95% (to cause 'forced lazy umount)
|
||||
dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync
|
||||
sync
|
||||
|
||||
lvs -a $vg
|
||||
|
||||
# Could loop here for a few secs so dmeventd can do some work
|
||||
# In the worst case check only happens every 10 seconds :(
|
||||
# With low water mark it should react way faster
|
||||
# With low water mark it quickly discovers overflow and umounts $vg/$lv1
|
||||
for i in $(seq 1 12) ; do
|
||||
is_lv_opened_ "$vg/$lv1" || break
|
||||
test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2014 Red Hat, Inc. All rights reserved.
|
||||
# Copyright (C) 2014-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
|
||||
@@ -37,15 +37,24 @@ check lv_field $vg/snap thin_id "3"
|
||||
lvconvert --mergethin $vg/snap
|
||||
|
||||
umount mnt
|
||||
|
||||
check lv_field $vg/$lv1 thin_id "1"
|
||||
check lv_field $vg/pool transaction_id "3"
|
||||
|
||||
vgchange -an $vg
|
||||
|
||||
# Check reboot case
|
||||
vgchange -ay --sysinit $vg
|
||||
# Metadata are still not updated (--poll n)
|
||||
check lv_field $vg/$lv1 thin_id "1"
|
||||
|
||||
# Check correct thin_id is shown after activation
|
||||
# even when metadata were not yet physically modified.
|
||||
# Merge take its place during activation,
|
||||
# but pool transaction_id still needs metadata update.
|
||||
check lv_field $vg/$lv1 thin_id "3"
|
||||
check lv_field $vg/pool transaction_id "3"
|
||||
|
||||
# Check the metadata are updated after refresh
|
||||
#
|
||||
vgchange --refresh $vg
|
||||
check lv_field $vg/$lv1 thin_id "3"
|
||||
check lv_field $vg/pool transaction_id "4"
|
||||
|
@@ -53,6 +53,13 @@ not vgchange -p 2 $vg 2>err
|
||||
grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err
|
||||
check vg_field $vg max_pv 128
|
||||
|
||||
# try some numbers around MAX limit (uint32)
|
||||
vgchange -p 4294967295 $vg
|
||||
invalid vgchange -p 4294967296 $vg
|
||||
invalid vgchange -p 18446744073709551615 $vg
|
||||
invalid vgchange -p 18446744073709551616 $vg
|
||||
check vg_field $vg max_pv 4294967295
|
||||
|
||||
# vgchange -l MaxLogicalVolumes
|
||||
check vg_field $vg max_lv 0
|
||||
invalid vgchange -l -128 $vg
|
||||
|
@@ -1,3 +1,4 @@
|
||||
|
||||
#
|
||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||
# Copyright (C) 2004-2012 Red Hat, Inc. All rights reserved.
|
||||
@@ -140,6 +141,8 @@ all: device-mapper
|
||||
CFLAGS_lvm.o += $(EXTRA_EXEC_CFLAGS)
|
||||
CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS)
|
||||
|
||||
INCLUDES += -I$(top_builddir)/tools
|
||||
|
||||
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
|
||||
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
|
||||
@@ -173,12 +176,35 @@ liblvm2cmd.$(LIB_SUFFIX).$(LIB_VERSION): liblvm2cmd.$(LIB_SUFFIX)
|
||||
$(CC) -E -P $(srcdir)/cmdnames.h 2> /dev/null | \
|
||||
egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
|
||||
|
||||
ccmd: create-commands.c
|
||||
$(CC) create-commands.c -o ccmd
|
||||
ccmd: $(srcdir)/create-commands.c
|
||||
$(CC) $(srcdir)/create-commands.c -o ccmd
|
||||
|
||||
command-lines.h: ccmd
|
||||
./ccmd --output struct command-lines.in > command-lines.h
|
||||
./ccmd --output count command-lines.in > command-lines-count.h
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
command-lines.h: $(srcdir)/command-lines.in ccmd
|
||||
$(top_builddir)/tools/ccmd --output struct $(srcdir)/command-lines.in > $@
|
||||
|
||||
command-lines-count.h: $(srcdir)/command-lines.in ccmd
|
||||
$(top_builddir)/tools/ccmd --output count $(srcdir)/command-lines.in > $@
|
||||
|
||||
# move properly to configure
|
||||
WC = /usr/bin/wc
|
||||
GREP = /bin/grep
|
||||
SORT = /bin/sort
|
||||
CUT = /bin/cut
|
||||
SED = /bin/sed
|
||||
|
||||
# FIXME Add licence text from template file
|
||||
command-lines-count-new.h: $(srcdir)/command-lines.in ccmd Makefile
|
||||
set -o pipefail && \
|
||||
(echo -n "#define COMMAND_COUNT " && \
|
||||
$(GREP) '^ID:' $(srcdir)/command-lines.in | $(WC) -l && \
|
||||
echo -e "enum {\n\tno_CMD," && \
|
||||
$(GREP) '^ID:' $(srcdir)/command-lines.in | $(CUT) -d\ -f2 | $(SORT) -u | $(SED) 's/\(.*\)/\t&_CMD,/' && \
|
||||
echo -e "\tCOMMAND_ID_COUNT,\n};" \
|
||||
) > $@
|
||||
|
||||
$(SOURCES:%.c=%.d): command-lines.h command-lines-count.h
|
||||
|
||||
ifneq ("$(CFLOW_CMD)", "")
|
||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
||||
|
1580
tools/args.h
1580
tools/args.h
File diff suppressed because it is too large
Load Diff
@@ -264,7 +264,7 @@ RULE: --alloc --discards --zero --cachemode --cachepolicy --cachesettings not lv
|
||||
# like above, it was previouly allowed in combination.
|
||||
|
||||
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
||||
OO: --activate Activate, OO_LVCHANGE
|
||||
OO: --activate Active, OO_LVCHANGE
|
||||
ID: lvchange_resync
|
||||
DESC: Resyncronize a mirror or raid LV.
|
||||
RULE: all not lv_is_pvmove lv_is_locked
|
||||
@@ -517,6 +517,15 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
lvconvert --mergethin LV_thin ...
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_merge_thin
|
||||
DESC: Merge thin LV into its origin LV.
|
||||
RULE: all not lv_is_locked lv_is_pvmove lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
|
||||
RULE: all and lv_is_visible
|
||||
|
||||
---
|
||||
|
||||
# lvconvert snapshot-related utilities
|
||||
# Create a new command set for these and migrate them out of lvconvert?
|
||||
|
||||
@@ -632,12 +641,7 @@ OO_LVCREATE_CACHE: --cachemode CacheMode, --cachepolicy String, --cachesettings
|
||||
|
||||
OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksize SizeKB
|
||||
|
||||
# FIXME: it's silly to include --mirrors 0 here. Fix the tests to not use
|
||||
# --mirrors 0 in commands that do not accept any non-zero --mirrors
|
||||
# option, and then remove this. Accepting an option, only so that the
|
||||
# option's value can invalidate the use of the option is not advisable.
|
||||
|
||||
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool, --mirrors 0
|
||||
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool
|
||||
|
||||
OO_LVCREATE_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB,
|
||||
--regionsize SizeMB, --minrecoveryrate SizeKB, --maxrecoveryrate SizeKB
|
||||
@@ -660,15 +664,10 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
---
|
||||
|
||||
# FIXME: consider removing the --mirrors 0, --stripes 1 options
|
||||
# and just reporting an error (or ignoring) if mirrors or stripes
|
||||
# options are given. Same reasoning as above: it's confusing to
|
||||
# advertise an option when the only value accepted for the option
|
||||
# makes the option do nothing.
|
||||
|
||||
lvcreate --type linear --size SizeMB VG
|
||||
OO: --mirrors 0, --stripes 1, OO_LVCREATE
|
||||
OO: OO_LVCREATE
|
||||
OP: PV ...
|
||||
IO: --mirrors 0, --stripes 1
|
||||
ID: lvcreate_linear
|
||||
DESC: Create a linear LV.
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
@@ -678,8 +677,9 @@ FLAGS: SECONDARY_SYNTAX
|
||||
# to people to not see the name parameter.
|
||||
|
||||
lvcreate --size SizeMB VG
|
||||
OO: --type linear, --mirrors 0, --stripes 1, OO_LVCREATE
|
||||
OO: --type linear, OO_LVCREATE
|
||||
OP: PV ...
|
||||
IO: --mirrors 0, --stripes 1
|
||||
ID: lvcreate_linear
|
||||
DESC: Create a linear LV (default --type linear).
|
||||
DESC: When --name is omitted, the name is generated.
|
||||
@@ -769,6 +769,7 @@ lvcreate --type thin-pool --size SizeMB VG
|
||||
OO: --thinpool LV_new, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thinpool
|
||||
DESC: Create a thin pool.
|
||||
|
||||
@@ -777,6 +778,7 @@ lvcreate --thin --size SizeMB VG
|
||||
OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thinpool
|
||||
DESC: Create a thin pool (variant, infers --type thin-pool).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
@@ -786,6 +788,7 @@ lvcreate --size SizeMB --thinpool LV_new VG
|
||||
OO: --thin, --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thinpool
|
||||
DESC: Create a thin pool named by the --thinpool arg
|
||||
DESC: (variant, infers --type thin-pool).
|
||||
@@ -817,12 +820,14 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool VG
|
||||
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol
|
||||
DESC: Create a thin LV in a thin pool.
|
||||
|
||||
# alternate form of lvcreate --type thin
|
||||
lvcreate --type thin --virtualsize SizeMB LV_thinpool
|
||||
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol
|
||||
DESC: Create a thin LV in a thin pool named in the first arg
|
||||
DESC: (variant, also see --thinpool for naming pool).
|
||||
@@ -834,6 +839,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
# alternate form of lvcreate --type thin
|
||||
lvcreate --virtualsize SizeMB --thinpool LV_thinpool VG
|
||||
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol
|
||||
DESC: Create a thin LV in a thin pool (variant, infers --type thin).
|
||||
FLAGS: SECONDARY_SYNTAX
|
||||
@@ -841,6 +847,7 @@ FLAGS: SECONDARY_SYNTAX
|
||||
# alternate form of lvcreate --type thin
|
||||
lvcreate --virtualsize SizeMB LV_thinpool
|
||||
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol
|
||||
DESC: Create a thin LV in the thin pool named in the first arg
|
||||
DESC: (variant, infers --type thin, also see --thinpool for
|
||||
@@ -851,12 +858,14 @@ FLAGS: SECONDARY_SYNTAX
|
||||
|
||||
lvcreate --type thin LV_thin
|
||||
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_snapshot
|
||||
DESC: Create a thin LV that is a snapshot of an existing thin LV.
|
||||
|
||||
# alternate form of lvcreate --type thin
|
||||
lvcreate --thin LV_thin
|
||||
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_snapshot
|
||||
DESC: Create a thin LV that is a snapshot of an existing thin LV
|
||||
DESC: (infers --type thin).
|
||||
@@ -865,33 +874,27 @@ FLAGS: SECONDARY_SYNTAX
|
||||
# alternate form of lvcreate --type thin
|
||||
lvcreate --snapshot LV_thin
|
||||
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_snapshot
|
||||
DESC: Create a thin LV that is a snapshot of an existing thin LV
|
||||
DESC: (infers --type thin).
|
||||
|
||||
lvcreate --type thin --thinpool LV_thinpool LV
|
||||
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_snapshot_of_external
|
||||
DESC: Create a thin LV that is a snapshot of an external origin LV.
|
||||
|
||||
# alternate form of lvcreate --type thin --thinpool LV_thinpool LV
|
||||
lvcreate --snapshot --thinpool LV_thinpool LV
|
||||
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_snapshot_of_external
|
||||
DESC: Create a thin LV that is a snapshot of an external origin LV
|
||||
DESC: (infers --type thin).
|
||||
|
||||
---
|
||||
|
||||
lvconvert --mergethin LV_thin ...
|
||||
OO: OO_LVCONVERT
|
||||
ID: lvconvert_merge_thin
|
||||
DESC: Merge thin LV into its origin LV.
|
||||
RULE: all not lv_is_locked lv_is_pvmove lv_is_merging_origin lv_is_virtual_origin lv_is_external_origin lv_is_merging_cow
|
||||
RULE: all and lv_is_visible
|
||||
|
||||
---
|
||||
|
||||
# stripes option is not intuitive when creating a thin LV,
|
||||
# but here it applies to creating the new thin pool that
|
||||
# is used for the thin LV
|
||||
@@ -912,6 +915,7 @@ lvcreate --type thin --virtualsize SizeMB --size SizeMB --thinpool LV_new
|
||||
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol_and_thinpool
|
||||
DESC: Create a thin LV, first creating a thin pool for it,
|
||||
DESC: where the new thin pool is named by the --thinpool arg.
|
||||
@@ -921,6 +925,7 @@ lvcreate --thin --virtualsize SizeMB --size SizeMB --thinpool LV_new
|
||||
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol_and_thinpool
|
||||
DESC: Create a thin LV, first creating a thin pool for it,
|
||||
DESC: where the new thin pool is named by the --thinpool arg
|
||||
@@ -932,6 +937,7 @@ lvcreate --type thin --virtualsize SizeMB --size SizeMB LV_new|VG
|
||||
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol_and_thinpool
|
||||
DESC: Create a thin LV, first creating a thin pool for it,
|
||||
DESC: where the new thin pool is named in the first arg,
|
||||
@@ -944,6 +950,7 @@ lvcreate --thin --virtualsize SizeMB --size SizeMB LV_new|VG
|
||||
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol_and_thinpool
|
||||
DESC: Create a thin LV, first creating a thin pool for it,
|
||||
DESC: where the new thin pool is named in the first arg,
|
||||
@@ -957,6 +964,7 @@ lvcreate --size SizeMB --virtualsize SizeMB VG
|
||||
OO: --type thin, --type snapshot, --thin, --snapshot, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||
--stripes Number, --stripesize SizeKB
|
||||
OP: PV ...
|
||||
IO: --mirrors 0
|
||||
ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot
|
||||
DESC: Create a thin LV, first creating a thin pool for it
|
||||
DESC: (infers --type thin).
|
||||
@@ -1327,7 +1335,7 @@ OO_VGCHANGE: --autobackup Bool, --ignoremonitoring, --ignoreskippedcluster,
|
||||
# because it can function as a required opt.
|
||||
|
||||
OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
|
||||
--logicalvolume Number, --maxphysicalvolumes Number, --alloc Alloc, --uuid,
|
||||
--logicalvolume Number, --maxphysicalvolumes Uint32, --alloc Alloc, --uuid,
|
||||
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
|
||||
--profile String, --detachprofile, --metadataprofile String
|
||||
@@ -1394,7 +1402,7 @@ ID: vgconvert_general
|
||||
|
||||
vgcreate VG_new PV ...
|
||||
OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogicalvolumes Number,
|
||||
--maxphysicalvolumes Number, --metadataprofile String, --metadatatype MetadataType,
|
||||
--maxphysicalvolumes Uint32, --metadataprofile String, --metadatatype MetadataType,
|
||||
--physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number,
|
||||
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
|
||||
@@ -1527,7 +1535,7 @@ OO_VGSPLIT: --autobackup Bool
|
||||
|
||||
# used only when the destination VG is new
|
||||
OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
|
||||
--maxlogicalvolumes Number, --maxphysicalvolumes Number,
|
||||
--maxlogicalvolumes Number, --maxphysicalvolumes Uint32,
|
||||
--metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG
|
||||
|
||||
vgsplit VG VG PV ...
|
||||
@@ -1581,6 +1589,7 @@ formats
|
||||
ID: formats_general
|
||||
|
||||
help
|
||||
OP: String ...
|
||||
ID: help_general
|
||||
|
||||
version
|
||||
|
@@ -51,8 +51,9 @@ struct command_name {
|
||||
*/
|
||||
|
||||
/* arg_def flags */
|
||||
#define ARG_DEF_FLAG_NEW 1 << 0
|
||||
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
|
||||
#define ARG_DEF_FLAG_NEW_VG 1 << 0
|
||||
#define ARG_DEF_FLAG_NEW_LV 1 << 1
|
||||
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 2
|
||||
|
||||
static inline int val_bit_is_set(uint64_t val_bits, int val_enum)
|
||||
{
|
||||
@@ -144,6 +145,7 @@ struct cmd_rule {
|
||||
#define CMD_OO_ARGS 150 /* optional opt args */
|
||||
#define CMD_RP_ARGS 8 /* required positional args */
|
||||
#define CMD_OP_ARGS 8 /* optional positional args */
|
||||
#define CMD_IO_ARGS 8 /* ignore opt args */
|
||||
#define CMD_MAX_RULES 32 /* max number of rules per command def */
|
||||
|
||||
/*
|
||||
@@ -185,12 +187,16 @@ struct command {
|
||||
/* optional positional args */
|
||||
struct pos_arg optional_pos_args[CMD_OP_ARGS];
|
||||
|
||||
/* unused opt args, are ignored instead of causing an error */
|
||||
struct opt_arg ignore_opt_args[CMD_IO_ARGS];
|
||||
|
||||
struct cmd_rule rules[CMD_MAX_RULES];
|
||||
|
||||
int ro_count;
|
||||
int oo_count;
|
||||
int rp_count;
|
||||
int op_count;
|
||||
int io_count;
|
||||
|
||||
/* used for processing current position */
|
||||
int pos_count;
|
||||
|
@@ -34,6 +34,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int int_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int uint32_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
int major_arg(struct cmd_context *cmd, struct arg_values *av) { return 0; }
|
||||
@@ -67,6 +68,7 @@ struct opt_name {
|
||||
int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
|
||||
uint32_t unused1;
|
||||
uint32_t unused2;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
/* also see val_props in tools.h and vals.h */
|
||||
@@ -103,7 +105,7 @@ enum {
|
||||
/* create foo_ARG enums for --option's */
|
||||
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
#define arg(a, b, c, d, e, f, g) a ,
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
};
|
||||
@@ -135,7 +137,7 @@ static struct val_name val_names[VAL_COUNT + 1] = {
|
||||
/* create table of option names, e.g. --foo, and corresponding enum from args.h */
|
||||
|
||||
static struct opt_name opt_names[ARG_COUNT + 1] = {
|
||||
#define arg(a, b, c, d, e, f) { # a, a, b, "", "--" c, d, e, f },
|
||||
#define arg(a, b, c, d, e, f, g) { # a, a, b, "", "--" c, d, e, f, g },
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
};
|
||||
@@ -179,11 +181,18 @@ static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
|
||||
#undef xx
|
||||
};
|
||||
|
||||
/* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */
|
||||
|
||||
static struct opt_name *opt_names_alpha[ARG_COUNT + 1];
|
||||
|
||||
#define MAX_LINE 1024
|
||||
#define MAX_LINE_ARGC 256
|
||||
|
||||
#define REQUIRED 1
|
||||
#define OPTIONAL 0
|
||||
#define DESC_LINE 256
|
||||
|
||||
#define REQUIRED 1 /* required option */
|
||||
#define OPTIONAL 0 /* optional option */
|
||||
#define IGNORE -1 /* ignore option */
|
||||
|
||||
struct oo_line {
|
||||
char *name;
|
||||
@@ -543,6 +552,13 @@ static int is_oo_line(char *str)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_io_line(char *str)
|
||||
{
|
||||
if (!strncmp(str, "IO:", 3))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_op_line(char *str)
|
||||
{
|
||||
if (!strncmp(str, "OP:", 3))
|
||||
@@ -608,8 +624,12 @@ static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
|
||||
if ((val_enum == lv_VAL) && strstr(name, "_"))
|
||||
def->lvt_bits = lv_to_bits(name);
|
||||
|
||||
if (strstr(name, "_new"))
|
||||
def->flags |= ARG_DEF_FLAG_NEW;
|
||||
if (strstr(name, "_new")) {
|
||||
if (val_enum == lv_VAL)
|
||||
def->flags |= ARG_DEF_FLAG_NEW_LV;
|
||||
else if (val_enum == vg_VAL)
|
||||
def->flags |= ARG_DEF_FLAG_NEW_VG;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,9 +681,12 @@ static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
|
||||
def->lvt_bits = lv_to_bits(name);
|
||||
}
|
||||
|
||||
if ((val_enum == vg_VAL) || (val_enum == lv_VAL) || (val_enum == pv_VAL)) {
|
||||
if (strstr(name, "_new"))
|
||||
def->flags |= ARG_DEF_FLAG_NEW;
|
||||
if (strstr(name, "_new")) {
|
||||
if (val_enum == lv_VAL)
|
||||
def->flags |= ARG_DEF_FLAG_NEW_LV;
|
||||
else if (val_enum == vg_VAL)
|
||||
def->flags |= ARG_DEF_FLAG_NEW_VG;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -788,10 +811,14 @@ static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int requ
|
||||
|
||||
opt = opt_str_to_num(str);
|
||||
skip:
|
||||
if (required)
|
||||
if (required > 0)
|
||||
cmd->required_opt_args[cmd->ro_count++].opt = opt;
|
||||
else
|
||||
else if (!required)
|
||||
cmd->optional_opt_args[cmd->oo_count++].opt = opt;
|
||||
else if (required < 0)
|
||||
cmd->ignore_opt_args[cmd->io_count++].opt = opt;
|
||||
else
|
||||
exit(1);
|
||||
|
||||
*takes_arg = opt_names[opt].val_enum ? 1 : 0;
|
||||
}
|
||||
@@ -814,10 +841,14 @@ static void update_prev_opt_arg(struct command *cmd, char *str, int required)
|
||||
|
||||
set_opt_def(cmd, str, &def);
|
||||
|
||||
if (required)
|
||||
if (required > 0)
|
||||
cmd->required_opt_args[cmd->ro_count-1].def = def;
|
||||
else
|
||||
else if (!required)
|
||||
cmd->optional_opt_args[cmd->oo_count-1].def = def;
|
||||
else if (required < 0)
|
||||
cmd->ignore_opt_args[cmd->io_count-1].def = def;
|
||||
else
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void add_pos_arg(struct command *cmd, char *str, int required)
|
||||
@@ -882,6 +913,24 @@ static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
static void add_ignore_opt_line(struct command *cmd, int argc, char *argv[])
|
||||
{
|
||||
int takes_arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!i && !strncmp(argv[i], "IO:", 3))
|
||||
continue;
|
||||
if (is_opt_name(argv[i]))
|
||||
add_opt_arg(cmd, argv[i], &takes_arg, IGNORE);
|
||||
else if (takes_arg)
|
||||
update_prev_opt_arg(cmd, argv[i], IGNORE);
|
||||
else
|
||||
printf("Can't parse argc %d argv %s prev %s\n",
|
||||
i, argv[i], argv[i-1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* process what follows OP:, which are optional pos args */
|
||||
|
||||
static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
|
||||
@@ -1007,10 +1056,10 @@ static void print_def(struct arg_def *def, int usage)
|
||||
}
|
||||
}
|
||||
|
||||
if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) {
|
||||
if (def->flags & ARG_DEF_FLAG_NEW)
|
||||
printf("_new");
|
||||
}
|
||||
if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG))
|
||||
printf("_new");
|
||||
if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV))
|
||||
printf("_new");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1147,10 +1196,15 @@ static char *flags_to_str(int flags)
|
||||
strcat(buf_flags, " | ");
|
||||
strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
|
||||
}
|
||||
if (flags & ARG_DEF_FLAG_NEW) {
|
||||
if (flags & ARG_DEF_FLAG_NEW_VG) {
|
||||
if (buf_flags[0])
|
||||
strcat(buf_flags, " | ");
|
||||
strcat(buf_flags, "ARG_DEF_FLAG_NEW");
|
||||
strcat(buf_flags, "ARG_DEF_FLAG_NEW_VG");
|
||||
}
|
||||
if (flags & ARG_DEF_FLAG_NEW_LV) {
|
||||
if (buf_flags[0])
|
||||
strcat(buf_flags, " | ");
|
||||
strcat(buf_flags, "ARG_DEF_FLAG_NEW_LV");
|
||||
}
|
||||
|
||||
return buf_flags;
|
||||
@@ -1672,12 +1726,15 @@ static void print_def_man(struct arg_def *def, int usage)
|
||||
printf("\\fP");
|
||||
}
|
||||
|
||||
if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) {
|
||||
if (def->flags & ARG_DEF_FLAG_NEW) {
|
||||
printf("\\fI");
|
||||
printf("_new");
|
||||
printf("\\fP");
|
||||
}
|
||||
if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG)) {
|
||||
printf("\\fI");
|
||||
printf("_new");
|
||||
printf("\\fP");
|
||||
}
|
||||
if ((val_enum == lv_VAL) && (def->flags & ARG_DEF_FLAG_NEW_LV)) {
|
||||
printf("\\fI");
|
||||
printf("_new");
|
||||
printf("\\fP");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2000,6 +2057,23 @@ void print_man_usage(struct command *cmd)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* common options listed in the usage section.
|
||||
*
|
||||
* For commands with only one variant, this is only
|
||||
* the options which are common to all lvm commands
|
||||
* (in lvm_all, see is_lvm_all_opt).
|
||||
*
|
||||
* For commands with more than one variant, this
|
||||
* is the set of options common to all variants
|
||||
* (in cname->common_options), (which obviously
|
||||
* includes the options common to all lvm commands.)
|
||||
*
|
||||
* List ordering:
|
||||
* options with short+long names, alphabetically,
|
||||
* then options with only long names, alphabetically
|
||||
*/
|
||||
|
||||
void print_man_usage_common(struct command *cmd)
|
||||
{
|
||||
struct cmd_name *cname;
|
||||
@@ -2013,23 +2087,17 @@ void print_man_usage_common(struct command *cmd)
|
||||
printf(".RS 4\n");
|
||||
printf("[");
|
||||
|
||||
/*
|
||||
* when there's more than one variant, options that
|
||||
* are common to all commands with a common name.
|
||||
*/
|
||||
|
||||
if (cname->variants < 2)
|
||||
goto all;
|
||||
|
||||
/* print those with short opts */
|
||||
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
|
||||
for (i = 0; i < ARG_COUNT; i++) {
|
||||
opt_enum = opt_names_alpha[i]->opt_enum;
|
||||
|
||||
if (!cname->common_options[opt_enum])
|
||||
continue;
|
||||
|
||||
if (!opt_names[opt_enum].short_opt)
|
||||
continue;
|
||||
|
||||
if (is_lvm_all_opt(opt_enum))
|
||||
if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
|
||||
continue;
|
||||
|
||||
if (sep) {
|
||||
@@ -2057,14 +2125,16 @@ void print_man_usage_common(struct command *cmd)
|
||||
}
|
||||
|
||||
/* print those without short opts */
|
||||
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
|
||||
for (i = 0; i < ARG_COUNT; i++) {
|
||||
opt_enum = opt_names_alpha[i]->opt_enum;
|
||||
|
||||
if (!cname->common_options[opt_enum])
|
||||
continue;
|
||||
|
||||
if (opt_names[opt_enum].short_opt)
|
||||
continue;
|
||||
|
||||
if (is_lvm_all_opt(opt_enum))
|
||||
if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
|
||||
continue;
|
||||
|
||||
if (sep) {
|
||||
@@ -2090,67 +2160,108 @@ void print_man_usage_common(struct command *cmd)
|
||||
break;
|
||||
}
|
||||
}
|
||||
all:
|
||||
/* options that are common to all lvm commands */
|
||||
|
||||
/* those with short opts */
|
||||
for (oo = 0; oo < lvm_all.oo_count; oo++) {
|
||||
opt_enum = lvm_all.optional_opt_args[oo].opt;
|
||||
|
||||
if (!opt_names[opt_enum].short_opt)
|
||||
continue;
|
||||
|
||||
if (sep) {
|
||||
printf(",");
|
||||
printf("\n.br\n");
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf(" \\fB-%c\\fP|\\fB%s\\fP",
|
||||
opt_names[opt_enum].short_opt,
|
||||
man_long_opt_name(cmd->name, opt_enum));
|
||||
|
||||
if (lvm_all.optional_opt_args[oo].def.val_bits) {
|
||||
printf(" ");
|
||||
print_def(&lvm_all.optional_opt_args[oo].def, 1);
|
||||
}
|
||||
sep = 1;
|
||||
}
|
||||
|
||||
/* those without short opts */
|
||||
for (oo = 0; oo < lvm_all.oo_count; oo++) {
|
||||
opt_enum = lvm_all.optional_opt_args[oo].opt;
|
||||
|
||||
if (opt_names[opt_enum].short_opt)
|
||||
continue;
|
||||
|
||||
if (sep) {
|
||||
printf(",");
|
||||
printf("\n.br\n");
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
/* space alignment without short opt */
|
||||
printf(" ");
|
||||
|
||||
printf(" \\fB%s\\fP", man_long_opt_name(cmd->name, opt_enum));
|
||||
|
||||
if (lvm_all.optional_opt_args[oo].def.val_bits) {
|
||||
printf(" ");
|
||||
print_def(&lvm_all.optional_opt_args[oo].def, 1);
|
||||
}
|
||||
sep = 1;
|
||||
}
|
||||
printf(" ]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
void print_man_all_options(struct cmd_name *cname)
|
||||
/*
|
||||
* Format of description, when different command names have
|
||||
* different descriptions:
|
||||
*
|
||||
* "#cmdname1"
|
||||
* "text foo goes here"
|
||||
* "a second line of text."
|
||||
* "#cmdname2"
|
||||
* "text bar goes here"
|
||||
* "another line of text."
|
||||
*
|
||||
* When called for cmdname2, this function should just print:
|
||||
*
|
||||
* "text bar goes here"
|
||||
* "another line of text."
|
||||
*/
|
||||
|
||||
static void print_man_option_desc(struct cmd_name *cname, int opt_enum)
|
||||
{
|
||||
const char *desc = opt_names[opt_enum].desc;
|
||||
char buf[DESC_LINE];
|
||||
int started_cname = 0;
|
||||
int line_count = 0;
|
||||
int di, bi;
|
||||
|
||||
if (desc[0] != '#') {
|
||||
printf("%s", desc);
|
||||
return;
|
||||
}
|
||||
|
||||
for (di = 0; di < strlen(desc); di++) {
|
||||
buf[bi++] = desc[di];
|
||||
|
||||
if (bi == DESC_LINE) {
|
||||
printf("print_man_option_desc line too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf[bi-1] != '\n')
|
||||
continue;
|
||||
|
||||
if (buf[0] != '#') {
|
||||
if (started_cname) {
|
||||
printf("%s", buf);
|
||||
line_count++;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bi = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Line starting with #cmdname */
|
||||
|
||||
/*
|
||||
* Must be starting a new command name.
|
||||
* If no lines have been printed, multiple command names
|
||||
* are using the same text. If lines have been printed,
|
||||
* then the start of a new command name means the end
|
||||
* of text for the current command name.
|
||||
*/
|
||||
if (line_count && started_cname)
|
||||
return;
|
||||
|
||||
if (!strncmp(buf + 1, cname->name, strlen(cname->name))) {
|
||||
/* The start of our command name. */
|
||||
started_cname = 1;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bi = 0;
|
||||
} else {
|
||||
/* The start of another command name. */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bi = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bi && started_cname)
|
||||
printf("%s", buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print a list of all options names for a given
|
||||
* command name, listed by:
|
||||
* options with short+long names, alphabetically,
|
||||
* then options with only long names, alphabetically
|
||||
*/
|
||||
|
||||
void print_man_all_options_list(struct cmd_name *cname)
|
||||
{
|
||||
int opt_enum, val_enum;
|
||||
int sep = 0;
|
||||
int i;
|
||||
|
||||
/* print those with both short and long opts */
|
||||
for (i = 0; i < ARG_COUNT; i++) {
|
||||
opt_enum = opt_names_alpha[i]->opt_enum;
|
||||
|
||||
/* print those with short opts */
|
||||
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
|
||||
if (!cname->all_options[opt_enum])
|
||||
continue;
|
||||
|
||||
@@ -2182,7 +2293,9 @@ void print_man_all_options(struct cmd_name *cname)
|
||||
}
|
||||
|
||||
/* print those without short opts */
|
||||
for (opt_enum = 0; opt_enum < ARG_COUNT; opt_enum++) {
|
||||
for (i = 0; i < ARG_COUNT; i++) {
|
||||
opt_enum = opt_names_alpha[i]->opt_enum;
|
||||
|
||||
if (!cname->all_options[opt_enum])
|
||||
continue;
|
||||
|
||||
@@ -2215,7 +2328,79 @@ void print_man_all_options(struct cmd_name *cname)
|
||||
}
|
||||
}
|
||||
|
||||
#define DESC_LINE 256
|
||||
/*
|
||||
* All options used for a given command name, along with descriptions.
|
||||
* listed in order of:
|
||||
* 1. options that are not common to all lvm commands, alphabetically
|
||||
* 2. options common to all lvm commands, alphabetically
|
||||
*/
|
||||
|
||||
void print_man_all_options_desc(struct cmd_name *cname)
|
||||
{
|
||||
int opt_enum, val_enum;
|
||||
int print_common = 0;
|
||||
int sep = 0;
|
||||
int i;
|
||||
|
||||
again:
|
||||
/*
|
||||
* Loop 1: print options that are not common to all lvm commands.
|
||||
* Loop 2: print options common to all lvm commands (lvm_all)
|
||||
*/
|
||||
|
||||
for (i = 0; i < ARG_COUNT; i++) {
|
||||
opt_enum = opt_names_alpha[i]->opt_enum;
|
||||
|
||||
if (!cname->all_options[opt_enum])
|
||||
continue;
|
||||
|
||||
if (!print_common && is_lvm_all_opt(opt_enum))
|
||||
continue;
|
||||
|
||||
if (print_common && !is_lvm_all_opt(opt_enum))
|
||||
continue;
|
||||
|
||||
if (sep)
|
||||
printf("\n.br\n");
|
||||
|
||||
printf("\n.TP\n");
|
||||
|
||||
if (opt_names[opt_enum].short_opt) {
|
||||
printf("\\fB-%c\\fP|\\fB%s\\fP",
|
||||
opt_names[opt_enum].short_opt,
|
||||
man_long_opt_name(cname->name, opt_enum));
|
||||
} else {
|
||||
printf("\\fB%s\\fP", man_long_opt_name(cname->name, opt_enum));
|
||||
}
|
||||
|
||||
val_enum = opt_names[opt_enum].val_enum;
|
||||
|
||||
if (!val_names[val_enum].fn) {
|
||||
/* takes no arg */
|
||||
} else if (!val_names[val_enum].usage) {
|
||||
printf(" ");
|
||||
printf("\\fI");
|
||||
printf("%s", val_names[val_enum].name);
|
||||
printf("\\fP");
|
||||
} else {
|
||||
printf(" ");
|
||||
print_val_man(val_names[val_enum].usage);
|
||||
}
|
||||
|
||||
if (opt_names[opt_enum].desc) {
|
||||
printf("\n");
|
||||
printf(".br\n");
|
||||
print_man_option_desc(cname, opt_enum);
|
||||
}
|
||||
|
||||
sep = 1;
|
||||
}
|
||||
|
||||
if (!print_common) {
|
||||
print_common = 1;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
void print_desc_man(const char *desc)
|
||||
{
|
||||
@@ -2288,6 +2473,12 @@ void print_man_command(void)
|
||||
printf("Common options:\n");
|
||||
printf(".\n");
|
||||
print_man_usage_common(prev_cmd);
|
||||
|
||||
printf("\n");
|
||||
printf(".SH OPTIONS\n");
|
||||
printf(".br\n");
|
||||
print_man_all_options_desc(cname);
|
||||
|
||||
prev_cmd = NULL;
|
||||
}
|
||||
|
||||
@@ -2346,7 +2537,7 @@ void print_man_command(void)
|
||||
/* listing them all when there's only 1 or 2 is just repetative */
|
||||
if (cname->variants > 2) {
|
||||
printf(".P\n");
|
||||
print_man_all_options(cname);
|
||||
print_man_all_options_list(cname);
|
||||
printf("\n");
|
||||
printf(".P\n");
|
||||
printf("\n");
|
||||
@@ -2369,6 +2560,12 @@ void print_man_command(void)
|
||||
printf("Common options:\n");
|
||||
printf(".\n");
|
||||
print_man_usage_common(cmd);
|
||||
|
||||
printf("\n");
|
||||
printf(".SH OPTIONS\n");
|
||||
printf(".br\n");
|
||||
print_man_all_options_desc(cname);
|
||||
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
@@ -2379,7 +2576,7 @@ void print_man_command(void)
|
||||
void print_command_struct(int only_usage)
|
||||
{
|
||||
struct command *cmd;
|
||||
int i, j, ro, rp, oo, op, ru, ruo;
|
||||
int i, j, ro, rp, oo, op, ru, ruo, io;
|
||||
|
||||
include_optional_opt_args(&lvm_all, "OO_USAGE_COMMON");
|
||||
|
||||
@@ -2405,6 +2602,7 @@ void print_command_struct(int only_usage)
|
||||
printf("commands[%d].rp_count = %d;\n", i, cmd->rp_count);
|
||||
printf("commands[%d].oo_count = %d;\n", i, cmd->oo_count);
|
||||
printf("commands[%d].op_count = %d;\n", i, cmd->op_count);
|
||||
printf("commands[%d].io_count = %d;\n", i, cmd->io_count);
|
||||
printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count);
|
||||
|
||||
if (cmd->cmd_flags)
|
||||
@@ -2510,6 +2708,35 @@ void print_command_struct(int only_usage)
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->io_count) {
|
||||
for (io = 0; io < cmd->io_count; io++) {
|
||||
printf("commands[%d].ignore_opt_args[%d].opt = %s;\n",
|
||||
i, io, opt_to_enum_str(cmd->ignore_opt_args[io].opt));
|
||||
|
||||
if (!cmd->ignore_opt_args[io].def.val_bits)
|
||||
continue;
|
||||
|
||||
printf("commands[%d].ignore_opt_args[%d].def.val_bits = %s;\n",
|
||||
i, io, val_bits_to_str(cmd->ignore_opt_args[io].def.val_bits));
|
||||
|
||||
if (cmd->ignore_opt_args[io].def.lvt_bits)
|
||||
printf("commands[%d].ignore_opt_args[%d].def.lvt_bits = %s;\n",
|
||||
i, io, lvt_bits_to_str(cmd->ignore_opt_args[io].def.lvt_bits));
|
||||
|
||||
if (cmd->ignore_opt_args[io].def.flags)
|
||||
printf("commands[%d].ignore_opt_args[%d].def.flags = %s;\n",
|
||||
i, io, flags_to_str(cmd->ignore_opt_args[io].def.flags));
|
||||
|
||||
if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, constnum_VAL))
|
||||
printf("commands[%d].ignore_opt_args[%d].def.num = %d;\n",
|
||||
i, io, cmd->ignore_opt_args[io].def.num);
|
||||
|
||||
if (val_bit_is_set(cmd->ignore_opt_args[io].def.val_bits, conststr_VAL))
|
||||
printf("commands[%d].ignore_opt_args[%d].def.str = \"%s\";\n",
|
||||
i, io, cmd->ignore_opt_args[io].def.str ?: "NULL");
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd->op_count) {
|
||||
for (op = 0; op < cmd->op_count; op++) {
|
||||
printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
|
||||
@@ -2650,6 +2877,23 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
static int long_name_compare(const void *on1, const void *on2)
|
||||
{
|
||||
struct opt_name **optname1 = (void *)on1;
|
||||
struct opt_name **optname2 = (void *)on2;
|
||||
return strcmp((*optname1)->long_opt + 2, (*optname2)->long_opt + 2);
|
||||
}
|
||||
|
||||
static void create_opt_names_alpha(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARG_COUNT; i++)
|
||||
opt_names_alpha[i] = &opt_names[i];
|
||||
|
||||
qsort(opt_names_alpha, ARG_COUNT, sizeof(long), long_name_compare);
|
||||
}
|
||||
|
||||
void print_command_list(void)
|
||||
{
|
||||
int i;
|
||||
@@ -2674,15 +2918,31 @@ void print_option_list(void)
|
||||
opt_names[i].short_opt ? opt_names[i].short_opt : 0);
|
||||
}
|
||||
|
||||
void print_option_alpha_list(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARG_COUNT; i++)
|
||||
printf("%d %s %s %c (%d)\n",
|
||||
opt_names_alpha[i]->opt_enum, opt_names_alpha[i]->name,
|
||||
opt_names_alpha[i]->long_opt, opt_names_alpha[i]->short_opt ?: ' ',
|
||||
opt_names_alpha[i]->short_opt ? opt_names_alpha[i]->short_opt : 0);
|
||||
}
|
||||
|
||||
static void print_help(int argc, char *argv[])
|
||||
{
|
||||
printf("%s --output struct|count|usage|expanded <filename>\n", argv[0]);
|
||||
printf("%s [options] --output <format> <filename>\n", argv[0]);
|
||||
printf("\n");
|
||||
printf("output formats:\n");
|
||||
printf("struct: print C structures for command-lines.h\n");
|
||||
printf("count: print defines and enums for command-lines-count.h\n");
|
||||
printf("ambiguous: print commands differing only by LV types\n");
|
||||
printf("usage: print usage format.\n");
|
||||
printf("expanded: print expanded input format.\n");
|
||||
printf("man: print man page format.\n");
|
||||
printf("\n");
|
||||
printf("options:\n");
|
||||
printf("-c|--man-command <commandname> man output for one command name\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -2706,9 +2966,12 @@ int main(int argc, char *argv[])
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
create_opt_names_alpha();
|
||||
|
||||
if (!strcmp(argv[1], "debug")) {
|
||||
print_command_list();
|
||||
print_option_list();
|
||||
print_option_alpha_list();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2852,6 +3115,14 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
/* IO: ... */
|
||||
if (is_io_line(line_argv[0])) {
|
||||
add_ignore_opt_line(cmd, line_argc, line_argv);
|
||||
prev_was_oo = 0;
|
||||
prev_was_op = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */
|
||||
|
||||
if (prev_was_oo_def) {
|
||||
|
@@ -370,7 +370,7 @@ static int _lvchange_resync(struct cmd_context *cmd, struct logical_volume *lv)
|
||||
/* Separate mirror log or metadata devices so we can clear them */
|
||||
if (!detach_metadata_devices(seg, &device_list)) {
|
||||
log_error("Failed to clear %s %s for %s.",
|
||||
seg->segtype->name, seg_is_raid(seg) ?
|
||||
lvseg_name(seg), seg_is_raid(seg) ?
|
||||
"metadata area" : "mirror log", display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
@@ -1022,6 +1022,12 @@ static int _lvchange_properties_check(struct cmd_context *cmd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vg_is_clustered(lv->vg) && lv_is_cache_origin(lv) && lv_is_raid(lv)) {
|
||||
log_error("Unable to change internal LV %s directly in a cluster.",
|
||||
display_lvname(lv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -2125,10 +2125,17 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
|
||||
if (!lv_update_and_reload(origin))
|
||||
return_0;
|
||||
|
||||
if (!lv_info(cmd, origin, 0, &info, 0, 0) || !info.exists)
|
||||
if (!lv_has_target_type(origin->vg->vgmem, origin, NULL,
|
||||
TARGET_NAME_SNAPSHOT_MERGE)) {
|
||||
/* Race during table reload prevented merging */
|
||||
merge_on_activate = 1;
|
||||
|
||||
} else if (!lv_info(cmd, origin, 0, &info, 0, 0) || !info.exists) {
|
||||
log_print_unless_silent("Conversion starts after activation.");
|
||||
else
|
||||
merge_on_activate = 1;
|
||||
} else {
|
||||
*lv_to_poll = origin;
|
||||
}
|
||||
}
|
||||
|
||||
if (merge_on_activate)
|
||||
|
@@ -210,7 +210,7 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
|
||||
{
|
||||
log_report_t saved_log_report_state = log_get_report_state();
|
||||
char *orig_command_log_selection = NULL;
|
||||
int is_lastlog_cmd = 0, argc, ret;
|
||||
int is_lastlog_cmd = 0, argc, ret, i;
|
||||
char *input = NULL, *args[MAX_ARGS], **argv;
|
||||
|
||||
rl_readline_name = "lvm";
|
||||
@@ -262,6 +262,9 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
|
||||
|
||||
add_history(input);
|
||||
|
||||
for (i = 0; i < MAX_ARGS; i++)
|
||||
args[i] = NULL;
|
||||
|
||||
argv = args;
|
||||
|
||||
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
|
||||
|
@@ -64,7 +64,7 @@ static struct val_props _val_props[VAL_COUNT + 1] = {
|
||||
* Table of valid --option's
|
||||
*/
|
||||
static struct arg_props _arg_props[ARG_COUNT + 1] = {
|
||||
#define arg(a, b, c, d, e, f) {a, b, "", "--" c, d, e, f},
|
||||
#define arg(a, b, c, d, e, f, g) {a, b, "", "--" c, d, e, f, g},
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
};
|
||||
@@ -655,6 +655,14 @@ int int_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *
|
||||
return 1;
|
||||
}
|
||||
|
||||
int uint32_arg(struct cmd_context *cmd, struct arg_values *av)
|
||||
{
|
||||
if (!int_arg(cmd, av) || (av->ui64_value > UINT32_MAX))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int int_arg_with_sign(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
|
||||
{
|
||||
char *ptr;
|
||||
@@ -1154,6 +1162,25 @@ static int _opt_synonym_is_set(struct cmd_context *cmd, int opt_std)
|
||||
return opt_syn && arg_is_set(cmd, opt_syn);
|
||||
}
|
||||
|
||||
static int _command_ignore_opt_matches(struct cmd_context *cmd, int ci, int io)
|
||||
{
|
||||
int opt_enum = commands[ci].ignore_opt_args[io].opt;
|
||||
|
||||
if (val_bit_is_set(commands[ci].ignore_opt_args[io].def.val_bits, conststr_VAL)) {
|
||||
if (!strcmp(commands[ci].ignore_opt_args[io].def.str, arg_str_value(cmd, opt_enum, "")))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val_bit_is_set(commands[ci].ignore_opt_args[io].def.val_bits, constnum_VAL)) {
|
||||
if (commands[ci].ignore_opt_args[io].def.num == arg_int_value(cmd, opt_enum, 0))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro)
|
||||
{
|
||||
int opt_enum = commands[ci].required_opt_args[ro].opt;
|
||||
@@ -1261,7 +1288,7 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp
|
||||
|
||||
#define HELP_LINE_SIZE 1024
|
||||
|
||||
static void _print_usage(const char *usage, int only_required)
|
||||
static void _print_usage(const char *usage_str, int only_required)
|
||||
{
|
||||
char buf[HELP_LINE_SIZE];
|
||||
int optional_ui = 0;
|
||||
@@ -1269,7 +1296,7 @@ static void _print_usage(const char *usage, int only_required)
|
||||
int ui;
|
||||
int bi;
|
||||
|
||||
if (!usage || !strlen(usage))
|
||||
if (!usage_str || !strlen(usage_str))
|
||||
return;
|
||||
|
||||
/*
|
||||
@@ -1286,32 +1313,32 @@ static void _print_usage(const char *usage, int only_required)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bi = 0;
|
||||
|
||||
for (ui = 0; ui < strlen(usage); ui++) {
|
||||
if (!bi && ((usage[ui] == ' ') || (usage[ui] == '\n')))
|
||||
for (ui = 0; ui < strlen(usage_str); ui++) {
|
||||
if (!bi && ((usage_str[ui] == ' ') || (usage_str[ui] == '\n')))
|
||||
continue;
|
||||
|
||||
/* The first "[ " indicates the start of the optional opt_args. */
|
||||
if ((usage[ui] == '[') && (usage[ui+1] == ' ')) {
|
||||
if ((usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) {
|
||||
optional_ui = ui;
|
||||
break;
|
||||
}
|
||||
|
||||
if (usage[ui] == '\0')
|
||||
if (usage_str[ui] == '\0')
|
||||
break;
|
||||
|
||||
if (usage[ui] == '(') {
|
||||
if (usage_str[ui] == '(') {
|
||||
buf[bi++] = '\n';
|
||||
buf[bi++] = '\t';
|
||||
}
|
||||
|
||||
buf[bi++] = usage[ui];
|
||||
buf[bi++] = usage_str[ui];
|
||||
|
||||
if (usage[ui] == ')') {
|
||||
if (usage_str[ui] == ')') {
|
||||
buf[bi++] = '\n';
|
||||
buf[bi++] = '\t';
|
||||
}
|
||||
|
||||
if (usage[ui] == ',') {
|
||||
if (usage_str[ui] == ',') {
|
||||
buf[bi++] = '\n';
|
||||
buf[bi++] = '\t';
|
||||
buf[bi++] = ' ';
|
||||
@@ -1341,25 +1368,25 @@ static void _print_usage(const char *usage, int only_required)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bi = 0;
|
||||
|
||||
for (ui = optional_ui; ui < strlen(usage); ui++) {
|
||||
for (ui = optional_ui; ui < strlen(usage_str); ui++) {
|
||||
|
||||
/* The second "[ " indicates the start of the optional pos_args. */
|
||||
if ((ui > optional_ui) && (usage[ui] == '[') && (usage[ui+1] == ' ')) {
|
||||
if ((ui > optional_ui) && (usage_str[ui] == '[') && (usage_str[ui+1] == ' ')) {
|
||||
optional_pos_ui = ui;
|
||||
break;
|
||||
}
|
||||
|
||||
if (usage[ui] == '\0')
|
||||
if (usage_str[ui] == '\0')
|
||||
break;
|
||||
if (usage[ui] == '\n')
|
||||
if (usage_str[ui] == '\n')
|
||||
break;
|
||||
|
||||
if (!bi)
|
||||
buf[bi++] = '\t';
|
||||
|
||||
buf[bi++] = usage[ui];
|
||||
buf[bi++] = usage_str[ui];
|
||||
|
||||
if (usage[ui] == ',') {
|
||||
if (usage_str[ui] == ',') {
|
||||
buf[bi++] = '\n';
|
||||
buf[bi++] = '\t';
|
||||
buf[bi++] = ' ';
|
||||
@@ -1386,16 +1413,16 @@ static void _print_usage(const char *usage, int only_required)
|
||||
memset(buf, 0, sizeof(buf));
|
||||
bi = 0;
|
||||
|
||||
for (ui = optional_pos_ui; ui < strlen(usage); ui++) {
|
||||
if (usage[ui] == '\0')
|
||||
for (ui = optional_pos_ui; ui < strlen(usage_str); ui++) {
|
||||
if (usage_str[ui] == '\0')
|
||||
break;
|
||||
if (usage[ui] == '\n')
|
||||
if (usage_str[ui] == '\n')
|
||||
break;
|
||||
|
||||
if (!bi)
|
||||
buf[bi++] = '\t';
|
||||
|
||||
buf[bi++] = usage[ui];
|
||||
buf[bi++] = usage_str[ui];
|
||||
|
||||
if (bi == (HELP_LINE_SIZE - 1))
|
||||
break;
|
||||
@@ -1615,6 +1642,14 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path,
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < commands[i].io_count; j++) {
|
||||
if ((commands[i].ignore_opt_args[j].opt == opt_enum) &&
|
||||
_command_ignore_opt_matches(cmd, i, j)) {
|
||||
accepted = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!accepted) {
|
||||
match_unused++;
|
||||
if (temp_unused_count < MAX_UNUSED_COUNT)
|
||||
@@ -1822,9 +1857,12 @@ static int _usage(const char *name, int help_count)
|
||||
log_print(". The _new suffix indicates the VG or LV must not yet exist.");
|
||||
log_print(". LV followed by _<type> indicates that an LV of the given type");
|
||||
log_print(" is required. (raid represents any raid<N> type.)");
|
||||
log_print(". The default output unit is specified by letter, followed by |unit");
|
||||
log_print(" which represents other possible units: hHbBsSkKmMgGtTpPeE.");
|
||||
log_print(". Output units are 1024 SI base, regardless of unit capitalization.");
|
||||
log_print(". Input units are always treated as base two values, regardless of");
|
||||
log_print(" unit capitalization, e.g. 'k' and 'K' both refer to 1024.");
|
||||
log_print(". The default input unit is specified by letter, followed by |unit");
|
||||
log_print(" which represents other possible input units: bBsSkKmMgGtTpPeE.");
|
||||
log_print(". Output units can be specified with the --units option, for which");
|
||||
log_print(" lower/upper case letters refer to base 2/10 values.");
|
||||
log_print(". Use --help --help --help to print secondary command syntax");
|
||||
log_print(" formats that are recognized, e.g. for compatibility.");
|
||||
log_print(". See man pages for short option equivalents of long option names,");
|
||||
|
@@ -113,6 +113,40 @@ static int _do_info_and_status(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check if this is really merging origin.
|
||||
* In such case, origin is gone, and user should see
|
||||
* only data from merged snapshot. Important for thin. */
|
||||
static int _check_merging_origin(const struct logical_volume *lv,
|
||||
struct lv_with_info_and_seg_status *status,
|
||||
int *merged)
|
||||
{
|
||||
uint32_t device_id;
|
||||
|
||||
*merged = 0;
|
||||
|
||||
switch (status->seg_status.type) {
|
||||
case SEG_STATUS_THIN:
|
||||
/* Get 'device_id' from active dm-table */
|
||||
if (!lv_thin_device_id(lv, &device_id))
|
||||
return_0;
|
||||
|
||||
if (lv->snapshot->device_id != device_id)
|
||||
return 1;
|
||||
break;
|
||||
case SEG_STATUS_SNAPSHOT:
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Origin is gone */
|
||||
log_debug_activation("Merge is progress, reporting merged LV %s.",
|
||||
display_lvname(lv->snapshot->lv));
|
||||
*merged = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
|
||||
const struct logical_volume *lv,
|
||||
int do_info, int do_status,
|
||||
@@ -123,10 +157,22 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
|
||||
.seg_status.type = SEG_STATUS_NONE
|
||||
};
|
||||
int r = ECMD_FAILED;
|
||||
int merged;
|
||||
|
||||
if (lv_is_merging_origin(lv))
|
||||
/* Status is need to know which LV should be shown */
|
||||
do_status = 1;
|
||||
|
||||
if (!_do_info_and_status(cmd, first_seg(lv), &status, do_info, do_status))
|
||||
goto_out;
|
||||
|
||||
if (lv_is_merging_origin(lv)) {
|
||||
if (!_check_merging_origin(lv, &status, &merged))
|
||||
goto_out;
|
||||
if (merged)
|
||||
lv = lv->snapshot->lv;
|
||||
}
|
||||
|
||||
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
|
||||
lv->vg, lv, NULL, NULL, NULL, &status, NULL))
|
||||
goto out;
|
||||
@@ -173,10 +219,22 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
|
||||
.seg_status.type = SEG_STATUS_NONE
|
||||
};
|
||||
int r = ECMD_FAILED;
|
||||
int merged;
|
||||
|
||||
if (lv_is_merging_origin(seg->lv))
|
||||
/* Status is need to know which LV should be shown */
|
||||
do_status = 1;
|
||||
|
||||
if (!_do_info_and_status(cmd, seg, &status, do_info, do_status))
|
||||
goto_out;
|
||||
|
||||
if (lv_is_merging_origin(seg->lv)) {
|
||||
if (!_check_merging_origin(seg->lv, &status, &merged))
|
||||
goto_out;
|
||||
if (merged)
|
||||
seg = seg->lv->snapshot;
|
||||
}
|
||||
|
||||
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
|
||||
seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
|
||||
goto_out;
|
||||
|
@@ -59,7 +59,7 @@ enum {
|
||||
|
||||
/* define the enums for the command line --options, foo_ARG */
|
||||
enum {
|
||||
#define arg(a, b, c, d, e, f) a ,
|
||||
#define arg(a, b, c, d, e, f, g) a ,
|
||||
#include "args.h"
|
||||
#undef arg
|
||||
};
|
||||
@@ -109,6 +109,7 @@ struct arg_props {
|
||||
int val_enum; /* foo_VAL from vals.h */
|
||||
uint32_t flags;
|
||||
uint32_t prio;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
struct arg_value_group_list {
|
||||
@@ -177,6 +178,7 @@ int size_kb_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int size_mb_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int size_mb_arg_with_percent(struct cmd_context *cmd, struct arg_values *av);
|
||||
int int_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int uint32_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
int int_arg_with_sign(struct cmd_context *cmd, struct arg_values *av);
|
||||
int int_arg_with_sign_and_percent(struct cmd_context *cmd, struct arg_values *av);
|
||||
int major_arg(struct cmd_context *cmd, struct arg_values *av);
|
||||
|
@@ -99,6 +99,7 @@ val(conststr_VAL, NULL, "ConstString", "ERR") /* used only for command defs */
|
||||
val(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
|
||||
val(bool_VAL, yes_no_arg, "Bool", "y|n")
|
||||
val(number_VAL, int_arg, "Number", NULL)
|
||||
val(uint32_VAL, uint32_arg, "Uint32", "Number")
|
||||
val(string_VAL, string_arg, "String", NULL)
|
||||
val(vg_VAL, string_arg, "VG", NULL)
|
||||
val(lv_VAL, string_arg, "LV", NULL)
|
||||
|
Reference in New Issue
Block a user