mirror of
git://sourceware.org/git/lvm2.git
synced 2025-10-01 21:44:22 +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 -
|
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.
|
Enable usage of cached volumes as snapshot origin LV.
|
||||||
Fix displayed lv name when splitting snapshot (2.02.146).
|
Fix displayed lv name when splitting snapshot (2.02.146).
|
||||||
Warn about command not making metadata backup just once per command.
|
Warn about command not making metadata backup just once per command.
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
Version 1.02.138 -
|
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.
|
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.
|
Do not try call callback when reverting activation on error path.
|
||||||
Fix file mapping for extents with physically adjacent extents.
|
Fix file mapping for extents with physically adjacent extents.
|
||||||
|
@@ -328,6 +328,7 @@ void process_event(struct dm_task *dmt,
|
|||||||
char *params;
|
char *params;
|
||||||
int needs_policy = 0;
|
int needs_policy = 0;
|
||||||
int needs_umount = 0;
|
int needs_umount = 0;
|
||||||
|
struct dm_task *new_dmt = NULL;
|
||||||
|
|
||||||
#if THIN_DEBUG
|
#if THIN_DEBUG
|
||||||
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
|
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
|
||||||
@@ -346,6 +347,28 @@ void process_event(struct dm_task *dmt,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
stack;
|
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);
|
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
|
||||||
@@ -433,6 +456,9 @@ out:
|
|||||||
device, state->fails);
|
device, state->fails);
|
||||||
pthread_kill(pthread_self(), SIGALRM);
|
pthread_kill(pthread_self(), SIGALRM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (new_dmt)
|
||||||
|
dm_task_destroy(new_dmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
int register_device(const char *device,
|
int register_device(const char *device,
|
||||||
|
@@ -618,7 +618,7 @@ class Lv(LvCommon):
|
|||||||
rc, out, err = cmdhandler.activate_deactivate(
|
rc, out, err = cmdhandler.activate_deactivate(
|
||||||
'lvchange', lv_name, activate, control_flags, options)
|
'lvchange', lv_name, activate, control_flags, options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
dbo.refresh()
|
cfg.load()
|
||||||
return '/'
|
return '/'
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
@@ -667,7 +667,7 @@ class Lv(LvCommon):
|
|||||||
rc, out, err = cmdhandler.lv_tag(
|
rc, out, err = cmdhandler.lv_tag(
|
||||||
lv_name, tags_add, tags_del, tag_options)
|
lv_name, tags_add, tags_del, tag_options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
dbo.refresh()
|
cfg.load()
|
||||||
return '/'
|
return '/'
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
|
@@ -19,7 +19,6 @@ from .utils import log_error, mt_async_result
|
|||||||
class RequestEntry(object):
|
class RequestEntry(object):
|
||||||
def __init__(self, tmo, method, arguments, cb, cb_error,
|
def __init__(self, tmo, method, arguments, cb, cb_error,
|
||||||
return_tuple=True, job_state=None):
|
return_tuple=True, job_state=None):
|
||||||
self.tmo = tmo
|
|
||||||
self.method = method
|
self.method = method
|
||||||
self.arguments = arguments
|
self.arguments = arguments
|
||||||
self.cb = cb
|
self.cb = cb
|
||||||
@@ -35,31 +34,38 @@ class RequestEntry(object):
|
|||||||
self._return_tuple = return_tuple
|
self._return_tuple = return_tuple
|
||||||
self._job_state = job_state
|
self._job_state = job_state
|
||||||
|
|
||||||
if self.tmo < 0:
|
if tmo < 0:
|
||||||
# Client is willing to block forever
|
# Client is willing to block forever
|
||||||
pass
|
pass
|
||||||
elif tmo == 0:
|
elif tmo == 0:
|
||||||
self._return_job()
|
self._return_job()
|
||||||
else:
|
else:
|
||||||
self.timer_id = GLib.timeout_add_seconds(
|
# Note: using 990 instead of 1000 for second to ms conversion to
|
||||||
tmo, RequestEntry._request_timeout, self)
|
# 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
|
@staticmethod
|
||||||
def _request_timeout(r):
|
def _request_timeout(r):
|
||||||
"""
|
"""
|
||||||
Method which gets called when the timer runs out!
|
Method which gets called when the timer runs out!
|
||||||
:param r: RequestEntry which timed 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):
|
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)
|
self._job = Job(self, self._job_state)
|
||||||
cfg.om.register_object(self._job, True)
|
cfg.om.register_object(self._job, True)
|
||||||
if self._return_tuple:
|
if self._return_tuple:
|
||||||
mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
|
self.cb(('/', self._job.dbus_object_path()))
|
||||||
else:
|
else:
|
||||||
mt_async_result(self.cb, self._job.dbus_object_path())
|
self.cb(self._job.dbus_object_path())
|
||||||
|
|
||||||
def run_cmd(self):
|
def run_cmd(self):
|
||||||
try:
|
try:
|
||||||
|
@@ -727,7 +727,7 @@ class Vg(AutomatedProperties):
|
|||||||
rc, out, err = cmdhandler.vg_tag(
|
rc, out, err = cmdhandler.vg_tag(
|
||||||
vg_name, tags_add, tags_del, tag_options)
|
vg_name, tags_add, tags_del, tag_options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
dbo.refresh()
|
cfg.load()
|
||||||
return '/'
|
return '/'
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
@@ -780,7 +780,7 @@ class Vg(AutomatedProperties):
|
|||||||
if dbo:
|
if dbo:
|
||||||
rc, out, err = method(vg_name, value, options)
|
rc, out, err = method(vg_name, value, options)
|
||||||
if rc == 0:
|
if rc == 0:
|
||||||
dbo.refresh()
|
cfg.load()
|
||||||
return '/'
|
return '/'
|
||||||
else:
|
else:
|
||||||
raise dbus.exceptions.DBusException(
|
raise dbus.exceptions.DBusException(
|
||||||
|
@@ -358,6 +358,10 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
|||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
int lv_deactivate_any_missing_subdevs(const struct logical_volume *lv)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
int pv_uses_vg(struct physical_volume *pv,
|
int pv_uses_vg(struct physical_volume *pv,
|
||||||
struct volume_group *vg)
|
struct volume_group *vg)
|
||||||
{
|
{
|
||||||
@@ -1936,7 +1940,7 @@ int monitor_dev_for_events(struct cmd_context *cmd, const struct logical_volume
|
|||||||
/* FIXME specify events */
|
/* FIXME specify events */
|
||||||
if (!monitor_fn(seg, 0)) {
|
if (!monitor_fn(seg, 0)) {
|
||||||
log_error("%s: %s segment monitoring function failed.",
|
log_error("%s: %s segment monitoring function failed.",
|
||||||
display_lvname(lv), seg->segtype->name);
|
display_lvname(lv), lvseg_name(seg));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -2573,6 +2577,77 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv)
|
|||||||
return r;
|
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?
|
* Does PV use VG somewhere in its construction?
|
||||||
* Returns 1 on failure.
|
* 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_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.
|
* 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.
|
* 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) {
|
if (!seg->segtype->ops->add_target_line) {
|
||||||
log_error(INTERNAL_ERROR "_emit_target cannot handle "
|
log_error(INTERNAL_ERROR "_emit_target cannot handle "
|
||||||
"segment type %s.", seg->segtype->name);
|
"segment type %s.", lvseg_name(seg));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -398,7 +398,7 @@ int export_extents(struct disk_list *dl, uint32_t lv_num,
|
|||||||
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
if (!(seg->segtype->flags & SEG_FORMAT1_SUPPORT)) {
|
||||||
log_error("Segment type %s in LV %s: "
|
log_error("Segment type %s in LV %s: "
|
||||||
"unsupported by format1",
|
"unsupported by format1",
|
||||||
seg->segtype->name, lv->name);
|
lvseg_name(seg), lv->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (seg_type(seg, s) != AREA_PV) {
|
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_cow(origin_lv) || lv_is_merging_cow(origin_lv) ||
|
||||||
lv_is_virtual(origin_lv)) {
|
lv_is_virtual(origin_lv)) {
|
||||||
log_error("Cache is not supported with %s segment type of the original logical volume %s.",
|
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;
|
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 */
|
/* Switch to cleaner policy to flush the cache */
|
||||||
cache_seg->cleaner_policy = 1;
|
cache_seg->cleaner_policy = 1;
|
||||||
/* Reaload kernel with "cleaner" policy */
|
/* Reload cache volume with "cleaner" policy */
|
||||||
if (!lv_update_and_reload_origin(cache_lv))
|
if (!lv_update_and_reload_origin(cache_lv))
|
||||||
return_0;
|
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 (1) {
|
||||||
if (!lv_refresh_suspend_resume(lock_lv))
|
if (!lv_refresh_suspend_resume(lock_lv))
|
||||||
return_0;
|
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;
|
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)
|
int lv_refresh_suspend_resume(const struct logical_volume *lv)
|
||||||
{
|
{
|
||||||
/*
|
if (!_lv_refresh_suspend_resume(lv))
|
||||||
* FIXME:
|
return 0;
|
||||||
*
|
|
||||||
* 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);
|
|
||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
/*
|
||||||
if (seg_type(seg, s) == AREA_LV &&
|
* Remove any transiently activated error
|
||||||
!_lv_refresh_suspend_resume(seg_lv(seg, s)))
|
* devices which arean't used any more.
|
||||||
return 0;
|
*/
|
||||||
if (seg->meta_areas &&
|
if (lv_is_raid(lv) && !lv_deactivate_any_missing_subdevs(lv)) {
|
||||||
seg_metatype(seg, s) == AREA_LV &&
|
log_error("Failed to remove temporary SubLVs from %s", display_lvname(lv));
|
||||||
!_lv_refresh_suspend_resume(seg_metalv(seg, s)))
|
return 0;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return _lv_refresh_suspend_resume(lv);
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3482,7 +3466,7 @@ int lv_add_segment(struct alloc_handle *ah,
|
|||||||
region_size))
|
region_size))
|
||||||
return_0;
|
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 "
|
log_error("Couldn't merge segments after extending "
|
||||||
"logical volume.");
|
"logical volume.");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4611,7 +4595,7 @@ static int _lvresize_adjust_policy(const struct logical_volume *lv,
|
|||||||
|
|
||||||
if (!policy_amount) {
|
if (!policy_amount) {
|
||||||
log_error("Can't extend %s with %s autoextend percent set to 0%%.",
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7063,7 +7047,7 @@ static int _should_wipe_lv(struct lvcreate_params *lp,
|
|||||||
struct logical_volume *lv, int warn)
|
struct logical_volume *lv, int warn)
|
||||||
{
|
{
|
||||||
/* Unzeroable segment */
|
/* Unzeroable segment */
|
||||||
if (first_seg(lv)->segtype->flags & SEG_CANNOT_BE_ZEROED)
|
if (seg_cannot_be_zeroed(first_seg(lv)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Thin snapshot need not to be zeroed */
|
/* Thin snapshot need not to be zeroed */
|
||||||
|
@@ -71,6 +71,13 @@ int lv_merge_segments(struct logical_volume *lv)
|
|||||||
if (error_count++ > ERROR_MAX) \
|
if (error_count++ > ERROR_MAX) \
|
||||||
goto out
|
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.
|
* 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 */
|
if (seg->origin) /* snap and thin */
|
||||||
raid_seg_error("non-zero origin LV");
|
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 */
|
if (seg->cow) /* snap */
|
||||||
raid_seg_error("non-zero cow LV");
|
raid_seg_error("non-zero cow LV");
|
||||||
if (!dm_list_empty(&seg->origin_list)) /* snap */
|
if (!dm_list_empty(&seg->origin_list)) /* snap */
|
||||||
raid_seg_error("non-zero origin_list");
|
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) */
|
/* replicator members (deprecated) */
|
||||||
if (seg->replicator)
|
if (seg->replicator)
|
||||||
raid_seg_error("non-zero 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;
|
uint32_t area_len, s;
|
||||||
|
|
||||||
/* General checks applying to all RAIDs */
|
/* General checks applying to all RAIDs */
|
||||||
if (!seg_is_raid(seg))
|
|
||||||
raid_seg_error("erroneous RAID check");
|
|
||||||
|
|
||||||
if (!seg->area_count)
|
if (!seg->area_count)
|
||||||
raid_seg_error("zero 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;
|
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? */
|
/* FIXME: should we check any non-RAID segment struct members at all? */
|
||||||
_check_non_raid_seg_members(seg, error_count);
|
_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. */
|
/* 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.
|
* 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;
|
struct lv_segment *seg, *seg2;
|
||||||
uint32_t le = 0;
|
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;
|
uint32_t area_multiplier, s;
|
||||||
struct seg_list *sl;
|
struct seg_list *sl;
|
||||||
struct glv_list *glvl;
|
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_site *rsite;
|
||||||
struct replicator_device *rdev;
|
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) {
|
dm_list_iterate_items(seg, &lv->segments) {
|
||||||
seg_count++;
|
seg_count++;
|
||||||
|
|
||||||
if (complete_vg && seg_is_raid(seg))
|
if (seg->lv != lv) {
|
||||||
_check_raid_seg(seg, &error_count);
|
log_error("LV %s invalid: segment %u is referencing different LV.",
|
||||||
|
lv->name, seg_count);
|
||||||
|
inc_error_count;
|
||||||
|
}
|
||||||
|
|
||||||
if (seg->le != le) {
|
if (seg->le != le) {
|
||||||
log_error("LV %s invalid: segment %u should begin at "
|
log_error("LV %s invalid: segment %u should begin at "
|
||||||
"LE %" PRIu32 " (found %" PRIu32 ").",
|
"LE %" PRIu32 " (found %" PRIu32 ").",
|
||||||
@@ -435,186 +500,6 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
inc_error_count;
|
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_is_snapshot(seg)) {
|
||||||
if (seg->cow && seg->cow == seg->origin) {
|
if (seg->cow && seg->cow == seg->origin) {
|
||||||
log_error("LV %s: segment %u has same LV %s for "
|
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))
|
if (seg_is_replicator(seg) && !check_replicator_segment(seg))
|
||||||
inc_error_count;
|
inc_error_count;
|
||||||
|
|
||||||
|
if (complete_vg)
|
||||||
|
_check_lv_segment(lv, seg, seg_count, &error_count);
|
||||||
|
|
||||||
for (s = 0; s < seg->area_count; s++) {
|
for (s = 0; s < seg->area_count; s++) {
|
||||||
if (seg_type(seg, s) == AREA_UNASSIGNED) {
|
if (seg_type(seg, s) == AREA_UNASSIGNED) {
|
||||||
log_error("LV %s: segment %u has 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;
|
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) {
|
dm_list_iterate_items(sl, &lv->segs_using_this_lv) {
|
||||||
seg = sl->seg;
|
seg = sl->seg;
|
||||||
seg_found = 0;
|
seg_found = 0;
|
||||||
@@ -768,6 +662,10 @@ int check_lv_segments(struct logical_volume *lv, int complete_vg)
|
|||||||
lv->name);
|
lv->name);
|
||||||
inc_error_count;
|
inc_error_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Validation of external origin counter */
|
||||||
|
if (seg->external_lv == lv)
|
||||||
|
external_lv_found++;
|
||||||
}
|
}
|
||||||
|
|
||||||
dm_list_iterate_items(glvl, &lv->indirect_glvs) {
|
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) {
|
/* Check LV flags match first segment type */
|
||||||
log_error("LV %s: inconsistent LE count %u != %u",
|
if (complete_vg) {
|
||||||
lv->name, le, lv->le_count);
|
if ((seg_count != 1) &&
|
||||||
inc_error_count;
|
(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:
|
out:
|
||||||
|
@@ -198,7 +198,7 @@
|
|||||||
#define lv_is_partial(lv) (((lv)->status & PARTIAL_LV) ? 1 : 0)
|
#define lv_is_partial(lv) (((lv)->status & PARTIAL_LV) ? 1 : 0)
|
||||||
#define lv_is_virtual(lv) (((lv)->status & VIRTUAL) ? 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(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_snapshot(lv) (((lv)->status & SNAPSHOT) ? 1 : 0)
|
||||||
#define lv_is_converting(lv) (((lv)->status & CONVERTING) ? 1 : 0)
|
#define lv_is_converting(lv) (((lv)->status & CONVERTING) ? 1 : 0)
|
||||||
#define lv_is_external_origin(lv) (((lv)->external_count > 0) ? 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;
|
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
|
* Performs a set of checks against a VG according to bits set in status
|
||||||
* and returns FAILED_* bits for those that aren't acceptable.
|
* 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;
|
uint32_t failure = 0;
|
||||||
|
|
||||||
if ((status & CLUSTERED) &&
|
if ((status & CLUSTERED) && !_access_vg_clustered(vg->cmd, vg))
|
||||||
(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);
|
|
||||||
/* Return because other flags are considered undefined. */
|
/* Return because other flags are considered undefined. */
|
||||||
return FAILED_CLUSTERED;
|
return FAILED_CLUSTERED;
|
||||||
}
|
|
||||||
|
|
||||||
if ((status & EXPORTED_VG) &&
|
if ((status & EXPORTED_VG) &&
|
||||||
vg_is_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;
|
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,
|
static int _access_vg_lock_type(struct cmd_context *cmd, struct volume_group *vg,
|
||||||
uint32_t lockd_state, uint32_t *failure)
|
uint32_t lockd_state, uint32_t *failure)
|
||||||
{
|
{
|
||||||
|
@@ -2724,15 +2724,6 @@ static const char *_get_segtype_alias(const struct segment_type *segtype)
|
|||||||
return "";
|
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)
|
static int _log_possible_conversion_types(const struct logical_volume *lv, const struct segment_type *new_segtype)
|
||||||
{
|
{
|
||||||
unsigned possible_conversions = 0;
|
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 "
|
log_error("Converting %s from %s%s%s%s is "
|
||||||
"directly possible to the following layout%s:",
|
"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 ? ")" : "",
|
*alias ? " (same as " : "", alias, *alias ? ")" : "",
|
||||||
possible_conversions > 1 ? "s" : "");
|
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_virtual(segtype) ((segtype)->flags & SEG_VIRTUAL ? 1 : 0)
|
||||||
#define segtype_is_unknown(segtype) ((segtype)->flags & SEG_UNKNOWN ? 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) \
|
#define segtype_supports_stripe_size(segtype) \
|
||||||
((segtype_is_striped(segtype) || segtype_is_mirror(segtype) || \
|
((segtype_is_striped(segtype) || segtype_is_mirror(segtype) || \
|
||||||
segtype_is_cache(segtype) || segtype_is_cache_pool(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_thin_volume(seg) segtype_is_thin_volume((seg)->segtype)
|
||||||
#define seg_is_virtual(seg) segtype_is_virtual((seg)->segtype)
|
#define seg_is_virtual(seg) segtype_is_virtual((seg)->segtype)
|
||||||
#define seg_unknown(seg) segtype_is_unknown((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_can_split(seg) segtype_can_split((seg)->segtype)
|
||||||
#define seg_cannot_be_zeroed(seg) ((seg)->segtype->flags & SEG_CANNOT_BE_ZEROED ? 1 : 0)
|
#define seg_cannot_be_zeroed(seg) segtype_cannot_be_zeroed((seg)->segtype)
|
||||||
#define seg_monitored(seg) ((seg)->segtype->flags & SEG_MONITORED ? 1 : 0)
|
#define seg_monitored(seg) segtype_monitored((seg)->segtype)
|
||||||
#define seg_only_exclusive(seg) ((seg)->segtype->flags & SEG_ONLY_EXCLUSIVE ? 1 : 0)
|
#define seg_only_exclusive(seg) segtype_only_exclusive((seg)->segtype)
|
||||||
#define seg_can_error_when_full(seg) ((seg)->segtype->flags & SEG_CAN_ERROR_WHEN_FULL ? 1 : 0)
|
#define seg_can_error_when_full(seg) segtype_can_error_when_full((seg)->segtype)
|
||||||
|
|
||||||
struct segment_type {
|
struct segment_type {
|
||||||
struct dm_list list; /* Internal */
|
struct dm_list list; /* Internal */
|
||||||
|
@@ -878,7 +878,7 @@ Count of writes merged this interval.
|
|||||||
.B write_sector_count
|
.B write_sector_count
|
||||||
Count of 512 byte sectors written this interval.
|
Count of 512 byte sectors written this interval.
|
||||||
.TP
|
.TP
|
||||||
.B write_nsecs
|
.B write_time
|
||||||
Accumulated duration of all write requests (ns).
|
Accumulated duration of all write requests (ns).
|
||||||
.TP
|
.TP
|
||||||
.B in_progress_count
|
.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
|
can also be given on the command line. The script can also be
|
||||||
executed directly if the first line is #! followed by the absolute
|
executed directly if the first line is #! followed by the absolute
|
||||||
path of \fBlvm\fP.
|
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
|
.SH BUILT-IN COMMANDS
|
||||||
.
|
.
|
||||||
@@ -238,261 +241,6 @@ The following commands are not implemented in LVM2 but might be
|
|||||||
in the future:
|
in the future:
|
||||||
.BR lvmsadc ", " lvmsar ", " pvdata .
|
.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
|
.SH VALID NAMES
|
||||||
.
|
.
|
||||||
The valid characters for VG and LV names are:
|
The valid characters for VG and LV names are:
|
||||||
|
@@ -16,6 +16,7 @@ from collections import OrderedDict
|
|||||||
import dbus
|
import dbus
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
|
||||||
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
BASE_INTERFACE = 'com.redhat.lvmdbus1'
|
||||||
@@ -188,10 +189,15 @@ class RemoteInterface(object):
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, dbus_object, interface, introspect,
|
self, dbus_object, interface, introspect,
|
||||||
properties=None):
|
properties=None, timelimit=-1):
|
||||||
self.dbus_object = dbus_object
|
self.dbus_object = dbus_object
|
||||||
self.interface = interface
|
self.interface = interface
|
||||||
self.introspect = introspect
|
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.dbus_interface = dbus.Interface(self.dbus_object, self.interface)
|
||||||
self._set_props(properties)
|
self._set_props(properties)
|
||||||
@@ -203,7 +209,19 @@ class RemoteInterface(object):
|
|||||||
return functools.partial(self, item)
|
return functools.partial(self, item)
|
||||||
|
|
||||||
def _wrapper(self, _method_name, *args, **kwargs):
|
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)
|
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 self.introspect:
|
||||||
if 'RETURN_VALUE' in self.introspect[
|
if 'RETURN_VALUE' in self.introspect[
|
||||||
@@ -236,13 +254,14 @@ class ClientProxy(object):
|
|||||||
short_name = ClientProxy._intf_short_name(interface)
|
short_name = ClientProxy._intf_short_name(interface)
|
||||||
self.short_interface_names.append(short_name)
|
self.short_interface_names.append(short_name)
|
||||||
ro = RemoteInterface(self.dbus_object, interface, introspect,
|
ro = RemoteInterface(self.dbus_object, interface, introspect,
|
||||||
properties)
|
properties, timelimit=self.tmo)
|
||||||
setattr(self, short_name, ro)
|
setattr(self, short_name, ro)
|
||||||
|
|
||||||
def __init__(self, bus, object_path, interface_prop_hash=None,
|
def __init__(self, bus, object_path, interface_prop_hash=None,
|
||||||
interfaces=None):
|
interfaces=None, timelimit=-1):
|
||||||
self.object_path = object_path
|
self.object_path = object_path
|
||||||
self.short_interface_names = []
|
self.short_interface_names = []
|
||||||
|
self.tmo = timelimit
|
||||||
self.dbus_object = bus.get_object(
|
self.dbus_object = bus.get_object(
|
||||||
BUS_NAME, self.object_path, introspect=False)
|
BUS_NAME, self.object_path, introspect=False)
|
||||||
|
|
||||||
|
@@ -1491,6 +1491,27 @@ wait_pvmove_lv_ready() {
|
|||||||
fi
|
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
|
# return total memory size in kB units
|
||||||
total_mem() {
|
total_mem() {
|
||||||
while IFS=":" read -r a b ; do
|
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 have_raid 1 3 0 || skip
|
||||||
|
|
||||||
aux prepare_pvs 9
|
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
|
# RAID1 convert tests
|
||||||
@@ -135,15 +136,27 @@ lvconvert --yes --splitmirrors 1 --name $lv2 $vg/$lv1 "$dev2"
|
|||||||
lvremove -ff $vg
|
lvremove -ff $vg
|
||||||
|
|
||||||
###########################################
|
###########################################
|
||||||
# RAID1 split + trackchanges / merge
|
# RAID1 split + trackchanges / merge with content check
|
||||||
###########################################
|
###########################################
|
||||||
# 3-way to 2-way/linear
|
# 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
|
aux wait_for_sync $vg $lv1
|
||||||
|
fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
|
||||||
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
|
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
|
||||||
check lv_exists $vg $lv1
|
check lv_exists $vg $lv1
|
||||||
check linear $vg ${lv1}_rimage_2
|
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
|
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
|
# FIXME: ensure no residual devices
|
||||||
lvremove -ff $vg
|
lvremove -ff $vg
|
||||||
|
|
||||||
|
@@ -50,6 +50,12 @@ not lvconvert --thin --thinpool $vg/tpool $vg/$lv1
|
|||||||
# Switch to 'writethrough' - this should be supported
|
# Switch to 'writethrough' - this should be supported
|
||||||
lvchange --cachemode writethrough $vg/$lv1
|
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
|
lvconvert --thin $vg/$lv1 --originname extorg --thinpool $vg/tpool
|
||||||
|
|
||||||
# check cache exist as extorg-real
|
# check cache exist as extorg-real
|
||||||
|
@@ -29,9 +29,7 @@ snap_and_merge() {
|
|||||||
sync
|
sync
|
||||||
lvs -a $vg
|
lvs -a $vg
|
||||||
|
|
||||||
# keep device open to prevent instant merge
|
SLEEP_PID=$(aux hold_device_open $vg $lv1 20)
|
||||||
sleep 20 < "$DM_DEV_DIR/$vg/$lv1" &
|
|
||||||
SLEEP_PID=$!
|
|
||||||
|
|
||||||
# initiate background merge
|
# initiate background merge
|
||||||
lvconvert -b --mergesnapshot $vg/$lv2
|
lvconvert -b --mergesnapshot $vg/$lv2
|
||||||
|
@@ -24,16 +24,6 @@ fill() {
|
|||||||
die "Snapshot does not fit $1"
|
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()
|
cleanup_tail()
|
||||||
{
|
{
|
||||||
test -z "$SLEEP_PID" || kill $SLEEP_PID || true
|
test -z "$SLEEP_PID" || kill $SLEEP_PID || true
|
||||||
@@ -125,10 +115,7 @@ lvchange -ay $vg1
|
|||||||
check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
|
check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
|
||||||
|
|
||||||
# Test removal of opened (but unmounted) snapshot (device busy) for a while
|
# Test removal of opened (but unmounted) snapshot (device busy) for a while
|
||||||
sleep 120 < "$DM_DEV_DIR/$vg1/$lv1" &
|
SLEEP_PID=$(aux hold_device_open $vg1 $lv1 60)
|
||||||
SLEEP_PID=$!
|
|
||||||
|
|
||||||
wait_for_open_ "$vg1-$lv1"
|
|
||||||
|
|
||||||
# Opened virtual snapshot device is not removable
|
# Opened virtual snapshot device is not removable
|
||||||
# it should retry device removal for a few seconds
|
# it should retry device removal for a few seconds
|
||||||
|
@@ -72,18 +72,18 @@ touch "$mntusedir/file$$"
|
|||||||
sync
|
sync
|
||||||
|
|
||||||
# Running 'keeper' process sleep holds the block device still in use
|
# 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=$!
|
PID_SLEEP=$!
|
||||||
|
|
||||||
lvs -a $vg
|
lvs -a $vg
|
||||||
# Fill pool above 95% (to cause 'forced lazy umount)
|
# Fill pool above 95% (to cause 'forced lazy umount)
|
||||||
dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync
|
dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync
|
||||||
sync
|
|
||||||
lvs -a $vg
|
lvs -a $vg
|
||||||
|
|
||||||
# Could loop here for a few secs so dmeventd can do some work
|
# Could loop here for a few secs so dmeventd can do some work
|
||||||
# In the worst case check only happens every 10 seconds :(
|
# 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
|
for i in $(seq 1 12) ; do
|
||||||
is_lv_opened_ "$vg/$lv1" || break
|
is_lv_opened_ "$vg/$lv1" || break
|
||||||
test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!"
|
test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!"
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/sh
|
#!/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,
|
# This copyrighted material is made available to anyone wishing to use,
|
||||||
# modify, copy, or redistribute it subject to the terms and conditions
|
# 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
|
lvconvert --mergethin $vg/snap
|
||||||
|
|
||||||
umount mnt
|
umount mnt
|
||||||
|
|
||||||
|
check lv_field $vg/$lv1 thin_id "1"
|
||||||
|
check lv_field $vg/pool transaction_id "3"
|
||||||
|
|
||||||
vgchange -an $vg
|
vgchange -an $vg
|
||||||
|
|
||||||
# Check reboot case
|
# Check reboot case
|
||||||
vgchange -ay --sysinit $vg
|
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 lv_field $vg/pool transaction_id "3"
|
||||||
|
|
||||||
# Check the metadata are updated after refresh
|
# Check the metadata are updated after refresh
|
||||||
|
#
|
||||||
vgchange --refresh $vg
|
vgchange --refresh $vg
|
||||||
check lv_field $vg/$lv1 thin_id "3"
|
check lv_field $vg/$lv1 thin_id "3"
|
||||||
check lv_field $vg/pool transaction_id "4"
|
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
|
grep "MaxPhysicalVolumes is less than the current number $pv_count of PVs for" err
|
||||||
check vg_field $vg max_pv 128
|
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
|
# vgchange -l MaxLogicalVolumes
|
||||||
check vg_field $vg max_lv 0
|
check vg_field $vg max_lv 0
|
||||||
invalid vgchange -l -128 $vg
|
invalid vgchange -l -128 $vg
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
#
|
#
|
||||||
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
|
||||||
# Copyright (C) 2004-2012 Red Hat, 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_lvm.o += $(EXTRA_EXEC_CFLAGS)
|
||||||
CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS)
|
CFLAGS_lvmcmdline.o += $(VALGRIND_CFLAGS)
|
||||||
|
|
||||||
|
INCLUDES += -I$(top_builddir)/tools
|
||||||
|
|
||||||
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
|
lvm: $(OBJECTS) lvm.o $(top_builddir)/lib/liblvm-internal.a
|
||||||
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
|
$(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $(OBJECTS) lvm.o \
|
||||||
$(LVMLIBS) $(READLINE_LIBS) $(LIBS) -rdynamic
|
$(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 | \
|
$(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
|
egrep -v '^ *(|#.*|config|devtypes|dumpconfig|formats|fullreport|help|lastlog|lvpoll|pvdata|segtypes|systemid|tags|version) *$$' > .commands
|
||||||
|
|
||||||
ccmd: create-commands.c
|
ccmd: $(srcdir)/create-commands.c
|
||||||
$(CC) create-commands.c -o ccmd
|
$(CC) $(srcdir)/create-commands.c -o ccmd
|
||||||
|
|
||||||
command-lines.h: ccmd
|
.DELETE_ON_ERROR:
|
||||||
./ccmd --output struct command-lines.in > command-lines.h
|
|
||||||
./ccmd --output count command-lines.in > command-lines-count.h
|
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)", "")
|
ifneq ("$(CFLOW_CMD)", "")
|
||||||
CFLOW_SOURCES = $(addprefix $(srcdir)/, $(SOURCES))
|
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.
|
# like above, it was previouly allowed in combination.
|
||||||
|
|
||||||
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
lvchange --resync VG|LV_raid_mirror|Tag|Select ...
|
||||||
OO: --activate Activate, OO_LVCHANGE
|
OO: --activate Active, OO_LVCHANGE
|
||||||
ID: lvchange_resync
|
ID: lvchange_resync
|
||||||
DESC: Resyncronize a mirror or raid LV.
|
DESC: Resyncronize a mirror or raid LV.
|
||||||
RULE: all not lv_is_pvmove lv_is_locked
|
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
|
# lvconvert snapshot-related utilities
|
||||||
# Create a new command set for these and migrate them out of lvconvert?
|
# 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
|
OO_LVCREATE_POOL: --poolmetadatasize SizeMB, --poolmetadataspare Bool, --chunksize SizeKB
|
||||||
|
|
||||||
# FIXME: it's silly to include --mirrors 0 here. Fix the tests to not use
|
OO_LVCREATE_THIN: --discards Discards, --errorwhenfull Bool
|
||||||
# --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_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB,
|
OO_LVCREATE_RAID: --mirrors SNumber, --stripes Number, --stripesize SizeKB,
|
||||||
--regionsize SizeMB, --minrecoveryrate SizeKB, --maxrecoveryrate 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
|
lvcreate --type linear --size SizeMB VG
|
||||||
OO: --mirrors 0, --stripes 1, OO_LVCREATE
|
OO: OO_LVCREATE
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0, --stripes 1
|
||||||
ID: lvcreate_linear
|
ID: lvcreate_linear
|
||||||
DESC: Create a linear LV.
|
DESC: Create a linear LV.
|
||||||
FLAGS: SECONDARY_SYNTAX
|
FLAGS: SECONDARY_SYNTAX
|
||||||
@@ -678,8 +677,9 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
# to people to not see the name parameter.
|
# to people to not see the name parameter.
|
||||||
|
|
||||||
lvcreate --size SizeMB VG
|
lvcreate --size SizeMB VG
|
||||||
OO: --type linear, --mirrors 0, --stripes 1, OO_LVCREATE
|
OO: --type linear, OO_LVCREATE
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0, --stripes 1
|
||||||
ID: lvcreate_linear
|
ID: lvcreate_linear
|
||||||
DESC: Create a linear LV (default --type linear).
|
DESC: Create a linear LV (default --type linear).
|
||||||
DESC: When --name is omitted, the name is generated.
|
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,
|
OO: --thinpool LV_new, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thinpool
|
ID: lvcreate_thinpool
|
||||||
DESC: Create a thin pool.
|
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,
|
OO: --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thinpool
|
ID: lvcreate_thinpool
|
||||||
DESC: Create a thin pool (variant, infers --type thin-pool).
|
DESC: Create a thin pool (variant, infers --type thin-pool).
|
||||||
FLAGS: SECONDARY_SYNTAX
|
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,
|
OO: --thin, --type thin-pool, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thinpool
|
ID: lvcreate_thinpool
|
||||||
DESC: Create a thin pool named by the --thinpool arg
|
DESC: Create a thin pool named by the --thinpool arg
|
||||||
DESC: (variant, infers --type thin-pool).
|
DESC: (variant, infers --type thin-pool).
|
||||||
@@ -817,12 +820,14 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
|
|
||||||
lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool VG
|
lvcreate --type thin --virtualsize SizeMB --thinpool LV_thinpool VG
|
||||||
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol
|
ID: lvcreate_thin_vol
|
||||||
DESC: Create a thin LV in a thin pool.
|
DESC: Create a thin LV in a thin pool.
|
||||||
|
|
||||||
# alternate form of lvcreate --type thin
|
# alternate form of lvcreate --type thin
|
||||||
lvcreate --type thin --virtualsize SizeMB LV_thinpool
|
lvcreate --type thin --virtualsize SizeMB LV_thinpool
|
||||||
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol
|
ID: lvcreate_thin_vol
|
||||||
DESC: Create a thin LV in a thin pool named in the first arg
|
DESC: Create a thin LV in a thin pool named in the first arg
|
||||||
DESC: (variant, also see --thinpool for naming pool).
|
DESC: (variant, also see --thinpool for naming pool).
|
||||||
@@ -834,6 +839,7 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
# alternate form of lvcreate --type thin
|
# alternate form of lvcreate --type thin
|
||||||
lvcreate --virtualsize SizeMB --thinpool LV_thinpool VG
|
lvcreate --virtualsize SizeMB --thinpool LV_thinpool VG
|
||||||
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol
|
ID: lvcreate_thin_vol
|
||||||
DESC: Create a thin LV in a thin pool (variant, infers --type thin).
|
DESC: Create a thin LV in a thin pool (variant, infers --type thin).
|
||||||
FLAGS: SECONDARY_SYNTAX
|
FLAGS: SECONDARY_SYNTAX
|
||||||
@@ -841,6 +847,7 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
# alternate form of lvcreate --type thin
|
# alternate form of lvcreate --type thin
|
||||||
lvcreate --virtualsize SizeMB LV_thinpool
|
lvcreate --virtualsize SizeMB LV_thinpool
|
||||||
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --type thin, --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol
|
ID: lvcreate_thin_vol
|
||||||
DESC: Create a thin LV in the thin pool named in the first arg
|
DESC: Create a thin LV in the thin pool named in the first arg
|
||||||
DESC: (variant, infers --type thin, also see --thinpool for
|
DESC: (variant, infers --type thin, also see --thinpool for
|
||||||
@@ -851,12 +858,14 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
|
|
||||||
lvcreate --type thin LV_thin
|
lvcreate --type thin LV_thin
|
||||||
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_snapshot
|
ID: lvcreate_thin_snapshot
|
||||||
DESC: Create a thin LV that is a snapshot of an existing thin LV.
|
DESC: Create a thin LV that is a snapshot of an existing thin LV.
|
||||||
|
|
||||||
# alternate form of lvcreate --type thin
|
# alternate form of lvcreate --type thin
|
||||||
lvcreate --thin LV_thin
|
lvcreate --thin LV_thin
|
||||||
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_snapshot
|
ID: lvcreate_thin_snapshot
|
||||||
DESC: Create a thin LV that is a snapshot of an existing thin LV
|
DESC: Create a thin LV that is a snapshot of an existing thin LV
|
||||||
DESC: (infers --type thin).
|
DESC: (infers --type thin).
|
||||||
@@ -865,33 +874,27 @@ FLAGS: SECONDARY_SYNTAX
|
|||||||
# alternate form of lvcreate --type thin
|
# alternate form of lvcreate --type thin
|
||||||
lvcreate --snapshot LV_thin
|
lvcreate --snapshot LV_thin
|
||||||
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_snapshot
|
ID: lvcreate_thin_snapshot
|
||||||
DESC: Create a thin LV that is a snapshot of an existing thin LV
|
DESC: Create a thin LV that is a snapshot of an existing thin LV
|
||||||
DESC: (infers --type thin).
|
DESC: (infers --type thin).
|
||||||
|
|
||||||
lvcreate --type thin --thinpool LV_thinpool LV
|
lvcreate --type thin --thinpool LV_thinpool LV
|
||||||
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_snapshot_of_external
|
ID: lvcreate_thin_snapshot_of_external
|
||||||
DESC: Create a thin LV that is a snapshot of an external origin LV.
|
DESC: Create a thin LV that is a snapshot of an external origin LV.
|
||||||
|
|
||||||
# alternate form of lvcreate --type thin --thinpool LV_thinpool LV
|
# alternate form of lvcreate --type thin --thinpool LV_thinpool LV
|
||||||
lvcreate --snapshot --thinpool LV_thinpool LV
|
lvcreate --snapshot --thinpool LV_thinpool LV
|
||||||
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
OO: --type thin, OO_LVCREATE_THIN, OO_LVCREATE
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_snapshot_of_external
|
ID: lvcreate_thin_snapshot_of_external
|
||||||
DESC: Create a thin LV that is a snapshot of an external origin LV
|
DESC: Create a thin LV that is a snapshot of an external origin LV
|
||||||
DESC: (infers --type thin).
|
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,
|
# stripes option is not intuitive when creating a thin LV,
|
||||||
# but here it applies to creating the new thin pool that
|
# but here it applies to creating the new thin pool that
|
||||||
# is used for the thin LV
|
# 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,
|
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol_and_thinpool
|
ID: lvcreate_thin_vol_and_thinpool
|
||||||
DESC: Create a thin LV, first creating a thin pool for it,
|
DESC: Create a thin LV, first creating a thin pool for it,
|
||||||
DESC: where the new thin pool is named by the --thinpool arg.
|
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,
|
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol_and_thinpool
|
ID: lvcreate_thin_vol_and_thinpool
|
||||||
DESC: Create a thin LV, first creating a thin pool for it,
|
DESC: Create a thin LV, first creating a thin pool for it,
|
||||||
DESC: where the new thin pool is named by the --thinpool arg
|
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,
|
OO: --thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol_and_thinpool
|
ID: lvcreate_thin_vol_and_thinpool
|
||||||
DESC: Create a thin LV, first creating a thin pool for it,
|
DESC: Create a thin LV, first creating a thin pool for it,
|
||||||
DESC: where the new thin pool is named in the first arg,
|
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,
|
OO: --type thin, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol_and_thinpool
|
ID: lvcreate_thin_vol_and_thinpool
|
||||||
DESC: Create a thin LV, first creating a thin pool for it,
|
DESC: Create a thin LV, first creating a thin pool for it,
|
||||||
DESC: where the new thin pool is named in the first arg,
|
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,
|
OO: --type thin, --type snapshot, --thin, --snapshot, OO_LVCREATE_POOL, OO_LVCREATE_THIN, OO_LVCREATE,
|
||||||
--stripes Number, --stripesize SizeKB
|
--stripes Number, --stripesize SizeKB
|
||||||
OP: PV ...
|
OP: PV ...
|
||||||
|
IO: --mirrors 0
|
||||||
ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot
|
ID: lvcreate_thin_vol_with_thinpool_or_sparse_snapshot
|
||||||
DESC: Create a thin LV, first creating a thin pool for it
|
DESC: Create a thin LV, first creating a thin pool for it
|
||||||
DESC: (infers --type thin).
|
DESC: (infers --type thin).
|
||||||
@@ -1327,7 +1335,7 @@ OO_VGCHANGE: --autobackup Bool, --ignoremonitoring, --ignoreskippedcluster,
|
|||||||
# because it can function as a required opt.
|
# because it can function as a required opt.
|
||||||
|
|
||||||
OO_VGCHANGE_META: --addtag Tag, --deltag Tag,
|
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,
|
--clustered Bool, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||||
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
|
--physicalextentsize SizeMB, --resizeable Bool, --systemid String, --locktype LockType,
|
||||||
--profile String, --detachprofile, --metadataprofile String
|
--profile String, --detachprofile, --metadataprofile String
|
||||||
@@ -1394,7 +1402,7 @@ ID: vgconvert_general
|
|||||||
|
|
||||||
vgcreate VG_new PV ...
|
vgcreate VG_new PV ...
|
||||||
OO: --addtag Tag, --alloc Alloc, --autobackup Bool, --clustered Bool, --maxlogicalvolumes Number,
|
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,
|
--physicalextentsize SizeMB, --force, --zero Bool, --labelsector Number,
|
||||||
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
--metadatasize SizeMB, --pvmetadatacopies MetadataCopiesPV, --vgmetadatacopies MetadataCopiesVG,
|
||||||
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
|
--reportformat ReportFmt, --dataalignment SizeKB, --dataalignmentoffset SizeKB,
|
||||||
@@ -1527,7 +1535,7 @@ OO_VGSPLIT: --autobackup Bool
|
|||||||
|
|
||||||
# used only when the destination VG is new
|
# used only when the destination VG is new
|
||||||
OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
|
OO_VGSPLIT_NEW: --alloc Alloc, --clustered Bool,
|
||||||
--maxlogicalvolumes Number, --maxphysicalvolumes Number,
|
--maxlogicalvolumes Number, --maxphysicalvolumes Uint32,
|
||||||
--metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG
|
--metadatatype MetadataType, --vgmetadatacopies MetadataCopiesVG
|
||||||
|
|
||||||
vgsplit VG VG PV ...
|
vgsplit VG VG PV ...
|
||||||
@@ -1581,6 +1589,7 @@ formats
|
|||||||
ID: formats_general
|
ID: formats_general
|
||||||
|
|
||||||
help
|
help
|
||||||
|
OP: String ...
|
||||||
ID: help_general
|
ID: help_general
|
||||||
|
|
||||||
version
|
version
|
||||||
|
@@ -51,8 +51,9 @@ struct command_name {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* arg_def flags */
|
/* arg_def flags */
|
||||||
#define ARG_DEF_FLAG_NEW 1 << 0
|
#define ARG_DEF_FLAG_NEW_VG 1 << 0
|
||||||
#define ARG_DEF_FLAG_MAY_REPEAT 1 << 1
|
#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)
|
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_OO_ARGS 150 /* optional opt args */
|
||||||
#define CMD_RP_ARGS 8 /* required positional args */
|
#define CMD_RP_ARGS 8 /* required positional args */
|
||||||
#define CMD_OP_ARGS 8 /* optional 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 */
|
#define CMD_MAX_RULES 32 /* max number of rules per command def */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -185,12 +187,16 @@ struct command {
|
|||||||
/* optional positional args */
|
/* optional positional args */
|
||||||
struct pos_arg optional_pos_args[CMD_OP_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];
|
struct cmd_rule rules[CMD_MAX_RULES];
|
||||||
|
|
||||||
int ro_count;
|
int ro_count;
|
||||||
int oo_count;
|
int oo_count;
|
||||||
int rp_count;
|
int rp_count;
|
||||||
int op_count;
|
int op_count;
|
||||||
|
int io_count;
|
||||||
|
|
||||||
/* used for processing current position */
|
/* used for processing current position */
|
||||||
int pos_count;
|
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(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 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 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(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 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; }
|
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" */
|
int val_enum; /* xyz_VAL when --foo takes a val like "--foo xyz" */
|
||||||
uint32_t unused1;
|
uint32_t unused1;
|
||||||
uint32_t unused2;
|
uint32_t unused2;
|
||||||
|
const char *desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* also see val_props in tools.h and vals.h */
|
/* also see val_props in tools.h and vals.h */
|
||||||
@@ -103,7 +105,7 @@ enum {
|
|||||||
/* create foo_ARG enums for --option's */
|
/* create foo_ARG enums for --option's */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
#define arg(a, b, c, d, e, f) a ,
|
#define arg(a, b, c, d, e, f, g) a ,
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
#undef arg
|
#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 */
|
/* create table of option names, e.g. --foo, and corresponding enum from args.h */
|
||||||
|
|
||||||
static struct opt_name opt_names[ARG_COUNT + 1] = {
|
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"
|
#include "args.h"
|
||||||
#undef arg
|
#undef arg
|
||||||
};
|
};
|
||||||
@@ -179,11 +181,18 @@ static struct cmd_name cmd_names[MAX_CMD_NAMES] = {
|
|||||||
#undef xx
|
#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 1024
|
||||||
#define MAX_LINE_ARGC 256
|
#define MAX_LINE_ARGC 256
|
||||||
|
|
||||||
#define REQUIRED 1
|
#define DESC_LINE 256
|
||||||
#define OPTIONAL 0
|
|
||||||
|
#define REQUIRED 1 /* required option */
|
||||||
|
#define OPTIONAL 0 /* optional option */
|
||||||
|
#define IGNORE -1 /* ignore option */
|
||||||
|
|
||||||
struct oo_line {
|
struct oo_line {
|
||||||
char *name;
|
char *name;
|
||||||
@@ -543,6 +552,13 @@ static int is_oo_line(char *str)
|
|||||||
return 0;
|
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)
|
static int is_op_line(char *str)
|
||||||
{
|
{
|
||||||
if (!strncmp(str, "OP:", 3))
|
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, "_"))
|
if ((val_enum == lv_VAL) && strstr(name, "_"))
|
||||||
def->lvt_bits = lv_to_bits(name);
|
def->lvt_bits = lv_to_bits(name);
|
||||||
|
|
||||||
if (strstr(name, "_new"))
|
if (strstr(name, "_new")) {
|
||||||
def->flags |= ARG_DEF_FLAG_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);
|
def->lvt_bits = lv_to_bits(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((val_enum == vg_VAL) || (val_enum == lv_VAL) || (val_enum == pv_VAL)) {
|
if (strstr(name, "_new")) {
|
||||||
if (strstr(name, "_new"))
|
if (val_enum == lv_VAL)
|
||||||
def->flags |= ARG_DEF_FLAG_NEW;
|
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);
|
opt = opt_str_to_num(str);
|
||||||
skip:
|
skip:
|
||||||
if (required)
|
if (required > 0)
|
||||||
cmd->required_opt_args[cmd->ro_count++].opt = opt;
|
cmd->required_opt_args[cmd->ro_count++].opt = opt;
|
||||||
else
|
else if (!required)
|
||||||
cmd->optional_opt_args[cmd->oo_count++].opt = opt;
|
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;
|
*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);
|
set_opt_def(cmd, str, &def);
|
||||||
|
|
||||||
if (required)
|
if (required > 0)
|
||||||
cmd->required_opt_args[cmd->ro_count-1].def = def;
|
cmd->required_opt_args[cmd->ro_count-1].def = def;
|
||||||
else
|
else if (!required)
|
||||||
cmd->optional_opt_args[cmd->oo_count-1].def = def;
|
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)
|
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 */
|
/* process what follows OP:, which are optional pos args */
|
||||||
|
|
||||||
static void add_optional_pos_line(struct command *cmd, int argc, char *argv[])
|
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 ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG))
|
||||||
if (def->flags & ARG_DEF_FLAG_NEW)
|
printf("_new");
|
||||||
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, " | ");
|
||||||
strcat(buf_flags, "ARG_DEF_FLAG_MAY_REPEAT");
|
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])
|
if (buf_flags[0])
|
||||||
strcat(buf_flags, " | ");
|
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;
|
return buf_flags;
|
||||||
@@ -1672,12 +1726,15 @@ static void print_def_man(struct arg_def *def, int usage)
|
|||||||
printf("\\fP");
|
printf("\\fP");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((val_enum == pv_VAL) || (val_enum == vg_VAL) || (val_enum == lv_VAL)) {
|
if ((val_enum == vg_VAL) && (def->flags & ARG_DEF_FLAG_NEW_VG)) {
|
||||||
if (def->flags & ARG_DEF_FLAG_NEW) {
|
printf("\\fI");
|
||||||
printf("\\fI");
|
printf("_new");
|
||||||
printf("_new");
|
printf("\\fP");
|
||||||
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");
|
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)
|
void print_man_usage_common(struct command *cmd)
|
||||||
{
|
{
|
||||||
struct cmd_name *cname;
|
struct cmd_name *cname;
|
||||||
@@ -2013,23 +2087,17 @@ void print_man_usage_common(struct command *cmd)
|
|||||||
printf(".RS 4\n");
|
printf(".RS 4\n");
|
||||||
printf("[");
|
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 */
|
/* 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])
|
if (!cname->common_options[opt_enum])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!opt_names[opt_enum].short_opt)
|
if (!opt_names[opt_enum].short_opt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (is_lvm_all_opt(opt_enum))
|
if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sep) {
|
if (sep) {
|
||||||
@@ -2057,14 +2125,16 @@ void print_man_usage_common(struct command *cmd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* print those without short opts */
|
/* 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])
|
if (!cname->common_options[opt_enum])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (opt_names[opt_enum].short_opt)
|
if (opt_names[opt_enum].short_opt)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (is_lvm_all_opt(opt_enum))
|
if ((cname->variants < 2) && !is_lvm_all_opt(opt_enum))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (sep) {
|
if (sep) {
|
||||||
@@ -2090,67 +2160,108 @@ void print_man_usage_common(struct command *cmd)
|
|||||||
break;
|
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");
|
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 opt_enum, val_enum;
|
||||||
int sep = 0;
|
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])
|
if (!cname->all_options[opt_enum])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -2182,7 +2293,9 @@ void print_man_all_options(struct cmd_name *cname)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* print those without short opts */
|
/* 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])
|
if (!cname->all_options[opt_enum])
|
||||||
continue;
|
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)
|
void print_desc_man(const char *desc)
|
||||||
{
|
{
|
||||||
@@ -2288,6 +2473,12 @@ void print_man_command(void)
|
|||||||
printf("Common options:\n");
|
printf("Common options:\n");
|
||||||
printf(".\n");
|
printf(".\n");
|
||||||
print_man_usage_common(prev_cmd);
|
print_man_usage_common(prev_cmd);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf(".SH OPTIONS\n");
|
||||||
|
printf(".br\n");
|
||||||
|
print_man_all_options_desc(cname);
|
||||||
|
|
||||||
prev_cmd = NULL;
|
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 */
|
/* listing them all when there's only 1 or 2 is just repetative */
|
||||||
if (cname->variants > 2) {
|
if (cname->variants > 2) {
|
||||||
printf(".P\n");
|
printf(".P\n");
|
||||||
print_man_all_options(cname);
|
print_man_all_options_list(cname);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(".P\n");
|
printf(".P\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -2369,6 +2560,12 @@ void print_man_command(void)
|
|||||||
printf("Common options:\n");
|
printf("Common options:\n");
|
||||||
printf(".\n");
|
printf(".\n");
|
||||||
print_man_usage_common(cmd);
|
print_man_usage_common(cmd);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
printf(".SH OPTIONS\n");
|
||||||
|
printf(".br\n");
|
||||||
|
print_man_all_options_desc(cname);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -2379,7 +2576,7 @@ void print_man_command(void)
|
|||||||
void print_command_struct(int only_usage)
|
void print_command_struct(int only_usage)
|
||||||
{
|
{
|
||||||
struct command *cmd;
|
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");
|
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].rp_count = %d;\n", i, cmd->rp_count);
|
||||||
printf("commands[%d].oo_count = %d;\n", i, cmd->oo_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].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);
|
printf("commands[%d].rule_count = %d;\n", i, cmd->rule_count);
|
||||||
|
|
||||||
if (cmd->cmd_flags)
|
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) {
|
if (cmd->op_count) {
|
||||||
for (op = 0; op < cmd->op_count; op++) {
|
for (op = 0; op < cmd->op_count; op++) {
|
||||||
printf("commands[%d].optional_pos_args[%d].pos = %d;\n",
|
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)
|
void print_command_list(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -2674,15 +2918,31 @@ void print_option_list(void)
|
|||||||
opt_names[i].short_opt ? opt_names[i].short_opt : 0);
|
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[])
|
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("\n");
|
||||||
|
printf("output formats:\n");
|
||||||
printf("struct: print C structures for command-lines.h\n");
|
printf("struct: print C structures for command-lines.h\n");
|
||||||
printf("count: print defines and enums for command-lines-count.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("ambiguous: print commands differing only by LV types\n");
|
||||||
printf("usage: print usage format.\n");
|
printf("usage: print usage format.\n");
|
||||||
printf("expanded: print expanded input 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[])
|
int main(int argc, char *argv[])
|
||||||
@@ -2706,9 +2966,12 @@ int main(int argc, char *argv[])
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
create_opt_names_alpha();
|
||||||
|
|
||||||
if (!strcmp(argv[1], "debug")) {
|
if (!strcmp(argv[1], "debug")) {
|
||||||
print_command_list();
|
print_command_list();
|
||||||
print_option_list();
|
print_option_list();
|
||||||
|
print_option_alpha_list();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2852,6 +3115,14 @@ int main(int argc, char *argv[])
|
|||||||
continue;
|
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 */
|
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */
|
||||||
|
|
||||||
if (prev_was_oo_def) {
|
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 */
|
/* Separate mirror log or metadata devices so we can clear them */
|
||||||
if (!detach_metadata_devices(seg, &device_list)) {
|
if (!detach_metadata_devices(seg, &device_list)) {
|
||||||
log_error("Failed to clear %s %s for %s.",
|
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));
|
"metadata area" : "mirror log", display_lvname(lv));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1022,6 +1022,12 @@ static int _lvchange_properties_check(struct cmd_context *cmd,
|
|||||||
return 0;
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2125,10 +2125,17 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
|
|||||||
if (!lv_update_and_reload(origin))
|
if (!lv_update_and_reload(origin))
|
||||||
return_0;
|
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.");
|
log_print_unless_silent("Conversion starts after activation.");
|
||||||
else
|
merge_on_activate = 1;
|
||||||
|
} else {
|
||||||
*lv_to_poll = origin;
|
*lv_to_poll = origin;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_on_activate)
|
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();
|
log_report_t saved_log_report_state = log_get_report_state();
|
||||||
char *orig_command_log_selection = NULL;
|
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;
|
char *input = NULL, *args[MAX_ARGS], **argv;
|
||||||
|
|
||||||
rl_readline_name = "lvm";
|
rl_readline_name = "lvm";
|
||||||
@@ -262,6 +262,9 @@ int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
|
|||||||
|
|
||||||
add_history(input);
|
add_history(input);
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_ARGS; i++)
|
||||||
|
args[i] = NULL;
|
||||||
|
|
||||||
argv = args;
|
argv = args;
|
||||||
|
|
||||||
if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_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
|
* Table of valid --option's
|
||||||
*/
|
*/
|
||||||
static struct arg_props _arg_props[ARG_COUNT + 1] = {
|
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"
|
#include "args.h"
|
||||||
#undef arg
|
#undef arg
|
||||||
};
|
};
|
||||||
@@ -655,6 +655,14 @@ int int_arg(struct cmd_context *cmd __attribute__((unused)), struct arg_values *
|
|||||||
return 1;
|
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)
|
int int_arg_with_sign(struct cmd_context *cmd __attribute__((unused)), struct arg_values *av)
|
||||||
{
|
{
|
||||||
char *ptr;
|
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);
|
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)
|
static int _command_required_opt_matches(struct cmd_context *cmd, int ci, int ro)
|
||||||
{
|
{
|
||||||
int opt_enum = commands[ci].required_opt_args[ro].opt;
|
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
|
#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];
|
char buf[HELP_LINE_SIZE];
|
||||||
int optional_ui = 0;
|
int optional_ui = 0;
|
||||||
@@ -1269,7 +1296,7 @@ static void _print_usage(const char *usage, int only_required)
|
|||||||
int ui;
|
int ui;
|
||||||
int bi;
|
int bi;
|
||||||
|
|
||||||
if (!usage || !strlen(usage))
|
if (!usage_str || !strlen(usage_str))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1286,32 +1313,32 @@ static void _print_usage(const char *usage, int only_required)
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
bi = 0;
|
bi = 0;
|
||||||
|
|
||||||
for (ui = 0; ui < strlen(usage); ui++) {
|
for (ui = 0; ui < strlen(usage_str); ui++) {
|
||||||
if (!bi && ((usage[ui] == ' ') || (usage[ui] == '\n')))
|
if (!bi && ((usage_str[ui] == ' ') || (usage_str[ui] == '\n')))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* The first "[ " indicates the start of the optional opt_args. */
|
/* 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;
|
optional_ui = ui;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usage[ui] == '\0')
|
if (usage_str[ui] == '\0')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (usage[ui] == '(') {
|
if (usage_str[ui] == '(') {
|
||||||
buf[bi++] = '\n';
|
buf[bi++] = '\n';
|
||||||
buf[bi++] = '\t';
|
buf[bi++] = '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[bi++] = usage[ui];
|
buf[bi++] = usage_str[ui];
|
||||||
|
|
||||||
if (usage[ui] == ')') {
|
if (usage_str[ui] == ')') {
|
||||||
buf[bi++] = '\n';
|
buf[bi++] = '\n';
|
||||||
buf[bi++] = '\t';
|
buf[bi++] = '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usage[ui] == ',') {
|
if (usage_str[ui] == ',') {
|
||||||
buf[bi++] = '\n';
|
buf[bi++] = '\n';
|
||||||
buf[bi++] = '\t';
|
buf[bi++] = '\t';
|
||||||
buf[bi++] = ' ';
|
buf[bi++] = ' ';
|
||||||
@@ -1341,25 +1368,25 @@ static void _print_usage(const char *usage, int only_required)
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
bi = 0;
|
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. */
|
/* 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;
|
optional_pos_ui = ui;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usage[ui] == '\0')
|
if (usage_str[ui] == '\0')
|
||||||
break;
|
break;
|
||||||
if (usage[ui] == '\n')
|
if (usage_str[ui] == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!bi)
|
if (!bi)
|
||||||
buf[bi++] = '\t';
|
buf[bi++] = '\t';
|
||||||
|
|
||||||
buf[bi++] = usage[ui];
|
buf[bi++] = usage_str[ui];
|
||||||
|
|
||||||
if (usage[ui] == ',') {
|
if (usage_str[ui] == ',') {
|
||||||
buf[bi++] = '\n';
|
buf[bi++] = '\n';
|
||||||
buf[bi++] = '\t';
|
buf[bi++] = '\t';
|
||||||
buf[bi++] = ' ';
|
buf[bi++] = ' ';
|
||||||
@@ -1386,16 +1413,16 @@ static void _print_usage(const char *usage, int only_required)
|
|||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
bi = 0;
|
bi = 0;
|
||||||
|
|
||||||
for (ui = optional_pos_ui; ui < strlen(usage); ui++) {
|
for (ui = optional_pos_ui; ui < strlen(usage_str); ui++) {
|
||||||
if (usage[ui] == '\0')
|
if (usage_str[ui] == '\0')
|
||||||
break;
|
break;
|
||||||
if (usage[ui] == '\n')
|
if (usage_str[ui] == '\n')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (!bi)
|
if (!bi)
|
||||||
buf[bi++] = '\t';
|
buf[bi++] = '\t';
|
||||||
|
|
||||||
buf[bi++] = usage[ui];
|
buf[bi++] = usage_str[ui];
|
||||||
|
|
||||||
if (bi == (HELP_LINE_SIZE - 1))
|
if (bi == (HELP_LINE_SIZE - 1))
|
||||||
break;
|
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) {
|
if (!accepted) {
|
||||||
match_unused++;
|
match_unused++;
|
||||||
if (temp_unused_count < MAX_UNUSED_COUNT)
|
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(". 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(". LV followed by _<type> indicates that an LV of the given type");
|
||||||
log_print(" is required. (raid represents any raid<N> 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(". Input units are always treated as base two values, regardless of");
|
||||||
log_print(" which represents other possible units: hHbBsSkKmMgGtTpPeE.");
|
log_print(" unit capitalization, e.g. 'k' and 'K' both refer to 1024.");
|
||||||
log_print(". Output units are 1024 SI base, regardless of unit capitalization.");
|
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(". Use --help --help --help to print secondary command syntax");
|
||||||
log_print(" formats that are recognized, e.g. for compatibility.");
|
log_print(" formats that are recognized, e.g. for compatibility.");
|
||||||
log_print(". See man pages for short option equivalents of long option names,");
|
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;
|
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,
|
static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
|
||||||
const struct logical_volume *lv,
|
const struct logical_volume *lv,
|
||||||
int do_info, int do_status,
|
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
|
.seg_status.type = SEG_STATUS_NONE
|
||||||
};
|
};
|
||||||
int r = ECMD_FAILED;
|
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))
|
if (!_do_info_and_status(cmd, first_seg(lv), &status, do_info, do_status))
|
||||||
goto_out;
|
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,
|
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
|
||||||
lv->vg, lv, NULL, NULL, NULL, &status, NULL))
|
lv->vg, lv, NULL, NULL, NULL, &status, NULL))
|
||||||
goto out;
|
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
|
.seg_status.type = SEG_STATUS_NONE
|
||||||
};
|
};
|
||||||
int r = ECMD_FAILED;
|
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))
|
if (!_do_info_and_status(cmd, seg, &status, do_info, do_status))
|
||||||
goto_out;
|
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,
|
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
|
||||||
seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
|
seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
|
||||||
goto_out;
|
goto_out;
|
||||||
|
@@ -59,7 +59,7 @@ enum {
|
|||||||
|
|
||||||
/* define the enums for the command line --options, foo_ARG */
|
/* define the enums for the command line --options, foo_ARG */
|
||||||
enum {
|
enum {
|
||||||
#define arg(a, b, c, d, e, f) a ,
|
#define arg(a, b, c, d, e, f, g) a ,
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
#undef arg
|
#undef arg
|
||||||
};
|
};
|
||||||
@@ -109,6 +109,7 @@ struct arg_props {
|
|||||||
int val_enum; /* foo_VAL from vals.h */
|
int val_enum; /* foo_VAL from vals.h */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint32_t prio;
|
uint32_t prio;
|
||||||
|
const char *desc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct arg_value_group_list {
|
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(struct cmd_context *cmd, struct arg_values *av);
|
||||||
int size_mb_arg_with_percent(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 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(struct cmd_context *cmd, struct arg_values *av);
|
||||||
int int_arg_with_sign_and_percent(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);
|
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(constnum_VAL, NULL, "ConstNumber", "ERR") /* used only for command defs */
|
||||||
val(bool_VAL, yes_no_arg, "Bool", "y|n")
|
val(bool_VAL, yes_no_arg, "Bool", "y|n")
|
||||||
val(number_VAL, int_arg, "Number", NULL)
|
val(number_VAL, int_arg, "Number", NULL)
|
||||||
|
val(uint32_VAL, uint32_arg, "Uint32", "Number")
|
||||||
val(string_VAL, string_arg, "String", NULL)
|
val(string_VAL, string_arg, "String", NULL)
|
||||||
val(vg_VAL, string_arg, "VG", NULL)
|
val(vg_VAL, string_arg, "VG", NULL)
|
||||||
val(lv_VAL, string_arg, "LV", NULL)
|
val(lv_VAL, string_arg, "LV", NULL)
|
||||||
|
Reference in New Issue
Block a user