Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=96a1943fb8d208aa…
Commit: 96a1943fb8d208aa84c386cf48f2b62038b09e2e
Parent: 14902d173917e814061a80f16ea54435abba1f91
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Dec 23 12:52:45 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Dec 23 13:16:35 2016 +0100
tests: update test
lvm2 now correctly reports thin_id after action of merged thin,
but before physical metadata update as we know the merge has happened.
---
test/shell/thin-vglock.sh | 15 ++++++++++++---
1 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/test/shell/thin-vglock.sh b/test/shell/thin-vglock.sh
index e59636d..40f3adf 100644
--- a/test/shell/thin-vglock.sh
+++ b/test/shell/thin-vglock.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (C) 2014 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2014-2016 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
@@ -37,15 +37,24 @@ check lv_field $vg/snap thin_id "3"
lvconvert --merge $vg/snap
umount mnt
+
+check lv_field $vg/$lv1 thin_id "1"
+check lv_field $vg/pool transaction_id "3"
+
vgchange -an $vg
# Check reboot case
vgchange -ay --sysinit $vg
-# Metadata are still not updated (--poll n)
-check lv_field $vg/$lv1 thin_id "1"
+
+# Check correct thin_id is shown after activation
+# even when metadata were not yet physically modified.
+# Merge take its place during activation,
+# but pool transaction_id still needs metadata update.
+check lv_field $vg/$lv1 thin_id "3"
check lv_field $vg/pool transaction_id "3"
# Check the metadata are updated after refresh
+#
vgchange --refresh $vg
check lv_field $vg/$lv1 thin_id "3"
check lv_field $vg/pool transaction_id "4"
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=62be9c8de430a054…
Commit: 62be9c8de430a054d5de9b652949f58a684a0cf6
Parent: e1943fc07f81e1c824757ccdac45c1e43a57af28
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Dec 22 23:31:22 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Dec 22 23:37:07 2016 +0100
tests: use hold_device_open
---
test/shell/snapshot-merge-stack.sh | 4 +---
test/shell/snapshot-usage.sh | 15 +--------------
test/shell/thin-autoumount-dmeventd.sh | 6 +++---
3 files changed, 5 insertions(+), 20 deletions(-)
diff --git a/test/shell/snapshot-merge-stack.sh b/test/shell/snapshot-merge-stack.sh
index bfafe71..2fdfaa4 100644
--- a/test/shell/snapshot-merge-stack.sh
+++ b/test/shell/snapshot-merge-stack.sh
@@ -29,9 +29,7 @@ snap_and_merge() {
sync
lvs -a $vg
- # keep device open to prevent instant merge
- sleep 20 < "$DM_DEV_DIR/$vg/$lv1" &
- SLEEP_PID=$!
+ SLEEP_PID=$(aux hold_device_open $vg $lv1 20)
# initiate background merge
lvconvert -b --merge $vg/$lv2
diff --git a/test/shell/snapshot-usage.sh b/test/shell/snapshot-usage.sh
index 042b4bf..a780664 100644
--- a/test/shell/snapshot-usage.sh
+++ b/test/shell/snapshot-usage.sh
@@ -24,16 +24,6 @@ fill() {
die "Snapshot does not fit $1"
}
-# Wait until device is opened
-wait_for_open_() {
- for i in $(seq 1 50) ; do
- test $(dmsetup info --noheadings -c -o open $1) -ne 0 && return
- sleep 0.1
- done
-
- die "$1 expected to be openned, but it's not!"
-}
-
cleanup_tail()
{
test -z "$SLEEP_PID" || kill $SLEEP_PID || true
@@ -125,10 +115,7 @@ lvchange -ay $vg1
check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
# Test removal of opened (but unmounted) snapshot (device busy) for a while
-sleep 120 < "$DM_DEV_DIR/$vg1/$lv1" &
-SLEEP_PID=$!
-
-wait_for_open_ "$vg1-$lv1"
+SLEEP_PID=$(aux hold_device_open $vg1 $lv1 60)
# Opened virtual snapshot device is not removable
# it should retry device removal for a few seconds
diff --git a/test/shell/thin-autoumount-dmeventd.sh b/test/shell/thin-autoumount-dmeventd.sh
index 3729e18..40dd75f 100644
--- a/test/shell/thin-autoumount-dmeventd.sh
+++ b/test/shell/thin-autoumount-dmeventd.sh
@@ -72,18 +72,18 @@ touch "$mntusedir/file$$"
sync
# Running 'keeper' process sleep holds the block device still in use
-sleep 60 < "$mntusedir/file$$" &
+sleep 60 < "$mntusedir/file$$" >/dev/null 2>&1 &
PID_SLEEP=$!
lvs -a $vg
# Fill pool above 95% (to cause 'forced lazy umount)
dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync
-sync
+
lvs -a $vg
# Could loop here for a few secs so dmeventd can do some work
# In the worst case check only happens every 10 seconds :(
-# With low water mark it should react way faster
+# With low water mark it quickly discovers overflow and umounts $vg/$lv1
for i in $(seq 1 12) ; do
is_lv_opened_ "$vg/$lv1" || break
test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!"
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=e1943fc07f81e1c8…
Commit: e1943fc07f81e1c824757ccdac45c1e43a57af28
Parent: 1053d46aff11a8e592ca91ba56d6400f4693b9a5
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Dec 22 22:21:09 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Dec 22 23:37:07 2016 +0100
tests: add device holding function
Hold device open with sleep and wait till sleep really opens
given devices.
---
test/lib/aux.sh | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/test/lib/aux.sh b/test/lib/aux.sh
index a195883..174e05e 100644
--- a/test/lib/aux.sh
+++ b/test/lib/aux.sh
@@ -1491,6 +1491,27 @@ wait_pvmove_lv_ready() {
fi
}
+# Holds device open with sleep which automatically expires after given timeout
+# Prints PID of running holding sleep process in background
+hold_device_open() {
+ local vgname=$1
+ local lvname=$2
+ local sec=${3:-20} # default 20sec
+
+ sleep $sec < "$DM_DEV_DIR/$vgname/$lvname" >/dev/null 2>&1 &
+ SLEEP_PID=$!
+ # wait till device is openned
+ for i in $(seq 1 50) ; do
+ if test "$(dmsetup info --noheadings -c -o open $vgname-$lvname)" -ne 0 ; then
+ echo "$SLEEP_PID"
+ return
+ fi
+ sleep .1
+ done
+
+ die "$vgname-$lvname expected to be openned, but it's not!"
+}
+
# return total memory size in kB units
total_mem() {
while IFS=":" read -r a b ; do
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=dd19b5698553b4eb…
Commit: dd19b5698553b4eb0214825a6dcb88a5330b4097
Parent: 77997c7673bfca56f51ae4eb55a50bc76e40fe79
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Dec 22 23:28:04 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Dec 22 23:37:07 2016 +0100
thin: refresh status when error processing fails
When thin-pool processes event and 'lvextend --use-policies' fails
rather capture up-to-date new info as the fullness percentage may
have jumped noticable. This way we could use 'more' correct numbers
when checking for thresholds.
---
WHATS_NEW_DM | 1 +
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 26 +++++++++++++++++++++++++
2 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 3f9eeac..67aed5e 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.138 -
=====================================
+ Thin dmeventd plugin reacts faster on lvextend failure path with umount.
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
Do not try call callback when reverting activation on error path.
Fix file mapping for extents with physically adjacent extents.
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index 0c26baf..65de465 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -328,6 +328,7 @@ void process_event(struct dm_task *dmt,
char *params;
int needs_policy = 0;
int needs_umount = 0;
+ struct dm_task *new_dmt = NULL;
#if THIN_DEBUG
log_debug("Watch for tp-data:%.2f%% tp-metadata:%.2f%%.",
@@ -346,6 +347,28 @@ void process_event(struct dm_task *dmt,
goto out;
stack;
+
+ /*
+ * Rather update oldish status
+ * since after 'command' processing
+ * percentage info could have changed a lot.
+ * If we would get above UMOUNT_THRESH
+ * we would wait for next sigalarm.
+ */
+ if (!(new_dmt = dm_task_create(DM_DEVICE_STATUS)))
+ goto_out;
+
+ if (!dm_task_set_uuid(new_dmt, dm_task_get_uuid(dmt)))
+ goto_out;
+
+ /* Non-blocking status read */
+ if (!dm_task_no_flush(new_dmt))
+ log_warn("WARNING: Can't set no_flush for dm status.");
+
+ if (!dm_task_run(new_dmt))
+ goto_out;
+
+ dmt = new_dmt;
}
dm_get_next_target(dmt, next, &start, &length, &target_type, ¶ms);
@@ -433,6 +456,9 @@ out:
device, state->fails);
pthread_kill(pthread_self(), SIGALRM);
}
+
+ if (new_dmt)
+ dm_task_destroy(new_dmt);
}
int register_device(const char *device,
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=77997c7673bfca56…
Commit: 77997c7673bfca56f51ae4eb55a50bc76e40fe79
Parent: 2aee4769b43a08eed549bd324664af5f406a25b2
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Dec 22 19:51:35 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Dec 22 23:37:07 2016 +0100
report: show proper info for merging origin
When there is 'merging' of an origin in progress, but metadata stil
do provide both origin and snapshot, we should show data from merged
snapshot. This is important mainly for thin case, where there was
a window, where i.e. 'lvs -o+device_id' would report information
about 'already gone' origin thin LV.
This race window is usually hard to trigger but can be ocasionally hit.
Usually shortly after activation, but before polling process manages
to update metadata after merge.
---
WHATS_NEW | 1 +
tools/reporter.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index dcfd85a..e5bbfe0 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ 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.
diff --git a/tools/reporter.c b/tools/reporter.c
index fc87c06..6c5996b 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -113,6 +113,40 @@ static int _do_info_and_status(struct cmd_context *cmd,
return 1;
}
+/* Check if this is really merging origin.
+ * In such case, origin is gone, and user should see
+ * only data from merged snapshot. Important for thin. */
+static int _check_merging_origin(const struct logical_volume *lv,
+ struct lv_with_info_and_seg_status *status,
+ int *merged)
+{
+ uint32_t device_id;
+
+ *merged = 0;
+
+ switch (status->seg_status.type) {
+ case SEG_STATUS_THIN:
+ /* Get 'device_id' from active dm-table */
+ if (!lv_thin_device_id(lv, &device_id))
+ return_0;
+
+ if (lv->snapshot->device_id != device_id)
+ return 1;
+ break;
+ case SEG_STATUS_SNAPSHOT:
+ break;
+ default:
+ return 1;
+ }
+
+ /* Origin is gone */
+ log_debug_activation("Merge is progress, reporting merged LV %s.",
+ display_lvname(lv->snapshot->lv));
+ *merged = 1;
+
+ return 1;
+}
+
static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
const struct logical_volume *lv,
int do_info, int do_status,
@@ -123,10 +157,22 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
.seg_status.type = SEG_STATUS_NONE
};
int r = ECMD_FAILED;
+ int merged;
+
+ if (lv_is_merging_origin(lv))
+ /* Status is need to know which LV should be shown */
+ do_status = 1;
if (!_do_info_and_status(cmd, first_seg(lv), &status, do_info, do_status))
goto_out;
+ if (lv_is_merging_origin(lv)) {
+ if (!_check_merging_origin(lv, &status, &merged))
+ goto_out;
+ if (merged)
+ lv = lv->snapshot->lv;
+ }
+
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
lv->vg, lv, NULL, NULL, NULL, &status, NULL))
goto out;
@@ -173,10 +219,22 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
.seg_status.type = SEG_STATUS_NONE
};
int r = ECMD_FAILED;
+ int merged;
+
+ if (lv_is_merging_origin(seg->lv))
+ /* Status is need to know which LV should be shown */
+ do_status = 1;
if (!_do_info_and_status(cmd, seg, &status, do_info, do_status))
goto_out;
+ if (lv_is_merging_origin(seg->lv)) {
+ if (!_check_merging_origin(seg->lv, &status, &merged))
+ goto_out;
+ if (merged)
+ seg = seg->lv->snapshot;
+ }
+
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
seg->lv->vg, seg->lv, NULL, seg, NULL, &status, NULL))
goto_out;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2aee4769b43a08ee…
Commit: 2aee4769b43a08eed549bd324664af5f406a25b2
Parent: 95e3dd5fb1297f6b1aa23cbedad1ab3dc14343a7
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Dec 22 19:46:02 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Dec 22 23:37:07 2016 +0100
snapshot: validate merge has started
Before starting polling process, validate the merge has actually started
so there is not pointless invoke of lvmpolld.
This also fixes reported message from command, so user has
correct info whether merging has already started or
if it's delayed for next activation.
---
WHATS_NEW | 1 +
tools/lvconvert.c | 9 +++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 8fefe6a..dcfd85a 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ 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.
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 0f0f0ad..ba8396f 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2497,8 +2497,13 @@ static int _lvconvert_merge_old_snapshot(struct cmd_context *cmd,
if (!lv_update_and_reload(origin))
return_0;
- lp->need_polling = 1;
- lp->lv_to_poll = origin;
+ if (lv_has_target_type(origin->vg->vgmem, origin, NULL,
+ TARGET_NAME_SNAPSHOT_MERGE)) {
+ lp->need_polling = 1;
+ lp->lv_to_poll = origin;
+ } else
+ /* Race during table reload prevented merging */
+ merge_on_activate = 1;
}
if (merge_on_activate)
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a7e1f973ccd1abfc…
Commit: a7e1f973ccd1abfc0f868f0b9c2382c2034e1633
Parent: 75568294be01f74ddadbf2c9bacf5d2fce219a44
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Wed Dec 14 15:30:01 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Tue Dec 20 11:06:57 2016 -0600
lvmdbusd: Use timeout_add instead
The function timeout_add_seconds has quite a bit of variability. Using
timeout_add which specifies the timeout in ms instead of seconds. Testing
shows that this is much more consistent which should improve clients that
are using shorter timeouts for the API and the connection.
---
daemons/lvmdbusd/request.py | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index 7c5da46..78392de 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -19,7 +19,6 @@ from .utils import log_error, mt_async_result
class RequestEntry(object):
def __init__(self, tmo, method, arguments, cb, cb_error,
return_tuple=True, job_state=None):
- self.tmo = tmo
self.method = method
self.arguments = arguments
self.cb = cb
@@ -35,23 +34,27 @@ class RequestEntry(object):
self._return_tuple = return_tuple
self._job_state = job_state
- if self.tmo < 0:
+ if tmo < 0:
# Client is willing to block forever
pass
elif tmo == 0:
self._return_job()
else:
- self.timer_id = GLib.timeout_add_seconds(
- tmo, RequestEntry._request_timeout, self)
+ # Note: using 990 instead of 1000 for second to ms conversion to
+ # account for overhead. Goal is to return just before the
+ # timeout amount has expired. Better to be a little early than
+ # late.
+ self.timer_id = GLib.timeout_add(
+ tmo * 990, RequestEntry._request_timeout, self)
@staticmethod
def _request_timeout(r):
"""
Method which gets called when the timer runs out!
:param r: RequestEntry which timed out
- :return: Nothing
+ :return: Result of timer_expired
"""
- r.timer_expired()
+ return r.timer_expired()
def _return_job(self):
# Return job is only called when we create a request object or when
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6fe6e8053a136af4…
Commit: 6fe6e8053a136af45174f153c00d404995af6e1c
Parent: f47da0ad234118f4a7a5e64b7a8480f6afd8e1de
Author: Tony Asleson <tasleson(a)redhat.com>
AuthorDate: Mon Dec 12 16:13:27 2016 -0600
Committer: Tony Asleson <tasleson(a)redhat.com>
CommitterDate: Tue Dec 20 11:06:57 2016 -0600
lvmdbusd: Remove un-needed main thread execution
---
daemons/lvmdbusd/request.py | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/daemons/lvmdbusd/request.py b/daemons/lvmdbusd/request.py
index a2c2ac9..7c5da46 100644
--- a/daemons/lvmdbusd/request.py
+++ b/daemons/lvmdbusd/request.py
@@ -54,12 +54,15 @@ class RequestEntry(object):
r.timer_expired()
def _return_job(self):
+ # Return job is only called when we create a request object or when
+ # we pop a timer. In both cases we are running in the correct context
+ # and do not need to schedule the call back in main context.
self._job = Job(self, self._job_state)
cfg.om.register_object(self._job, True)
if self._return_tuple:
- mt_async_result(self.cb, ('/', self._job.dbus_object_path()))
+ self.cb(('/', self._job.dbus_object_path()))
else:
- mt_async_result(self.cb, self._job.dbus_object_path())
+ self.cb(self._job.dbus_object_path())
def run_cmd(self):
try:
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=eb3f83357afd2b74…
Commit: eb3f83357afd2b7462f5be9f409424f588a138c8
Parent: c90e9392e47a04f0d89c8ab0e0dca7fe9de00143
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Dec 19 14:06:55 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Dec 19 14:41:16 2016 +0100
lvconvert: fix shown lv name for snapshot split
We can't keep 'display_lvname' for too long - it's using
ringbuffer and keeps limited number of names. So it's
safe only per few simple tests, but can't be used anymore
after some function calls..
(Fixes 00e641ef37a977129acc503f3fa1b67f556ac5eb)
---
WHATS_NEW | 1 +
tools/lvconvert.c | 10 +++++-----
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index fbaa369..ab113ae 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Fix displayed lv name when splitting snapshot (2.02.146).
Warn about command not making metadata backup just once per command.
Enable usage of cached volume as thin volume's external origin.
Support cache volume activation with -real layer.
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index 393d286..4103995 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2167,7 +2167,7 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu
return_0;
if (lv_is_pvmove(cow) || lv_is_mirror_type(cow) || lv_is_raid_type(cow) || lv_is_thin_type(cow)) {
- log_error("LV %s type is unsupported with --splitsnapshot.", cow_name);
+ log_error("LV %s type is unsupported with --splitsnapshot.", display_lvname(cow));
return 0;
}
@@ -2179,8 +2179,8 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu
lv_is_visible(cow) &&
lv_is_active(cow)) {
if (yes_no_prompt("Do you really want to split off active "
- "logical volume %s? [y/n]: ", cow_name) == 'n') {
- log_error("Logical volume %s not split.", cow_name);
+ "logical volume %s? [y/n]: ", display_lvname(cow)) == 'n') {
+ log_error("Logical volume %s not split.", display_lvname(cow));
return 0;
}
}
@@ -2189,14 +2189,14 @@ static int _lvconvert_splitsnapshot(struct cmd_context *cmd, struct logical_volu
if (!archive(vg))
return_0;
- log_verbose("Splitting snapshot %s from its origin.", cow_name);
+ log_verbose("Splitting snapshot %s from its origin.", display_lvname(cow));
if (!vg_remove_snapshot(cow))
return_0;
backup(vg);
- log_print_unless_silent("Logical Volume %s split from its origin.", cow_name);
+ log_print_unless_silent("Logical Volume %s split from its origin.", display_lvname(cow));
return 1;
}
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=009b711834d26610…
Commit: 009b711834d26610d23d14bd8b7540eb69c836a7
Parent: 8d6ac1c3ba2ee72e9832383609b6ff030d9883ce
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Thu Dec 15 19:03:42 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sun Dec 18 20:44:31 2016 +0000
libdm: clear region table in dm_stats_list()
Call _stats_regions_destroy() from dm_stats_list() if dms->regions
is non-NULL. This avoids leaking any pool allocations and ensures
the handle is in a known state: if an error occurs during the list,
dms->regions will be NULL and the handle will appear empty.
---
libdm/libdm-stats.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 8d202d2..3978244 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -1083,6 +1083,9 @@ int dm_stats_list(struct dm_stats *dms, const char *program_id)
if (!_stats_set_name_cache(dms))
return_0;
+ if (dms->regions)
+ _stats_regions_destroy(dms);
+
r = dm_snprintf(msg, sizeof(msg), "@stats_list %s", program_id);
if (r < 0) {
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=79121416dfd69590…
Commit: 79121416dfd695900a02711e6f63146e532b825b
Parent: 75f23880934a8c1cb192e9a898261320db15043a
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sun Dec 18 15:06:12 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:38:51 2016 +0100
thin: add comment with future extension
It could be actually better to use even cache origin in
read-only mode so there could no be some 'acidental'
change being done on this volume.
This however need further tools enhancment - where we would need
to handle whole subtree on 'lvchange -pr/-prw'.
---
lib/metadata/thin_manip.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/lib/metadata/thin_manip.c b/lib/metadata/thin_manip.c
index e7a2c33..42ec552 100644
--- a/lib/metadata/thin_manip.c
+++ b/lib/metadata/thin_manip.c
@@ -99,6 +99,10 @@ int attach_thin_external_origin(struct lv_segment *seg,
external_lv->name);
external_lv->status &= ~LVM_WRITE;
}
+
+ // TODO: should we mark even origin read-only ?
+ //if (lv_is_cache(external_lv)) /* read-only corigin of cache LV */
+ // seg_lv(first_seg(external_lv), 0)->status &= ~LVM_WRITE;
}
return 1;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=75f23880934a8c1c…
Commit: 75f23880934a8c1cb192e9a898261320db15043a
Parent: 5bb6266046b11e6e4b47596689e3f4a75ba692a3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sun Dec 18 16:36:33 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:38:30 2016 +0100
backup: show warning once per command
When command calls backup() more then once (which is actually not
wanted) this warning message is shown repeatedly:
"WARNING: This metadata update is NOT backed up."
Instead now print message just once and less confuse user.
---
WHATS_NEW | 1 +
lib/format_text/archiver.c | 4 +++-
2 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index e7abf59..fbaa369 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Warn about command not making metadata backup just once per command.
Enable usage of cached volume as thin volume's external origin.
Support cache volume activation with -real layer.
Improve search of lock-holder for external origin and thin-pool.
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 92799e4..d381155 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -35,6 +35,7 @@ struct archive_params {
struct backup_params {
int enabled;
char *dir;
+ int suppress;
};
int archive_init(struct cmd_context *cmd, const char *dir,
@@ -235,7 +236,8 @@ static int _backup(struct volume_group *vg)
int backup_locally(struct volume_group *vg)
{
if (!vg->cmd->backup_params->enabled || !vg->cmd->backup_params->dir) {
- log_warn("WARNING: This metadata update is NOT backed up");
+ log_warn_suppress(vg->cmd->backup_params->suppress++,
+ "WARNING: This metadata update is NOT backed up.");
return 1;
}
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5bb6266046b11e6e…
Commit: 5bb6266046b11e6e4b47596689e3f4a75ba692a3
Parent: 69434c2eca5bb7667d73916a28d03b8c687aea32
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Dec 17 22:41:27 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:35:27 2016 +0100
lvconvert: support cache to external origin conversion
Add this functionality to lvconvert:
'lvconvert --thin cachedLV --thinpool vg/poll'
Converts cachedLV to external origin (which will be read-only).
New thin volume is created in thinpool LV and it's using external
origin as source for unprovisioned chunks.
This conversion happens online (while volume is in use).
Thin LV remains fully writable.
Cached external origin no longer could be written so cache will be used
ONLY for read operations. For this limitation we require cache mode
to be writethrough (as writeback cannot write to read-only volumes).
When thinLV is later removed cached external origin is again
fully usable, just note, LV remain in 'read-only' mode.
When read-write is needed, 'lvchange -prw' has to be used.
Single external origin could be user by multiple thinLV in
multiple differen thin pool.
---
WHATS_NEW | 1 +
lib/metadata/cache_manip.c | 1 -
tools/lvconvert.c | 39 +++++++++++++++++++++++++++++++++++++--
3 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 74638fd..e7abf59 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Enable usage of cached volume as thin volume's external origin.
Support cache volume activation with -real layer.
Improve search of lock-holder for external origin and thin-pool.
Support status checking of cache volume used in layer.
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index ed72fae..12b1054 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -324,7 +324,6 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv)
lv_is_thin_volume(origin_lv) || lv_is_thin_pool_metadata(origin_lv) ||
lv_is_origin(origin_lv) || lv_is_merging_origin(origin_lv) ||
lv_is_cow(origin_lv) || lv_is_merging_cow(origin_lv) ||
- lv_is_external_origin(origin_lv) ||
lv_is_virtual(origin_lv)) {
log_error("Cache is not supported with %s segment type of the original logical volume %s.",
first_seg(origin_lv)->segtype->name, display_lvname(origin_lv));
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index dc32e37..393d286 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -2825,7 +2825,6 @@ static int _lvconvert_thin(struct cmd_context *cmd,
if (lv_is_locked(lv) ||
!lv_is_visible(lv) ||
- lv_is_cache_type(lv) ||
lv_is_cow(lv) ||
lv_is_pool(lv) ||
lv_is_pool_data(lv) ||
@@ -3725,6 +3724,12 @@ static int _convert_cache_volume_splitmirrors(struct cmd_context *cmd, struct lo
* Convert a cache LV to a thin pool (using the cache LV for thin pool data).
* lvconvert --type thin-pool LV
*
+ * Convert a cache LV to a thin volume with cached external origin using given
+ * thinpool tpLV (when not yet Thinpool convert it to thin-pool first).
+ * Conversion is 2-step process in this case.
+ * Only writethrough cacheLV can be converted as external origin is read-only.
+ * lvconvert --thin cacheLV --thinpool tpLV
+ *
* Alternate syntax:
* This is equivalent to above, but not preferred because it's ambiguous and inconsistent.
* lvconvert --thinpool LV
@@ -3732,7 +3737,37 @@ static int _convert_cache_volume_splitmirrors(struct cmd_context *cmd, struct lo
static int _convert_cache_volume_thin_pool(struct cmd_context *cmd, struct logical_volume *lv,
struct lvconvert_params *lp)
{
- return _lvconvert_pool(cmd, lv, lp);
+ int is_clean;
+ const struct lv_segment *pool_seg;
+
+ if (!_lvconvert_pool(cmd, lv, lp))
+ return_0;
+
+ if (lv_is_cache(lv) && !lv_is_pool_data(lv)) {
+ pool_seg = first_seg(first_seg(lv)->pool_lv);
+ if (pool_seg->cache_mode != CACHE_MODE_WRITETHROUGH) {
+ log_error("Cannot convert cache volume %s with %s cache mode to external origin.",
+ display_lvname(lv),
+ get_cache_mode_name(pool_seg));
+ log_error("To proceed, run 'lvchange --cachemode writethrough %s'.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (!lv_cache_wait_for_clean(lv, &is_clean))
+ return_0;
+
+ if (!is_clean) {
+ log_error("Cache %s is not clean, refusing to convert to external origin.",
+ display_lvname(lv));
+ return 0;
+ }
+
+ if (!_lvconvert_thin(cmd, lv, lp))
+ return_0;
+ }
+
+ return 1;
}
/*
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=69434c2eca5bb766…
Commit: 69434c2eca5bb7667d73916a28d03b8c687aea32
Parent: 954c59779d35436a6d2f28482ec1ed6dc128844c
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sun Dec 18 15:05:31 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:30:50 2016 +0100
cache: improve activation with -real
When cache volume may be converted from normal to -real layer LV
we need to improve logic for call cache_check.
With this patch, we register call for cache_check only when metadata LV
is not yet present in active table slot (should match initial table
load).
This avoids unwanted checking when cache would become layer device
online.
---
WHATS_NEW | 1 +
lib/activate/dev_manager.c | 4 ++++
2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 6ab2b19..74638fd 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Support cache volume activation with -real layer.
Improve search of lock-holder for external origin and thin-pool.
Support status checking of cache volume used in layer.
Avoid shifting by one number of blocks when clearing dirty cache volume.
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 8245454..520a0a1 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -2901,6 +2901,10 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
return_0;
if (lv_is_cache(lv) &&
+ /* Register callback only for layer activation or non-layered cache LV */
+ (layer || !lv_layer(lv)) &&
+ /* Register callback when metadata LV is NOT already active */
+ !_cached_dm_info(dm->mem, dtree, first_seg(first_seg(lv)->pool_lv)->metadata_lv, NULL) &&
!_pool_register_callback(dm, dnode, lv))
return_0;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=954c59779d35436a…
Commit: 954c59779d35436a6d2f28482ec1ed6dc128844c
Parent: 29b0e42be3026a11c86fc05f82f6a14e71d26cc8
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Dec 17 22:40:59 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:29:08 2016 +0100
libdm: drop callback on revert path
The system is likely in some very inconsisten state.
Do not try to make it even more problematic with trying
to invoke tools like thin_check via callback.
---
WHATS_NEW_DM | 1 +
libdm/libdm-deptree.c | 4 ++++
2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index ab32bdb..d57ddd7 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.138 -
=====================================
+ Do not try call callback when reverting activation on error path.
Fix file mapping for extents with physically adjacent extents.
Validation vsnprintf result in runtime translate of dm_log (1.02.136).
Separate filemap extent allocation from region table.
diff --git a/libdm/libdm-deptree.c b/libdm/libdm-deptree.c
index cf6a06e..c5226a7 100644
--- a/libdm/libdm-deptree.c
+++ b/libdm/libdm-deptree.c
@@ -2778,6 +2778,10 @@ static int _dm_tree_revert_activated(struct dm_tree_node *parent)
dm_list_iterate_items_gen(child, &parent->activated, activated_list) {
log_debug_activation("Reverting %s.", child->name);
+ if (child->callback) {
+ log_debug_activation("Dropping callback for %s.", child->name);
+ child->callback = NULL;
+ }
if (!_deactivate_node(child->name, child->info.major, child->info.minor,
&child->dtree->cookie, child->udev_flags, 0)) {
log_error("Unable to deactivate %s (%" PRIu32
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=29b0e42be3026a11…
Commit: 29b0e42be3026a11c86fc05f82f6a14e71d26cc8
Parent: a24eae6e82f365c66f4faeabc975ead0c476916b
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Dec 17 22:40:14 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:25:25 2016 +0100
lv: fix lock holder for external origin
External origin could be reloaded via more locks.
It's actually even more complex then thin-pool,
as it may be active on more nodes for linear LVs
(and maybe even more types).
External origin is always read-only thus unmodifiable
device so there should not be a problem accesing it
through multiple nodes.
Also for thin-pool check first presence of active thin-pool.
FIXME:
It's not easy to detect on which nodes this device is active
Thus manipulation with such device may require checking every
node and it active state and refresh.
But since such setup is quite complex to prepare and use,
hopefully there are not user trying to 'explore' this usage yet.
---
WHATS_NEW | 1 +
lib/metadata/lv.c | 24 +++++++++++++-----------
2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 6b9a310..6ab2b19 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Improve search of lock-holder for external origin and thin-pool.
Support status checking of cache volume used in layer.
Avoid shifting by one number of blocks when clearing dirty cache volume.
Extend metadata validation of external origin LV use count.
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index 1084149..8587902 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -1551,14 +1551,19 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv)
if (lv_is_cow(lv))
return lv_lock_holder(origin_from_cow(lv));
- if (lv_is_thin_pool(lv)) {
- /* Find any active LV from the pool */
- dm_list_iterate_items(sl, &lv->segs_using_this_lv)
- if (lv_is_active(sl->seg->lv)) {
- log_debug_activation("Thin volume %s is active.",
- display_lvname(lv));
- return sl->seg->lv;
- }
+ if (lv_is_thin_pool(lv) ||
+ lv_is_external_origin(lv)) {
+ /* FIXME: Ensure cluster keeps thin-pool active exlusively.
+ * External origin can be activated on more nodes (depends on type).
+ */
+ if (!lv_is_active(lv))
+ /* Find any active LV from the pool or external origin */
+ dm_list_iterate_items(sl, &lv->segs_using_this_lv)
+ if (lv_is_active(sl->seg->lv)) {
+ log_debug_activation("Thin volume %s is active.",
+ display_lvname(lv));
+ return sl->seg->lv;
+ }
return lv;
}
@@ -1573,9 +1578,6 @@ const struct logical_volume *lv_lock_holder(const struct logical_volume *lv)
lv_is_thin_volume(sl->seg->lv) &&
first_seg(lv)->pool_lv == sl->seg->pool_lv)
continue; /* Skip thin snaphost */
- if (lv_is_external_origin(lv) &&
- lv_is_thin_volume(sl->seg->lv))
- continue; /* Skip external origin */
if (lv_is_pending_delete(sl->seg->lv))
continue; /* Skip deleted LVs */
return lv_lock_holder(sl->seg->lv);
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a24eae6e82f365c6…
Commit: a24eae6e82f365c66f4faeabc975ead0c476916b
Parent: bf157ed833f8732c4e264422bd8be46fdf75673a
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Dec 17 21:52:27 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:23:13 2016 +0100
cache: prepare status checking for layer
To be ready to show status of cache volume, call the status
with layer. Layer is automatically detected in this case when
cache volume is used in 'layered' form (needs -real suffix).
---
WHATS_NEW | 1 +
lib/activate/activate.c | 4 ++--
lib/metadata/cache_manip.c | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 2e9c953..6b9a310 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Support status checking of cache volume used in layer.
Avoid shifting by one number of blocks when clearing dirty cache volume.
Extend metadata validation of external origin LV use count.
Fix dm table when the last user of active external origin is removed.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index c554337..b7009e6 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -770,7 +770,7 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
/* INFO is not set as cache-pool cannot be active.
* STATUS is collected from cache LV */
lv_seg = get_only_segment_using_this_lv(lv);
- (void) _lv_info(cmd, lv_seg->lv, 0, NULL, lv_seg, &status->seg_status, 0, 0);
+ (void) _lv_info(cmd, lv_seg->lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
}
@@ -1171,7 +1171,7 @@ int lv_cache_status(const struct logical_volume *cache_lv,
return 0;
}
- if (!lv_info(cache_lv->vg->cmd, cache_lv, 0, NULL, 0, 0)) {
+ if (!lv_info(cache_lv->vg->cmd, cache_lv, 1, NULL, 0, 0)) {
log_error("Cannot check status for locally inactive cache volume %s.",
display_lvname(cache_lv));
return 0;
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 54d907c..ed72fae 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -475,7 +475,7 @@ int lv_cache_remove(struct logical_volume *cache_lv)
}
/* Localy active volume is needed for writeback */
- if (!lv_is_active_locally(cache_lv)) {
+ if (!lv_info(cache_lv->vg->cmd, cache_lv, 1, NULL, 0, 0)) {
/* Give up any remote locks */
if (!deactivate_lv(cache_lv->vg->cmd, cache_lv)) {
log_error("Cannot deactivate remotely active cache volume %s.",
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=c71fefad8d5e1d9a…
Commit: c71fefad8d5e1d9a075553ab69791ddbf6bcb153
Parent: bdfc96cb089031c6d95dccb0ff66616efdb16783
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Dec 17 21:54:51 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 18 19:12:12 2016 +0100
lvs: show status for layer
When LV is external origin, show info for LV but
status for -layer. So we expose more info to a user
as otherwise active external origin is only linear
mapping of -real layer.
We do the same for i.e. old snaphost origin.
---
WHATS_NEW | 1 +
lib/activate/activate.c | 7 +++++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index eee6e98..93fc93e 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Improve reported lvs status for active external origin volume.
Fix table load for splitted RAID LV and require explicit activation.
Always active splitted RAID LV exclusively locally.
Do not use LV RAID status bit for segment status.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index b4c8a2c..c554337 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -784,6 +784,13 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
status->info.exists = 0; /* So pool LV is not active */
}
return 1;
+ } else if (lv_is_external_origin(lv)) {
+ if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL,
+ with_open_count, with_read_ahead))
+ return_0;
+
+ (void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
+ return 1;
} else if (lv_is_origin(lv)) {
/* Query segment status for 'layered' (-real) device most of the time,
* only for merging snapshot, query its progress.
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5635cd3b0337ac85…
Commit: 5635cd3b0337ac854a82a1a15cef2609c2091e6c
Parent: 886b4f755d7f33194f92dafbf2c22517db4de374
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Sun Dec 18 12:42:47 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sun Dec 18 13:03:44 2016 +0000
dmstats: separate TIMERFD and useleep() exit conditions
The time management code mixes tests of the _timer_fd value with
code that should be timer agnostic: this causes problems for users
of the usleep() timer, since it cannot properly detect the start
of a new interval:
Beginning first interval
Interval #18446744069414584348 time delta: 1000000000ns
Interval #18446744069414584348 current err: 0ns
End interval #18446744069414584348 duration: 1000000000ns
Adjusted sample interval duration: 1000000000ns
[...]
Beginning first interval
Interval #18446744069414584349 time delta: 1000000000ns
Interval #18446744069414584349 current err: 0ns
End interval #18446744069414584349 duration: 1000000000ns
Adjusted sample interval duration: 1000000000ns
Separate these out, by defining a _timer_running() call that each
timer implements, and only define _timer_fd if we are compiling
with TIMERFD enabled.
---
tools/dmsetup.c | 19 +++++++++++++++++--
1 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 17c5742..b1967db 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -286,7 +286,9 @@ static struct dm_timestamp *_start_timestamp = NULL;
static uint64_t _interval = 0; /* configured interval in nsecs */
static uint64_t _new_interval = 0; /* flag top-of-interval */
static uint64_t _last_interval = 0; /* approx. measured interval in nsecs */
+#ifdef HAVE_SYS_TIMERFD_H
static int _timer_fd = -1; /* timerfd file descriptor. */
+#endif /* HAVE_SYS_TIMERFD_H */
/* Invalid fd value used to signal end-of-reporting. */
#define TIMER_STOPPED -2
@@ -647,6 +649,14 @@ static int _do_timer_wait(void)
return _do_timerfd_wait();
}
+static int _timer_running(void)
+{
+ /*
+ * Clock shutdown for exit - nothing to do.
+ */
+ return ((_timer_fd == TIMER_STOPPED) && !_cycle_timestamp);
+}
+
#else /* !HAVE_SYS_TIMERFD_H */
static int _start_usleep_timer(void)
{
@@ -718,6 +728,11 @@ static int _do_timer_wait(void)
return _do_usleep_wait();
}
+static int _timer_running(void)
+{
+ return (_start_timestamp != NULL);
+}
+
#endif /* HAVE_SYS_TIMERFD_H */
static int _update_interval_times(void)
@@ -729,7 +744,7 @@ static int _update_interval_times(void)
/*
* Clock shutdown for exit - nothing to do.
*/
- if ((_timer_fd == TIMER_STOPPED) && !_cycle_timestamp)
+ if (!_timer_running())
goto out;
/* clock is running */
@@ -805,7 +820,7 @@ static int _update_interval_times(void)
out:
/* timer stopped or never started */
- if (!r || _timer_fd < 0) {
+ if (!r || !_timer_running()) {
/* The _cycle_timestamp has not yet been allocated if we
* fail to obtain this_timestamp on the first interval.
*/
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=886b4f755d7f3319…
Commit: 886b4f755d7f33194f92dafbf2c22517db4de374
Parent: 68ec42ebaf288911b1cb95882678ca778b795953
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Sun Dec 18 12:39:26 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sun Dec 18 13:03:44 2016 +0000
dmstats: use better interval estimate for usleep() timer
Although the usleep() interval timer is not used if the Linux
TIMERFD interface is available it should still provide reasonably
good timing.
Instead of trying to estimate the error from the duration of the
last sleep, peg it to the start time of the program, and use the
value of ((start_time - now) % interval) to correct the current
interval duration.
This always pulls us back into sync at the end of each interval,
rather than relying on trying to incrementally adjust the time
duration at each interval start.
This greatly reduces drift when the usleep() clock is used.
---
tools/dmsetup.c | 20 +++++++++++---------
1 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 1be19d5..17c5742 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -282,6 +282,7 @@ const char *_stats_types[] = {
/* report timekeeping */
static struct dm_timestamp *_cycle_timestamp = NULL;
+static struct dm_timestamp *_start_timestamp = NULL;
static uint64_t _interval = 0; /* configured interval in nsecs */
static uint64_t _new_interval = 0; /* flag top-of-interval */
static uint64_t _last_interval = 0; /* approx. measured interval in nsecs */
@@ -650,12 +651,14 @@ static int _do_timer_wait(void)
static int _start_usleep_timer(void)
{
log_debug("Using usleep for interval timekeeping.");
+ _start_timestamp = dm_timestamp_alloc();
+ dm_timestamp_get(_start_timestamp);
return 1;
}
static int _do_usleep_wait(void)
{
- static struct dm_timestamp *_last_sleep, *_now = NULL;
+ static struct dm_timestamp *_now = NULL;
uint64_t this_interval;
int64_t delta_t;
@@ -664,9 +667,7 @@ static int _do_usleep_wait(void)
* message ioctls by keeping track of the last wake time and
* adjusting the sleep interval accordingly.
*/
- if (!_last_sleep && !_now) {
- if (!(_last_sleep = dm_timestamp_alloc()))
- return_0;
+ if (!_now) {
if (!(_now = dm_timestamp_alloc()))
return_0;
dm_timestamp_get(_now);
@@ -674,19 +675,19 @@ static int _do_usleep_wait(void)
log_error("Using "FMTu64" as first interval.", this_interval);
} else {
dm_timestamp_get(_now);
- delta_t = dm_timestamp_delta(_now, _last_sleep);
- log_debug("Interval timer delta_t: "FMTi64, delta_t);
+ delta_t = dm_timestamp_delta(_now, _start_timestamp);
+ log_debug("Interval timer drift: "FMTi64,
+ (delta_t % _interval));
/* FIXME: usleep timer drift over large counts. */
/* adjust for time spent populating and reporting */
- this_interval = 2 * _interval - delta_t;
+ this_interval = _interval - (delta_t % _interval);
log_debug("Using "FMTu64" as interval.", this_interval);
}
/* Signal that a new interval has begun. */
_new_interval = 1;
- dm_timestamp_copy(_last_sleep, _now);
if (usleep(this_interval / NSEC_PER_USEC)) {
if (errno == EINTR)
@@ -699,8 +700,9 @@ static int _do_usleep_wait(void)
}
if (_count == 2) {
- dm_timestamp_destroy(_last_sleep);
+ dm_timestamp_destroy(_start_timestamp);
dm_timestamp_destroy(_now);
+ _start_timestamp = _now = NULL;
}
return 1;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=35791689ba5ef95d…
Commit: 35791689ba5ef95da45290fd12ce9cff55c86258
Parent: 0f98d5c2e6d103a46bb5eca75ac496622933c475
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 20:28:29 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Wed Dec 14 11:28:11 2016 +0000
libdm: use destination size as limit in dm_bit_copy()
The dm_bit_copy() macro uses the source (bs1) bitset size as the
limit for memcpy:
memcpy((bs1) + 1, (bs2) + 1, ((*(bs1) / DM_BITS_PER_INT) + 1)..)
This is safe if the destination bitset is smaller than the source,
or if the two bitsets are of the same size.
With a destination that is larger (e.g. when resizing a bitmap to
add more capacity), the memcpy will overrun the source bitset and
set garbage bits in the destination.
There are nine uses of the macro currently (8 in libdm/regex, and
1 in daemons/cmirrord): in each case the two bitsets are always of
equal size so the behaviour is unchanged.
Fix the macro to use bs2's size to simplify resizing bitsets and
avoid the need for another copy macro.
---
libdm/libdevmapper.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index bcf784b..ed46795 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -2090,7 +2090,7 @@ int dm_bit_get_prev(dm_bitset_t bs, int last_bit);
memset((bs) + 1, 0, ((*(bs) / DM_BITS_PER_INT) + 1) * sizeof(int))
#define dm_bit_copy(bs1, bs2) \
- memcpy((bs1) + 1, (bs2) + 1, ((*(bs1) / DM_BITS_PER_INT) + 1) * sizeof(int))
+ memcpy((bs1) + 1, (bs2) + 1, ((*(bs2) / DM_BITS_PER_INT) + 1) * sizeof(int))
/*
* Parse a string representation of a bitset into a dm_bitset_t. The
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=77e09c3fb4d019ab…
Commit: 77e09c3fb4d019ab3a0472059481ef990c64b415
Parent: 4a05f83278a1b1967b91d8f47fa1f7ce18341439
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Dec 14 11:16:47 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Dec 14 11:37:02 2016 +0100
raid: activation with list
Commit 069039204002e5c8514050fe541bbd378c383a02 revealed a problem
in raid metadata manipulation.
We do two operations in one table reload:
- raid leg/image extraction
- rename remaining raid legs
This should be made in separate steps. Otherwise we do an
uncorrectable table change on error path (leaving tables
for admin and dmsetup).
As a hotfix - restore the previous logic and use a single
new function _lv_update_and_reload_list which activates exclusively
extracted LVs on the list before resuming suspended raid LV.
This restore 'rename' functionality upon resume.
Also still preserve the 'origin_only' logic - although we know
it's not working properly for cluster and LV stacking.
Further fixes are needed.
---
lib/metadata/raid_manip.c | 67 +++++++++++++++++++++++++++++++++++++++-----
1 files changed, 59 insertions(+), 8 deletions(-)
diff --git a/lib/metadata/raid_manip.c b/lib/metadata/raid_manip.c
index 049102a..ed48239 100644
--- a/lib/metadata/raid_manip.c
+++ b/lib/metadata/raid_manip.c
@@ -233,11 +233,6 @@ static int _deactivate_and_remove_lvs(struct volume_group *vg, struct dm_list *r
{
struct lv_list *lvl;
- /* Need to take lock/resume for proper deactivation */
- dm_list_iterate_items(lvl, removal_lvs)
- if (!activate_lv_excl_local(vg->cmd, lvl->lv))
- return_0;
-
dm_list_iterate_items(lvl, removal_lvs) {
if (!deactivate_lv(vg->cmd, lvl->lv))
return_0;
@@ -363,6 +358,62 @@ static int _raid_remove_top_layer(struct logical_volume *lv,
return 1;
}
+/*
+ * Assisted excl_local activation of lvl listed LVs before resume
+ *
+ * FIXME: code which needs to use this function is usually unsafe
+ * againt crashes as it's doing more then 1 operation per commit
+ * and as such is currently irreversible on error path.
+ *
+ * Function is not making backup as this is usually not the last
+ * metadata changing operation.
+ *
+ * Also we should take 'struct lv_list'...
+ */
+static int _lv_update_and_reload_list(struct logical_volume *lv, int origin_only, struct dm_list *lv_list)
+{
+ struct volume_group *vg = lv->vg;
+ const struct logical_volume *lock_lv = lv_lock_holder(lv);
+ struct lv_list *lvl;
+ int r;
+
+ log_very_verbose("Updating logical volume %s on disk(s)%s.",
+ display_lvname(lock_lv), origin_only ? " (origin only)": "");
+
+ if (!vg_write(vg))
+ return_0;
+
+ if (!(r = (origin_only ? suspend_lv_origin(vg->cmd, lock_lv) : suspend_lv(vg->cmd, lock_lv)))) {
+ log_error("Failed to lock logical volume %s.",
+ display_lvname(lock_lv));
+ vg_revert(vg);
+ } else if (!(r = vg_commit(vg)))
+ stack; /* !vg_commit() has implict vg_revert() */
+
+ if (r && lv_list) {
+ dm_list_iterate_items(lvl, lv_list) {
+ log_very_verbose("Activating logical volume %s before %s in kernel.",
+ display_lvname(lvl->lv), display_lvname(lock_lv));
+ if (!activate_lv_excl_local(vg->cmd, lvl->lv)) {
+ log_error("Failed to activate %s before resuming %s.",
+ display_lvname(lvl->lv), display_lvname(lock_lv));
+ r = 0; /* But lets try with the rest */
+ }
+ }
+ }
+
+ log_very_verbose("Updating logical volume %s in kernel.",
+ display_lvname(lock_lv));
+
+ if (!(origin_only ? resume_lv_origin(vg->cmd, lock_lv) : resume_lv(vg->cmd, lock_lv))) {
+ log_error("Problem reactivating logical volume %s.",
+ display_lvname(lock_lv));
+ r = 0;
+ }
+
+ return r;
+}
+
/* Makes on-disk metadata changes
* If LV is active:
* clear first block of device
@@ -1233,7 +1284,7 @@ static int _raid_remove_images(struct logical_volume *lv,
if (!commit)
return 1;
- if (!lv_update_and_reload(lv))
+ if (!_lv_update_and_reload_list(lv, 0, removal_lvs))
return_0;
/*
@@ -1927,7 +1978,7 @@ static int _raid0_add_or_remove_metadata_lvs(struct logical_volume *lv,
return_0;
if (update_and_reload) {
- if (!lv_update_and_reload_origin(lv))
+ if (!_lv_update_and_reload_list(lv, 1, removal_lvs))
return_0;
/* If any residual LVs, eliminate them, write VG, commit it and take a backup */
@@ -1977,7 +2028,7 @@ static int _lv_update_reload_fns_reset_eliminate_lvs(struct logical_volume *lv,
{
int flags_were_cleared = 0, r = 0;
- if (!lv_update_and_reload_origin(lv))
+ if (!_lv_update_and_reload_list(lv, 1, removal_lvs))
return_0;
/* Eliminate any residual LV and don't commit the metadata */
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f4401fe351f63679…
Commit: f4401fe351f63679ae8f4bab448a9283fb631a4a
Parent: fce7449d7311b49839f339b714c48e953e9a837a
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 21:36:11 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 21:41:31 2016 +0000
libdm: ensure first extent is always counted
If FIEMAP returns a single extent after the first call, no extent
boundary is detected and the first extent is not counted by the
normal mechanism.
In this case, increment nr_extents at the same time the extent is
added to the region table, before returning.
---
libdm/libdm-stats.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 02a30dc..8d202d2 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4286,8 +4286,10 @@ static uint64_t _stats_map_extents(struct dm_pool *mem,
* If the file only has a single extent, no boundary is ever
* detected to trigger addition of the first extent.
*/
- if (fm_ext[i - 1].fe_logical == 0)
+ if (fm_ext[i - 1].fe_logical == 0) {
_stats_add_extent(mem, fm_pending, nr_extents);
+ nr_extents++;
+ }
fiemap->fm_start = (fm_ext[i - 1].fe_logical +
fm_ext[i - 1].fe_length);
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=e8d966bc31741f84…
Commit: e8d966bc31741f846dc6d0d4af9a565d19560b98
Parent: 5d1d65e735b6dcc5f02d0e536e3b63617f40ce83
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 10:32:29 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 21:02:18 2016 +0000
libdm: use dm_bit_get_last() in _stats_group_tag_fill()
Instead of iterating over all bits, use dm_bit_get_last() to find
the last set bit in the group bitmap.
---
libdm/libdm-stats.c | 4 +---
1 files changed, 1 insertions(+), 3 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 471bd7b..8210a93 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -1716,9 +1716,7 @@ static size_t _stats_group_tag_fill(const struct dm_stats *dms,
int i, j, r, next, last = 0;
size_t used = 0;
- i = dm_bit_get_first(regions);
- for (; i >= 0; i = dm_bit_get_next(regions, i))
- last = i;
+ last = dm_bit_get_last(regions);
i = dm_bit_get_first(regions);
for(; i >= 0; i = dm_bit_get_next(regions, i)) {
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=107bc13db3b0117e…
Commit: 107bc13db3b0117e32bacede53fbd382feaf4a17
Parent: 83a9cd5258fbd1acf293734cb4c3aba0f9ffcc9b
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 12:03:50 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 20:41:29 2016 +0000
util: add clz() and use __builtin_clz() if available
Add a macro for the clz (count leading zeros) operation.
Use the GCC __builtin_clz() for clz() if it is available and fall
back to a shift based implementation on systems that do not set
HAVE___BUILTIN_CLZ.
---
lib/misc/util.h | 41 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 41 insertions(+), 0 deletions(-)
diff --git a/lib/misc/util.h b/lib/misc/util.h
index 730b903..9231ea9 100644
--- a/lib/misc/util.h
+++ b/lib/misc/util.h
@@ -35,6 +35,47 @@
#define uninitialized_var(x) x = x
#endif
+/*
+ * GCC 3.4 adds a __builtin_clz, which uses the count leading zeros (clz)
+ * instruction on arches that have one. Provide a fallback using shifts
+ * and comparisons for older compilers.
+ */
+#ifdef HAVE___BUILTIN_CLZ
+#define clz(x) __builtin_clz((x))
+#else /* ifdef HAVE___BUILTIN_CLZ */
+unsigned _dm_clz(unsigned x)
+{
+ int n;
+
+ if ((int)x <= 0) return (~x >> 26) & 32;
+
+ n = 1;
+
+ if ((x >> 16) == 0) {
+ n = n + 16;
+ x = x << 16;
+ }
+
+ if ((x >> 24) == 0) {
+ n = n + 8;
+ x = x << 8;
+ }
+
+ if ((x >> 28) == 0) {
+ n = n + 4;
+ x = x << 4;
+ }
+
+ if ((x >> 30) == 0) {
+ n = n + 2;
+ x = x << 2;
+ }
+ n = n - (x >> 31);
+ return n;
+}
+#define clz(x) _dm_clz((x))
+#endif /* ifdef HAVE___BUILTIN_CLZ */
+
#define KERNEL_VERSION(major, minor, release) (((major) << 16) + ((minor) << 8) + (release))
/* Define some portable printing types */
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8e339728283d3b83…
Commit: 8e339728283d3b83222a25c7bf12b79a944c6ef5
Parent: 99b6d82e2dac7ef097fa940c64456620930d7758
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 14:31:39 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 15:37:48 2016 +0000
libdm: check for non-existent region_id values in groups
Check that all region_id values specified in a group bitmap are
actually present: although this should not normally happen when
using the dmstats tool, it is possible as a result of manual
changes (or bugs) for a group descriptor to contain one or more
group_id values that do not exist.
Check for this situation when reading group descriptors, warn
the user the user, and clear these bits in the bitmap when
formatting it for output.
---
libdm/libdm-stats.c | 27 +++++++++++++++++++++------
1 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 5833ac6..2d2a032 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -645,6 +645,23 @@ static void _stats_update_groups(struct dm_stats *dms)
}
}
+static void _check_group_regions_present(struct dm_stats *dms,
+ struct dm_stats_group *group)
+{
+ dm_bitset_t regions = group->regions;
+ int64_t i, group_id;
+
+ group_id = i = dm_bit_get_first(regions);
+
+ for (; i > 0; dm_bit_get_next(regions, i))
+ if (!_stats_region_present(&dms->regions[i])) {
+ log_warn("Group descriptor " FMTi64 " contains "
+ "non-existent region_id " FMTi64 ".",
+ group_id, i);
+ dm_bit_clear(regions, i);
+ }
+}
+
/*
* Parse a DMS_GROUP group descriptor embedded in a region's aux_data.
*
@@ -1030,6 +1047,9 @@ static int _stats_parse_list(struct dm_stats *dms, const char *resp)
dms->regions = dm_pool_end_object(mem);
dms->groups = dm_pool_end_object(group_mem);
+ dm_stats_foreach_group(dms)
+ _check_group_regions_present(dms, &dms->groups[dms->cur_group]);
+
_stats_update_groups(dms);
if (fclose(list_rows))
@@ -1742,17 +1762,12 @@ bad:
static size_t _stats_group_tag_len(const struct dm_stats *dms,
dm_bitset_t regions)
{
- int i, j, next, nr_regions = 0;
+ int64_t i, j, next, nr_regions = 0;
size_t buflen = 0, id_len = 0;
/* check region ids and find last set bit */
i = dm_bit_get_first(regions);
for (; i >= 0; i = dm_bit_get_next(regions, i)) {
- if (!dm_stats_region_present(dms, i)) {
- log_error("Region identifier %d not found", i);
- return 0;
- }
-
/* length of region_id or range start in characters */
id_len = (i) ? 1 + (size_t) log10(i) : 1;
buflen += id_len;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=99b6d82e2dac7ef0…
Commit: 99b6d82e2dac7ef097fa940c64456620930d7758
Parent: 138e4336fd8422623df7daa362b98a4899f5fbec
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Tue Dec 13 13:56:10 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 14:37:41 2016 +0000
libdm: fix segfault with invalid group descriptor
If a region has a a DMS_GROUP tag in aux_data where the first
region_id in the bitmap is not the same as the containing region,
dmstats will segfault:
# '2' is never a valid group bitset list for region_id == 0
# dmsetup message vg_hex/root 0 "@stats_set_aux 0 DMS_GROUP=img:2#"
# dmsetup message vg_hex/root 0 "@stats_list"
0: 45383680+16384 16384 dmstats DMS_GROUP=img:2#
1: 46071808+32768 32768 dmstats -
2: 47382528+16384 16384 dmstats -
# dmstats list
Segmentation fault (core dumped)
The crash will occur in some arbitrary dm_stats_get_* property
method - this happens while processing the 1st region_id in the
bitset, because the region is marked as grouped, but there is
no group bitmap present at dms->groups[2]->regions.
Fix this by detecting a mismatch between the expected region_id
and dm_bit_get_first() for the parsed bitset during
_parse_aux_data_group().
---
libdm/libdm-stats.c | 8 +++++++-
1 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 8c0428e..5833ac6 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -708,8 +708,14 @@ static int _parse_aux_data_group(struct dm_stats *dms,
}
group->group_id = dm_bit_get_first(regions);
- group->regions = regions;
+ if (group->group_id != region->region_id) {
+ log_error("Found invalid group descriptor in region " FMTu64
+ " aux_data.", region->region_id);
+ group->group_id = DM_STATS_GROUP_NOT_PRESENT;
+ goto bad;
+ }
+ group->regions = regions;
group->alias = NULL;
if (strlen(alias)) {
group->alias = dm_strdup(alias);
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=93f420caf4e58f46…
Commit: 93f420caf4e58f468919f40a9f3f9c20157affd0
Parent: 87117c2b2546231c789f92c75590f053a8fb987c
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Mon Dec 12 20:40:27 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Tue Dec 13 09:09:25 2016 +0000
libdm: fix _stats_get_extents_for_file()
Handle files that contain multiple logical extents in a single
physical extent properly:
- In FIEMAP terms a logical extent is a contiguous range of
sectors in the file's address space.
- One or more physically adjacent logical extents comprise a
physical extent: these are the disk areas that will be mapped
to regions.
- An extent boundary occurs when the start sector of extent
n+1 is not equal to (n.start + n.length).
This requires that we accumulate the length values of extents
returned by FIEMAP until a discontinuity is found (since each
struct fiemap_extent returned by FIEMAP only represents a single
logical extent, which may be contiguous with other logical
extents on-disk).
This avoids creating large numbers of regions for physically
adjacent (logical) extents and fixes the earlier behaviour which
would only map the first logical extent of the physical extent,
leaving gaps in the region table for these files.
---
WHATS_NEW_DM | 3 +-
libdm/libdm-stats.c | 56 +++++++++++++++++++++++++++++++++-----------------
2 files changed, 39 insertions(+), 20 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index f402113..ab32bdb 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,8 +1,9 @@
Version 1.02.138 -
=====================================
+ Fix file mapping for extents with physically adjacent extents.
Validation vsnprintf result in runtime translate of dm_log (1.02.136).
Separate filemap extent allocation from region table.
- Fix segmentation fault when filemap region creation fails
+ Fix segmentation fault when filemap region creation fails.
Fix performance of region cleanup for failed filemap creation.
Fix very slow region deletion with many regions.
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 850aa49..56a38f2 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4194,10 +4194,9 @@ static int _stats_add_extent(struct dm_pool *mem, struct fiemap_extent *fm_ext,
}
/* test for the boundary of an extent */
-#define ext_boundary(ext, exp, exp_dense) \
-(((ext).fe_logical != 0) && \
-((ext).fe_physical != (exp)) && \
-((ext).fe_physical != (exp_dense)))
+#define ext_boundary(ext, exp) \
+((ext).fe_logical != 0) && \
+((ext).fe_physical != (exp))
/*
* Read the extents of an open file descriptor into a table of struct _extent.
@@ -4213,10 +4212,9 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
uint64_t *buf;
struct fiemap *fiemap = NULL;
struct fiemap_extent *fm_ext = NULL;
- struct fiemap_extent fm_last = {0};
+ struct fiemap_extent fm_last = {0}, fm_pending = {0};
struct _extent *extents;
unsigned long long expected = 0;
- unsigned long long expected_dense = 0;
unsigned long flags = 0;
unsigned int i, num = 0;
int tot_extents = 0, n = 0;
@@ -4264,31 +4262,51 @@ static struct _extent *_stats_get_extents_for_file(struct dm_pool *mem, int fd,
break;
for (i = 0; i < fiemap->fm_mapped_extents; i++) {
- expected_dense = fm_last.fe_physical +
- fm_last.fe_length;
- expected = fm_last.fe_physical +
- fm_ext[i].fe_logical - fm_last.fe_logical;
- if (ext_boundary(fm_ext[i], expected, expected_dense)) {
+ expected = fm_last.fe_physical + fm_last.fe_length;
+
+ if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
+ last = 1;
+
+ /* cannot map extents that are not yet allocated. */
+ if (fm_ext[i].fe_flags
+ & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC))
+ continue;
+
+ if (ext_boundary(fm_ext[i], expected)) {
tot_extents++;
- if (!_stats_add_extent(mem, fm_ext + i,
- tot_extents - 1))
+ if (!_stats_add_extent(mem, &fm_pending,
+ fm_pending.fe_flags))
goto_bad;
+ /* Begin a new pending extent. */
+ fm_pending.fe_flags = tot_extents - 1;
+ fm_pending.fe_physical = fm_ext[i].fe_physical;
+ fm_pending.fe_logical = fm_ext[i].fe_logical;
+ fm_pending.fe_length = fm_ext[i].fe_length;
} else {
expected = 0;
if (!tot_extents)
tot_extents = 1;
- if (fm_ext[i].fe_logical == 0)
- if (!_stats_add_extent(mem, fm_ext + i,
- tot_extents - 1))
- goto_bad;
+ /* Begin a new pending extent for extent 0. */
+ if (fm_ext[i].fe_logical == 0) {
+ fm_pending.fe_flags = tot_extents - 1;
+ fm_pending.fe_physical = fm_ext[i].fe_physical;
+ fm_pending.fe_logical = fm_ext[i].fe_logical;
+ fm_pending.fe_length = fm_ext[i].fe_length;
+ } else
+ fm_pending.fe_length += fm_ext[i].fe_length;
}
num += tot_extents;
- if (fm_ext[i].fe_flags & FIEMAP_EXTENT_LAST)
- last = 1;
fm_last = fm_ext[i];
n++;
}
+ /*
+ * If the file only has a single extent, no boundary is ever
+ * detected to trigger addition of the first extent.
+ */
+ if (fm_ext[i].fe_logical == 0)
+ _stats_add_extent(mem, &fm_pending, fm_pending.fe_flags);
+
fiemap->fm_start = (fm_ext[i - 1].fe_logical +
fm_ext[i - 1].fe_length);
} while (last == 0);
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=56e4e2ce2ba05990…
Commit: 56e4e2ce2ba05990eb4e8ced8a9a966b986f14ab
Parent: 273ccb11704075b1876f6931e9e8de19ff2b31a3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sun Dec 11 10:25:15 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 11 23:24:19 2016 +0100
tests: track leaked devices in tests
When test calls teardown, no devices created by test are expected
to be left in table. Trap such orphans and make the test fail.
---
test/lib/aux.sh | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/test/lib/aux.sh b/test/lib/aux.sh
index 7f3c84a..4749f81 100644
--- a/test/lib/aux.sh
+++ b/test/lib/aux.sh
@@ -520,6 +520,8 @@ teardown() {
if test -f TESTNAME ; then
+ TEST_LEAKED_DEVICES=$(dmsetup table | grep "$PREFIX" | grep -v "${PREFIX}pv") || true
+
kill_tagged_processes
if test -n "$LVM_TEST_LVMLOCKD_TEST" ; then
@@ -567,6 +569,12 @@ teardown() {
fi
+ test -z "$TEST_LEAKED_DEVICES" || {
+ echo "Unexpected devices left dm table:"
+ echo "$TEST_LEAKED_DEVICES"
+ return 1
+ }
+
test -n "$TESTDIR" && {
cd "$TESTOLDPWD"
rm -rf "$TESTDIR" || echo BLA
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=198f335139f7a538…
Commit: 198f335139f7a538272c8cb6657ad4f5d58b01db
Parent: 4a33e4c509fb72bf3540d20bd35e1f0944e1d37a
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Dec 10 15:07:14 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sun Dec 11 23:24:19 2016 +0100
tests: slower device
Some of test machines are too fast, slow raid syncing even more.
---
test/shell/lvchange-rebuild-raid.sh | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/test/shell/lvchange-rebuild-raid.sh b/test/shell/lvchange-rebuild-raid.sh
index 6b91941..df6a8cb 100644
--- a/test/shell/lvchange-rebuild-raid.sh
+++ b/test/shell/lvchange-rebuild-raid.sh
@@ -21,7 +21,7 @@ aux prepare_vg 8
# Delay legs so that rebuilding status characters can be read
for d in $(< DEVICES)
do
- aux delay_dev "$d" 0 15 $(get first_extent_sector "$d")
+ aux delay_dev "$d" 0 20 $(get first_extent_sector "$d")
done
# rhbz 1064592
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d8ba8ee9aea0b23a…
Commit: d8ba8ee9aea0b23a4ff03d19f7ddbe6511cdcbbd
Parent: 1de3e106c96f6df7b32e072b6a1a3f924fa041bc
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Sat Dec 10 13:07:03 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sat Dec 10 13:31:12 2016 +0000
libdm: use a private pool for filemap extent table
When mapping regions to a file descriptor, a temporary table of
extent descriptors is built using the dm_pool object building
interface.
Previously this use borrowed the dms->mem region and counter
table pool (since nothing can interleave with the allocation
while the caller is still in dm_stats_create_regions_from_fd()).
This turns out to be problematic for error recovery. When a
region creation operation fails partway through file mapping,
we need to roll back the set of already created regions and
this requires a listed handle: the dm_stats_list() will then
allocate from the same pool as the extents; we either have
to throw away valid list data, or leak the extent table, to
return the handle in a valid state.
Avoid this problem by creating a new, temporary mem pool in
_stats_create_file_regions() to hold the extent data, and
discarding it on exit from the function.
---
WHATS_NEW_DM | 1 +
libdm/libdm-stats.c | 19 ++++++++++++++++---
2 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 4113876..73707b6 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.138 -
=====================================
+ Separate filemap extent allocation from region table.
Fix segmentation fault when filemap region creation fails
Fix performance of region cleanup for failed filemap creation.
Fix very slow region deletion with many regions.
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 34870e3..78b66ab 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4324,6 +4324,7 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
int precise, uint64_t *count)
{
uint64_t *regions = NULL, i, max_region;
+ struct dm_pool *extent_mem = NULL;
struct _extent *extents = NULL;
char *hist_arg = NULL;
struct statfs fsbuf;
@@ -4357,9 +4358,19 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
return 0;
}
- if (!(extents = _stats_get_extents_for_file(dms->mem, fd, count)))
+ /* Use a temporary, private pool for the extent table. This avoids
+ * hijacking the dms->mem (region table) pool which would lead to
+ * interleaving temporary allocations with dm_stats_list() data,
+ * causing complications in the error path.
+ */
+ if (!(extent_mem = dm_pool_create("extents", sizeof(*extents))))
return_0;
+ if (!(extents = _stats_get_extents_for_file(extent_mem, fd, count))) {
+ dm_pool_destroy(extent_mem);
+ return_0;
+ }
+
if (bounds) {
/* _build_histogram_arg enables precise if vals < 1ms. */
if (!(hist_arg = _build_histogram_arg(bounds, &precise)))
@@ -4386,7 +4397,8 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
if (bounds)
dm_free(hist_arg);
- dm_pool_free(dms->mem, extents);
+ dm_pool_free(extent_mem, extents);
+ dm_pool_destroy(extent_mem);
return regions;
out_remove:
@@ -4407,7 +4419,8 @@ out_remove:
*count = 0;
out:
- dm_pool_free(dms->mem, extents);
+ dm_pool_free(extent_mem, extents);
+ dm_pool_destroy(extent_mem);
dm_free(hist_arg);
dm_free(regions);
return NULL;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2d1dbb9eddd9dbc3…
Commit: 2d1dbb9eddd9dbc3aedf4572926178e532899995
Parent: 97c4490cc53157adde6da84933524f22149f449f
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Fri Dec 9 23:59:51 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sat Dec 10 11:59:16 2016 +0000
libdm: fix performance of failed filemap cleanup
While cleaning up the table of already created regions during a
failed dm_stats_create_regions_from_fd(), list the handle once,
and call _stats_delete_region() directly. This avoids sending a
@stats_list message for each region deleted, reducing runtime
from 6s to 0.7s when cleaning up ~250 out of ~10000 regions:
# time dmstats create --filemap b.img
device-mapper: message ioctl on (253:0) failed: Cannot allocate memory
Failed to create region 246 of 309 at 9388032.
Could not create regions from file /root/b.img
<< pauses here >>
Command failed
real 0m6.267s
user 0m3.770s
sys 0m2.487s
# time dmstats create --filemap b.img
device-mapper: message ioctl on (253:0) failed: Cannot allocate memory
Failed to create region 246 of 309 at 9388032.
Could not create regions from file /root/b.img
Command failed
real 0m0.716s
user 0m0.034s
sys 0m0.581s
Testing the error path requires region creation to start to
fail part way through the operation (in order to have regions
to clean up): the simplest way is to ensure the system is
close to the kernel limit of 1/4 RAM or 1/2 vmalloc space
consumed by dmstats data.
---
libdm/libdevmapper.h | 21 +++++++++++++--------
libdm/libdm-stats.c | 20 +++++++++++++++-----
2 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 09e3fcc..fe2e410 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1297,24 +1297,29 @@ int dm_stats_get_group_descriptor(const struct dm_stats *dms,
* filesystem and optionally place them into a group.
*
* File descriptor fd must reference a regular file, open for reading,
- * in a local file system that supports the FIEMAP ioctl and that
+ * in a local file system that supports the FIEMAP ioctl, and that
* returns data describing the physical location of extents.
*
* The file descriptor can be closed by the caller following the call
* to dm_stats_create_regions_from_fd().
*
- * The function returns a pointer to an array of uint64_t containing
- * the IDs of the newly created regions. The array is terminated by the
- * value DM_STATS_REGIONS_ALL and should be freed using dm_free() when
- * no longer required.
- *
* Unless nogroup is non-zero the regions will be placed into a group
- * and the group alias is set to the value supplied.
+ * and the group alias set to the value supplied (if alias is NULL no
+ * group alias will be assigned).
+ *
+ * On success the function returns a pointer to an array of uint64_t
+ * containing the IDs of the newly created regions. The region_id
+ * array is terminated by the value DM_STATS_REGION_NOT_PRESENT and
+ * should be freed using dm_free() when no longer required. On error
+ * NULL is returned.
+ *
+ * Following a call to dm_stats_create_regions_from_fd() the handle
+ * is guaranteed to be in a listed state, and to contain any region
+ * and group identifiers created by the operation.
*
* The group_id for the new group is equal to the region_id value in
* the first array element.
*
- * File mapped histograms will be supported in a future version.
*/
uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
int group, int precise,
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 1cabd9a..34870e3 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4323,8 +4323,8 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
struct dm_histogram *bounds,
int precise, uint64_t *count)
{
+ uint64_t *regions = NULL, i, max_region;
struct _extent *extents = NULL;
- uint64_t *regions = NULL, i;
char *hist_arg = NULL;
struct statfs fsbuf;
struct stat buf;
@@ -4390,11 +4390,22 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
return regions;
out_remove:
- /* clean up regions after create failure */
- for (--i; i != DM_STATS_REGION_NOT_PRESENT; i--)
- if (!dm_stats_delete_region(dms, regions[i]))
+ /* New region creation may begin to fail part-way through creating
+ * a set of file mapped regions: in this case we need to roll back
+ * the regions that were already created and return the handle to
+ * a consistent state. A listed handle is required for this: use a
+ * single list operation and call _stats_delete_region() directly
+ * to avoid a @stats_list ioctl and list parsing for each region.
+ */
+ dm_stats_list(dms, NULL);
+
+ max_region = i;
+ for (i = max_region - 1; i < max_region; i++)
+ if (!_stats_delete_region(dms, regions[i]))
log_error("Could not delete region " FMTu64 ".", i);
+ *count = 0;
+
out:
dm_pool_free(dms->mem, extents);
dm_free(hist_arg);
@@ -4402,7 +4413,6 @@ out:
return NULL;
}
-
uint64_t *dm_stats_create_regions_from_fd(struct dm_stats *dms, int fd,
int group, int precise,
struct dm_histogram *bounds,
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=97c4490cc53157ad…
Commit: 97c4490cc53157adde6da84933524f22149f449f
Parent: c459f23565e86eb9a8a116995cda7dcaed858b9f
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Fri Dec 9 22:58:25 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sat Dec 10 11:57:14 2016 +0000
libdm: split off internal _stats_delete_region()
Split dm_stats_delete_region() so that internal callers can manage
the handle state themselves.
dm_stats_delete_region() now just handles checking the state of the
handle, reporting validation errors, and calling dm_stats_list() if
necessary, before calling _stats_delete_region().
The new _stats_delete_region() function performs the actual group
member removal and region deletion, and requires a fully listed
handle to operate.
Callers that repeatedly delete regions can use a single listed
handle for many operations on the same device, avoiding one
message ioctl per region deleted: since @stats_list with many
regions is expensive, this yields large runtime improvements.
---
libdm/libdm-stats.c | 43 ++++++++++++++++++++++++++-----------------
1 files changed, 26 insertions(+), 17 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 438a1ed..1cabd9a 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -2018,10 +2018,34 @@ static int _stats_remove_region_id_from_group(struct dm_stats *dms,
return _stats_set_aux(dms, group_id, dms->regions[group_id].aux_data);
}
-int dm_stats_delete_region(struct dm_stats *dms, uint64_t region_id)
+static int _stats_delete_region(struct dm_stats *dms, uint64_t region_id)
{
char msg[STATS_MSG_BUF_LEN];
struct dm_task *dmt;
+
+ if (_stats_region_is_grouped(dms, region_id))
+ if (!_stats_remove_region_id_from_group(dms, region_id)) {
+ log_error("Could not remove region ID " FMTu64 " from "
+ "group ID " FMTu64,
+ region_id, dms->regions[region_id].group_id);
+ return 0;
+ }
+
+ if (!dm_snprintf(msg, sizeof(msg), "@stats_delete " FMTu64, region_id)) {
+ log_error("Could not prepare @stats_delete message.");
+ return 0;
+ }
+
+ dmt = _stats_send_message(dms, msg);
+ if (!dmt)
+ return_0;
+ dm_task_destroy(dmt);
+
+ return 1;
+}
+
+int dm_stats_delete_region(struct dm_stats *dms, uint64_t region_id)
+{
int listed = 0;
if (!_stats_bound(dms))
@@ -2065,23 +2089,8 @@ int dm_stats_delete_region(struct dm_stats *dms, uint64_t region_id)
goto bad;
}
- if(_stats_region_is_grouped(dms, region_id))
- if (!_stats_remove_region_id_from_group(dms, region_id)) {
- log_error("Could not remove region ID " FMTu64 " from "
- "group ID " FMTu64,
- region_id, dms->regions[region_id].group_id);
- goto bad;
- }
-
- if (!dm_snprintf(msg, sizeof(msg), "@stats_delete " FMTu64, region_id)) {
- log_error("Could not prepare @stats_delete message.");
+ if (!_stats_delete_region(dms, region_id))
goto bad;
- }
-
- dmt = _stats_send_message(dms, msg);
- if (!dmt)
- return_0;
- dm_task_destroy(dmt);
if (!listed)
/* wipe region and mark as not present */
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=30ad254d84047ffe…
Commit: 30ad254d84047ffe3eba98943855b53a893390e2
Parent: 7fd2fa22ddb3ed97283305100567cc4b5122ddb3
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Fri Dec 9 15:50:41 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Fri Dec 9 16:04:13 2016 +0000
libdm: use correct region_id when cleaning up a failed filemap
If we fail to create a region during dm_stats_create_regions_from_fd(),
we must remove all regions that were created to do this to date. This
needs to loop over the table of region_id values that were populated
by _stats_create_file_regions() before the error.
The code for this failure case in the out_remove branch incorrectly
uses the table index as the region_id:
for (--i; i != DM_STATS_REGION_NOT_PRESENT; i--) {
if (!dm_stats_delete_region(dms, i))
log_error("Could not delete region " FMTu64 ".", i);
}
This causes the cleanup code to delete a completely unrelated set
of regions (since the index here will always be nr_regions..0).
Fix it to pass the actual region_id stored in regions[i] instead.
---
libdm/libdm-stats.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 3900433..438a1ed 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -4382,10 +4382,9 @@ static uint64_t *_stats_create_file_regions(struct dm_stats *dms, int fd,
out_remove:
/* clean up regions after create failure */
- for (--i; i != DM_STATS_REGION_NOT_PRESENT; i--) {
- if (!dm_stats_delete_region(dms, i))
+ for (--i; i != DM_STATS_REGION_NOT_PRESENT; i--)
+ if (!dm_stats_delete_region(dms, regions[i]))
log_error("Could not delete region " FMTu64 ".", i);
- }
out:
dm_pool_free(dms->mem, extents);
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6dd0bd0255d585fe…
Commit: 6dd0bd0255d585feca61000432d2de9552ede4e0
Parent: 0ce9ae3cda9411f8f2a5491b07a6c4f06ab44da1
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Thu Dec 8 20:55:47 2016 +0000
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Fri Dec 9 10:55:39 2016 +0000
libdm-stats: fix dm_stats_delete_region() performance
Fix a silly bug in dm_stats_delete_region() that hugely inflates
runtimes when deleting a large number of regions.
For ~50,000 regions this change reduces the runtime from 98s to
6s on my test systems (a ~93% reduction).
The bug exists because dm_stats_delete_region() applies a truth
test to the return value of dm_stats_get_nr_areas(); this is
never correct usage - it will walk the entire region table and
calculate area counts for each region (which is roughly O(n^2)
in the number of regions, as dm_stats_delete_region() is being
called inside a region walk).
Although the individual area calculation is not that costly,
uselessly running anything 2,500,000,000 times over gets a bit
slow.
A much cheaper test (which is always true if the areas check is
true) is to just test dm_stats_get_nr_regions() or dms->regions;
if either is true it implies at least one area exists.
Old:
Performance counter stats for 'dmstats delete --allregions --alldevices':
98117.791458 task-clock (msec) # 1.000 CPUs utilized
127 context-switches # 0.001 K/sec
3 cpu-migrations # 0.000 K/sec
6,631 page-faults # 0.068 K/sec
307,711,724,562 cycles # 3.136 GHz
544,762,959,577 instructions # 1.77 insn per cycle
84,287,824,115 branches # 859.047 M/sec
2,538,875 branch-misses # 0.00% of all branches
98.119578733 seconds time elapsed
New:
Performance counter stats for 'dmstats delete --allregions --alldevices':
6427.251074 task-clock (msec) # 1.000 CPUs utilized
6 context-switches # 0.001 K/sec
0 cpu-migrations # 0.000 K/sec
6,634 page-faults # 0.001 M/sec
21,613,018,724 cycles # 3.363 GHz
3,794,755,445 instructions # 0.18 insn per cycle
852,974,026 branches # 132.712 M/sec
808,625 branch-misses # 0.09% of all branches
6.428953647 seconds time elapsed
---
libdm/libdm-stats.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-stats.c b/libdm/libdm-stats.c
index 2fc00da..411fd80 100644
--- a/libdm/libdm-stats.c
+++ b/libdm/libdm-stats.c
@@ -2051,7 +2051,7 @@ int dm_stats_delete_region(struct dm_stats *dms, uint64_t region_id)
goto bad;
}
- if (!dm_stats_get_nr_areas(dms)) {
+ if (!dm_stats_get_nr_regions(dms)) {
log_error("Could not delete region ID " FMTu64 ": "
"no regions found", region_id);
goto bad;
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=e2c7e0ad1196cc93…
Commit: e2c7e0ad1196cc9323b63807ed199bcf4b10807c
Parent: 6fd20be629b6dceb96702c5f875a2e612e6f465d
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Dec 5 15:23:18 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Dec 5 17:10:14 2016 +0100
activation: optimize away lv_has_target_type
It's actually not needed to call extra lv_has_target_type() to detect
snapshot merge is in progress - decode this right during status
capturing and save even few extra ioctl calls.
---
WHATS_NEW | 1 +
lib/activate/activate.c | 50 ++++++++++++++++++++++++++++------------------
2 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index a097477..df4c49e 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Avoid using lv_has_target_type() call within lv_info_with_seg_status.
Simplify internal lv_info_with_seg_status API.
Decide which status is needed in one place for lv_info_with_seg_status.
Fix matching of LV segment when checking for it info status.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index afdf518..3128f36 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -757,7 +757,7 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
{
- const struct logical_volume *lv = status->lv = lv_seg->lv;
+ const struct logical_volume *olv, *lv = status->lv = lv_seg->lv;
if (!activation())
return 0;
@@ -780,36 +780,46 @@ int lv_info_with_seg_status(struct cmd_context *cmd,
status->info.exists = 0; /* So pool LV is not active */
}
return 1;
- } else if (lv_is_origin(lv) &&
- (!lv_is_merging_origin(lv) ||
- !lv_has_target_type(cmd->mem, lv, NULL, TARGET_NAME_SNAPSHOT_MERGE))) {
+ } else if (lv_is_origin(lv)) {
/* Query segment status for 'layered' (-real) device most of the time,
* only for merging snapshot, query its progress.
* TODO: single LV may need couple status to be exposed at once....
* but this needs more logical background
*/
- /* Show INFO for actual origin */
- if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL, with_open_count, with_read_ahead))
+ /* Show INFO for actual origin and grab status for merging origin */
+ if (!_lv_info(cmd, lv, 0, &status->info, lv_seg,
+ lv_is_merging_origin(lv) ? &status->seg_status : NULL,
+ with_open_count, with_read_ahead))
return_0;
- if (status->info.exists)
+ if (status->info.exists &&
+ (status->seg_status.type != SEG_STATUS_SNAPSHOT)) /* Not merging */
/* Grab STATUS from layered -real */
(void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
} else if (lv_is_cow(lv)) {
- if (lv_is_merging_cow(lv) &&
- lv_has_target_type(cmd->mem, origin_from_cow(lv), NULL, TARGET_NAME_SNAPSHOT_MERGE)) {
- /*
- * When merge is in progress, query merging origin LV instead.
- * COW volume is already mapped as error target in this case.
- */
- status->lv = lv = origin_from_cow(lv);
- lv_seg = first_seg(lv);
- log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
- display_lvname(lv));
- } else
- /* Hadle fictional lvm2 snapshot and query snapshotX volume */
- lv_seg = find_snapshot(lv);
+ if (lv_is_merging_cow(lv)) {
+ olv = origin_from_cow(lv);
+
+ if (!_lv_info(cmd, olv, 0, &status->info, first_seg(olv), &status->seg_status,
+ with_open_count, with_read_ahead))
+ return_0;
+
+ if (status->seg_status.type == SEG_STATUS_SNAPSHOT) {
+ log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
+ display_lvname(lv));
+ /*
+ * When merge is in progress, query merging origin LV instead.
+ * COW volume is already mapped as error target in this case.
+ */
+ status->lv = olv;
+ return 1;
+ }
+
+ /* Merge not yet started, still a snapshot... */
+ }
+ /* Hadle fictional lvm2 snapshot and query snapshotX volume */
+ lv_seg = find_snapshot(lv);
}
return _lv_info(cmd, lv, 0, &status->info, lv_seg, &status->seg_status,
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6fd20be629b6dceb…
Commit: 6fd20be629b6dceb96702c5f875a2e612e6f465d
Parent: ed93f0973a307634d1266aeab5c0d2bbceab086e
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Dec 5 14:31:25 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Dec 5 17:09:47 2016 +0100
activation: lv_info_with_seg_status API change
Drop LV from passed API arg - it's always segment being checked.
Also use_layer is now in full control of lv_info_with_seg_status().
It decides which device needs to be checked to get 'the most info'.
TODO: future version should be able to expose status from
---
WHATS_NEW | 1 +
lib/activate/activate.c | 47 +++++++++++++----------------------------------
lib/activate/activate.h | 16 +++++-----------
lib/metadata/lv.c | 6 +++---
tools/reporter.c | 18 ++++++++----------
5 files changed, 30 insertions(+), 58 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 2b0e822..a097477 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Simplify internal lv_info_with_seg_status API.
Decide which status is needed in one place for lv_info_with_seg_status.
Fix matching of LV segment when checking for it info status.
Report log_warn when status cannot be parsed.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 1b1f7e4..afdf518 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -741,32 +741,24 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
}
/*
- * Returns 1 if lv_seg_status structure populated,
- * else 0 on failure or if device not active locally.
- */
-int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
- int use_layer, struct lv_seg_status *lv_seg_status)
-{
- if (!activation())
- return 0;
-
- return _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, lv_seg_status, 0, 0);
-}
-
-/*
- * Returns 1 if lv_with_info_and_seg_status structure populated,
+ * Returns 1 if lv_with_info_and_seg_status info structure populated,
* else 0 on failure or if device not active locally.
*
* When seg_status parsing had troubles it will set type to SEG_STATUS_UNKNOWN.
*
- * This is the same as calling lv_info and lv_status,
- * but* it's done in one go with one ioctl if possible! ]
+ * Using usually one ioctl to obtain info and status.
+ * More complex segment do collect info from one device,
+ * but status from another device.
+ *
+ * TODO: further improve with more statuses (i.e. snapshot's origin/merge)
*/
-int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
- const struct lv_segment *lv_seg, int use_layer,
+int lv_info_with_seg_status(struct cmd_context *cmd,
+ const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead)
{
+ const struct logical_volume *lv = status->lv = lv_seg->lv;
+
if (!activation())
return 0;
@@ -774,23 +766,10 @@ int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume
/* INFO is not set as cache-pool cannot be active.
* STATUS is collected from cache LV */
lv_seg = get_only_segment_using_this_lv(lv);
- (void) _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
+ (void) _lv_info(cmd, lv_seg->lv, 0, NULL, lv_seg, &status->seg_status, 0, 0);
return 1;
}
- /* By default, take the first LV segment to report status for. */
- if (!lv_seg)
- lv_seg = first_seg(lv);
-
- if (lv != lv_seg->lv)
- /*
- * If the info is requested for an LV and segment
- * status for segment that belong to another LV,
- * we need to acquire info and status separately!
- */
- return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
- _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
-
if (lv_is_thin_pool(lv)) {
/* Always collect status for '-tpool' */
if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0) &&
@@ -824,7 +803,7 @@ int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume
* When merge is in progress, query merging origin LV instead.
* COW volume is already mapped as error target in this case.
*/
- lv = origin_from_cow(lv);
+ status->lv = lv = origin_from_cow(lv);
lv_seg = first_seg(lv);
log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
display_lvname(lv));
@@ -833,7 +812,7 @@ int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume
lv_seg = find_snapshot(lv);
}
- return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
+ return _lv_info(cmd, lv, 0, &status->info, lv_seg, &status->seg_status,
with_open_count, with_read_ahead);
}
diff --git a/lib/activate/activate.h b/lib/activate/activate.h
index 3922d78..db8d997 100644
--- a/lib/activate/activate.h
+++ b/lib/activate/activate.h
@@ -54,11 +54,12 @@ struct lv_seg_status {
};
struct lv_with_info_and_seg_status {
- const struct logical_volume *lv; /* input */
int info_ok;
+ const struct logical_volume *lv; /* output */
struct lvinfo info; /* output */
int seg_part_of_lv; /* output */
- struct lv_seg_status seg_status; /* input/output, see lv_seg_status */
+ struct lv_seg_status seg_status; /* output, see lv_seg_status */
+ /* TODO: add extra status for snapshot origin */
};
struct lv_activate_opts {
@@ -133,21 +134,14 @@ int lv_info_by_lvid(struct cmd_context *cmd, const char *lvid_s, int use_layer,
struct lvinfo *info, int with_open_count, int with_read_ahead);
/*
- * Returns 1 if lv_seg_status structure has been populated,
- * else 0 on failure or if device not active locally.
- */
-int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
- int use_layer, struct lv_seg_status *lv_seg_status);
-
-/*
* Returns 1 if lv_info_and_seg_status structure has been populated,
* else 0 on failure or if device not active locally.
*
* lv_info_with_seg_status is the same as calling lv_info and then lv_status,
* but this fn tries to do that with one ioctl if possible.
*/
-int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume *lv,
- const struct lv_segment *lv_seg, int use_layer,
+int lv_info_with_seg_status(struct cmd_context *cmd,
+ const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int with_open_count, int with_read_ahead);
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index eb5066a..087b564 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -255,7 +255,7 @@ char *lvseg_kernel_discards_dup(struct dm_pool *mem, const struct lv_segment *se
if (!(status.seg_status.mem = dm_pool_create("reporter_pool", 1024)))
return_NULL;
- if (!(status.info_ok = lv_info_with_seg_status(seg->lv->vg->cmd, seg->lv, seg, 1, &status, 0, 0)))
+ if (!(status.info_ok = lv_info_with_seg_status(seg->lv->vg->cmd, seg, &status, 0, 0)))
goto_bad;
ret = lvseg_kernel_discards_dup_with_info_and_seg_status(mem, &status);
@@ -407,7 +407,7 @@ dm_percent_t lvseg_percent_with_info_and_seg_status(const struct lv_with_info_an
/* TODO: expose highest mapped sector */
p = DM_PERCENT_INVALID;
else {
- seg = first_seg(lvdm->lv);
+ seg = lvdm->seg_status.seg;
/* Pool allocates whole chunk so round-up to nearest one */
csize = first_seg(seg->pool_lv)->chunk_size;
csize = ((seg->lv->size + csize - 1) / csize) * csize;
@@ -1318,7 +1318,7 @@ char *lv_attr_dup(struct dm_pool *mem, const struct logical_volume *lv)
if (!(status.seg_status.mem = dm_pool_create("reporter_pool", 1024)))
return_0;
- if (!(status.info_ok = lv_info_with_seg_status(lv->vg->cmd, lv, first_seg(lv), 1, &status, 1, 1)))
+ if (!(status.info_ok = lv_info_with_seg_status(lv->vg->cmd, first_seg(lv), &status, 1, 1)))
goto_bad;
ret = lv_attr_dup_with_info_and_seg_status(mem, &status);
diff --git a/tools/reporter.c b/tools/reporter.c
index 0a9ca34..fc87c06 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -88,14 +88,13 @@ static int _vgs_single(struct cmd_context *cmd __attribute__((unused)),
}
static int _do_info_and_status(struct cmd_context *cmd,
- const struct logical_volume *lv,
const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int do_info, int do_status)
{
- status->lv = lv;
+ status->lv = lv_seg->lv;
- if (lv_is_historical(lv))
+ if (lv_is_historical(lv_seg->lv))
return 1;
if (do_status) {
@@ -104,13 +103,12 @@ static int _do_info_and_status(struct cmd_context *cmd,
if (do_info)
/* both info and status */
- status->info_ok = lv_info_with_seg_status(cmd, lv, lv_seg, 0, status, 1, 1);
+ status->info_ok = lv_info_with_seg_status(cmd, lv_seg, status, 1, 1);
else
- /* status only */
- status->info_ok = lv_info_with_seg_status(cmd, lv, lv_seg, 0, status, 0, 0);
+ status->info_ok = lv_info_with_seg_status(cmd, lv_seg, status, 0, 0);
} else if (do_info)
/* info only */
- status->info_ok = lv_info(cmd, lv, 0, &status->info, 1, 1);
+ status->info_ok = lv_info(cmd, status->lv, 0, &status->info, 1, 1);
return 1;
}
@@ -126,7 +124,7 @@ static int _do_lvs_with_info_and_status_single(struct cmd_context *cmd,
};
int r = ECMD_FAILED;
- if (!_do_info_and_status(cmd, lv, NULL, &status, do_info, do_status))
+ if (!_do_info_and_status(cmd, first_seg(lv), &status, do_info, do_status))
goto_out;
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
@@ -176,7 +174,7 @@ static int _do_segs_with_info_and_status_single(struct cmd_context *cmd,
};
int r = ECMD_FAILED;
- if (!_do_info_and_status(cmd, seg->lv, seg, &status, do_info, do_status))
+ if (!_do_info_and_status(cmd, seg, &status, do_info, do_status))
goto_out;
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
@@ -302,7 +300,7 @@ static int _do_pvsegs_sub_single(struct cmd_context *cmd,
.lv = &_free_logical_volume
};
- if (seg && !_do_info_and_status(cmd, seg->lv, seg, &status, do_info, do_status))
+ if (seg && !_do_info_and_status(cmd, seg, &status, do_info, do_status))
goto_out;
if (!report_object(sh ? : handle->custom_handle, sh != NULL,
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ed93f0973a307634…
Commit: ed93f0973a307634d1266aeab5c0d2bbceab086e
Parent: 0089201588d65bf131d3fadd1cf5be67a562c4b1
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Mon Dec 5 10:20:42 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Dec 5 17:09:13 2016 +0100
activation: lv_info_with_seg_status unify status selection
Start moving selection of status taken for a LV into a single place.
The logic for showing info & status has been spread over multiple
places and were doing too complex decision going agains each other.
Unify selection of status of origin & cow scanned device.
TODO: in future we want to grab status for LV and layered LV and have
both statuses present for display - i.e. when 'old snapshot'
of thinLV is takes and there is ongoing merge - at some moment
we are not capable to show all needed info.
---
WHATS_NEW | 1 +
lib/activate/activate.c | 82 ++++++++++++++++++++++++++++++--------------
lib/activate/dev_manager.c | 56 +++++++++++++++--------------
tools/reporter.c | 41 +++-------------------
4 files changed, 91 insertions(+), 89 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 0f5ed02..2b0e822 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Decide which status is needed in one place for lv_info_with_seg_status.
Fix matching of LV segment when checking for it info status.
Report log_warn when status cannot be parsed.
Test segment type before accessing segment members when checking status.
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index efb8912..1b1f7e4 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -688,32 +688,6 @@ static int _lv_info(struct cmd_context *cmd, const struct logical_volume *lv,
if (seg_status) {
/* TODO: for now it's mess with seg_status */
seg_status->seg = seg;
- if (lv_is_merging_cow(lv)) {
- if (lv_has_target_type(cmd->mem, origin_from_cow(lv), NULL, TARGET_NAME_SNAPSHOT_MERGE)) {
- /*
- * When the snapshot-merge has not yet started, query COW LVs as is.
- * When merge is in progress, query merging origin LV instead.
- * COW volume is already mapped as error target in this case.
- */
- lv = origin_from_cow(lv);
- seg_status->seg = first_seg(lv);
- log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
- display_lvname(lv));
- }
- } else if (!use_layer && lv_is_origin(lv) && !lv_is_external_origin(lv)) {
- /*
- * Query status for 'layered' (-real) device most of the time,
- * only when snapshot merge started, query its progress.
- * TODO: single LV may need couple status to be exposed at once....
- * but this needs more logical background
- */
- if (!lv_is_merging_origin(lv) ||
- !lv_has_target_type(cmd->mem, origin_from_cow(lv), NULL, TARGET_NAME_SNAPSHOT_MERGE))
- use_layer = 1;
- } else if (lv_is_cow(lv)) {
- /* Hadle fictional lvm2 snapshot and query snapshotX volume */
- seg_status->seg = find_snapshot(lv);
- }
}
if (!dev_manager_info(cmd, lv,
@@ -783,6 +757,8 @@ int lv_status(struct cmd_context *cmd, const struct lv_segment *lv_seg,
* Returns 1 if lv_with_info_and_seg_status structure populated,
* else 0 on failure or if device not active locally.
*
+ * When seg_status parsing had troubles it will set type to SEG_STATUS_UNKNOWN.
+ *
* This is the same as calling lv_info and lv_status,
* but* it's done in one go with one ioctl if possible! ]
*/
@@ -794,6 +770,18 @@ int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume
if (!activation())
return 0;
+ if (lv_is_used_cache_pool(lv)) {
+ /* INFO is not set as cache-pool cannot be active.
+ * STATUS is collected from cache LV */
+ lv_seg = get_only_segment_using_this_lv(lv);
+ (void) _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
+ return 1;
+ }
+
+ /* By default, take the first LV segment to report status for. */
+ if (!lv_seg)
+ lv_seg = first_seg(lv);
+
if (lv != lv_seg->lv)
/*
* If the info is requested for an LV and segment
@@ -803,6 +791,48 @@ int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume
return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
_lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
+ if (lv_is_thin_pool(lv)) {
+ /* Always collect status for '-tpool' */
+ if (_lv_info(cmd, lv, 1, &status->info, lv_seg, &status->seg_status, 0, 0) &&
+ (status->seg_status.type == SEG_STATUS_THIN_POOL)) {
+ /* There is -tpool device, but query 'active' state of 'fake' thin-pool */
+ if (!_lv_info(cmd, lv, 0, NULL, NULL, NULL, 0, 0) &&
+ !status->seg_status.thin_pool->needs_check)
+ status->info.exists = 0; /* So pool LV is not active */
+ }
+ return 1;
+ } else if (lv_is_origin(lv) &&
+ (!lv_is_merging_origin(lv) ||
+ !lv_has_target_type(cmd->mem, lv, NULL, TARGET_NAME_SNAPSHOT_MERGE))) {
+ /* Query segment status for 'layered' (-real) device most of the time,
+ * only for merging snapshot, query its progress.
+ * TODO: single LV may need couple status to be exposed at once....
+ * but this needs more logical background
+ */
+ /* Show INFO for actual origin */
+ if (!_lv_info(cmd, lv, 0, &status->info, NULL, NULL, with_open_count, with_read_ahead))
+ return_0;
+
+ if (status->info.exists)
+ /* Grab STATUS from layered -real */
+ (void) _lv_info(cmd, lv, 1, NULL, lv_seg, &status->seg_status, 0, 0);
+ return 1;
+ } else if (lv_is_cow(lv)) {
+ if (lv_is_merging_cow(lv) &&
+ lv_has_target_type(cmd->mem, origin_from_cow(lv), NULL, TARGET_NAME_SNAPSHOT_MERGE)) {
+ /*
+ * When merge is in progress, query merging origin LV instead.
+ * COW volume is already mapped as error target in this case.
+ */
+ lv = origin_from_cow(lv);
+ lv_seg = first_seg(lv);
+ log_debug_activation("Snapshot merge is in progress, querying status of %s instead.",
+ display_lvname(lv));
+ } else
+ /* Hadle fictional lvm2 snapshot and query snapshotX volume */
+ lv_seg = find_snapshot(lv);
+ }
+
return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
with_open_count, with_read_ahead);
}
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index 56c6d1d..a72d5a9 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -124,42 +124,41 @@ static int _get_segment_status_from_target_params(const char *target_name,
const char *params,
struct lv_seg_status *seg_status)
{
- struct segment_type *segtype;
+ const struct lv_segment *seg = seg_status->seg;
+ const struct segment_type *segtype = seg->segtype;
seg_status->type = SEG_STATUS_UNKNOWN; /* Parsing failed */
+ /* Switch to snapshot segtype status logic for merging origin */
+ /* This is 'dynamic' decision, both states are valid */
+ if (lv_is_merging_origin(seg->lv)) {
+ if (!strcmp(target_name, TARGET_NAME_SNAPSHOT_ORIGIN)) {
+ seg_status->type = SEG_STATUS_NONE;
+ return 1; /* Merge has not yet started */
+ }
+ if (!strcmp(target_name, TARGET_NAME_SNAPSHOT_MERGE) &&
+ !(segtype = get_segtype_from_string(seg->lv->vg->cmd, TARGET_NAME_SNAPSHOT)))
+ return_0;
+ /* Merging, parse 'snapshot' status of merge progress */
+ }
+
if (!params) {
log_warn("WARNING: Cannot find matching %s segment for %s.",
- seg_status->seg->segtype->name,
- display_lvname(seg_status->seg->lv));
+ segtype->name, display_lvname(seg_status->seg->lv));
return 0;
}
- /*
- * TODO: Add support for other segment types too!
- * The segment to report status for must be properly
- * selected for all the other types - mainly make sure
- * linear/striped, old snapshots and raids have proper
- * segment selected for status!
- */
- if (!strcmp(target_name, TARGET_NAME_SNAPSHOT_MERGE) &&
- lv_is_merging_origin(seg_status->seg->lv)) {
- /* Snapshot merge has started, check snapshot status */
- if (!(segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, TARGET_NAME_SNAPSHOT)))
- return_0;
- } else {
- if (!(segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, target_name)))
- return_0;
-
- /* Validate segtype from DM table and lvm2 metadata */
- if (segtype != seg_status->seg->segtype) {
- log_warn("WARNING: segment type %s found does not match "
- "expected segment type %s.",
- segtype->name, seg_status->seg->segtype->name);
- return 0;
- }
+ /* Validate target_name segtype from DM table with lvm2 metadata segtype */
+ if (strcmp(segtype->name, target_name) &&
+ /* If kernel's type isn't an exact match is it compatible? */
+ (!segtype->ops->target_status_compatible ||
+ !segtype->ops->target_status_compatible(target_name))) {
+ log_warn(INTERNAL_ERROR "WARNING: Segment type %s found does not match expected type %s for %s.",
+ target_name, segtype->name, display_lvname(seg_status->seg->lv));
+ return 0;
}
+ /* TODO: move into segtype method */
if (segtype_is_cache(segtype)) {
if (!dm_get_status_cache(seg_status->mem, params, &(seg_status->cache)))
return_0;
@@ -181,7 +180,10 @@ static int _get_segment_status_from_target_params(const char *target_name,
return_0;
seg_status->type = SEG_STATUS_SNAPSHOT;
} else
- /* Status not supported */
+ /*
+ * TODO: Add support for other segment types too!
+ * Status not supported
+ */
seg_status->type = SEG_STATUS_NONE;
return 1;
diff --git a/tools/reporter.c b/tools/reporter.c
index b7a2f39..0a9ca34 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -87,32 +87,12 @@ static int _vgs_single(struct cmd_context *cmd __attribute__((unused)),
return ECMD_PROCESSED;
}
-static void _choose_lv_segment_for_status_report(const struct logical_volume *lv, const struct lv_segment **lv_seg)
-{
- if (lv_is_used_cache_pool(lv)) {
- /* For a used cache pool, choose cache volume segment */
- *lv_seg = get_only_segment_using_this_lv(lv);
- return;
- }
-
- /*
- * By default, take the first LV segment to report status for.
- * If there's any other specific segment that needs to be
- * reported instead for the LV, choose it here and assign it
- * to lvdm->seg_status->seg. This is the segment whose
- * status line will be used for report exactly.
- */
- *lv_seg = first_seg(lv);
-}
-
static int _do_info_and_status(struct cmd_context *cmd,
const struct logical_volume *lv,
const struct lv_segment *lv_seg,
struct lv_with_info_and_seg_status *status,
int do_info, int do_status)
{
- unsigned use_layer = lv_is_thin_pool(lv) ? 1 : 0;
-
status->lv = lv;
if (lv_is_historical(lv))
@@ -121,27 +101,16 @@ static int _do_info_and_status(struct cmd_context *cmd,
if (do_status) {
if (!(status->seg_status.mem = dm_pool_create("reporter_pool", 1024)))
return_0;
- if (!lv_seg || seg_is_used_cache_pool(lv_seg))
- _choose_lv_segment_for_status_report(lv, &lv_seg);
- if (do_info) {
+ if (do_info)
/* both info and status */
- status->info_ok = lv_info_with_seg_status(cmd, lv, lv_seg, use_layer, status, 1, 1);
- /* for inactive thin-pools reset lv info struct */
- if (use_layer && status->info_ok &&
- !lv_info(cmd, lv, 0, NULL, 0, 0))
- memset(&status->info, 0, sizeof(status->info));
- /* for inactive cache reset lvinfo for its struct for cache-pool */
- if (lv_is_used_cache_pool(lv) && !status->info_ok) {
- memset(&status->info, 0, sizeof(status->info));
- status->info_ok = 1;
- }
- } else
+ status->info_ok = lv_info_with_seg_status(cmd, lv, lv_seg, 0, status, 1, 1);
+ else
/* status only */
- status->info_ok = lv_status(cmd, lv_seg, use_layer, &status->seg_status);
+ status->info_ok = lv_info_with_seg_status(cmd, lv, lv_seg, 0, status, 0, 0);
} else if (do_info)
/* info only */
- status->info_ok = lv_info(cmd, lv, use_layer, &status->info, 1, 1);
+ status->info_ok = lv_info(cmd, lv, 0, &status->info, 1, 1);
return 1;
}
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0089201588d65bf1…
Commit: 0089201588d65bf131d3fadd1cf5be67a562c4b1
Parent: 5ba2d58d28ace811c33e7e66b777fcca3f42149e
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Nov 30 13:43:43 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Dec 5 17:05:23 2016 +0100
cleanup: swap test order
Check for lv != lvseg->lv.
Make the logic of following patches look better and easier to read.
---
lib/activate/activate.c | 22 +++++++++++-----------
1 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/lib/activate/activate.c b/lib/activate/activate.c
index 8fc45b7..efb8912 100644
--- a/lib/activate/activate.c
+++ b/lib/activate/activate.c
@@ -794,17 +794,17 @@ int lv_info_with_seg_status(struct cmd_context *cmd, const struct logical_volume
if (!activation())
return 0;
- if (lv == lv_seg->lv)
- return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
- with_open_count, with_read_ahead);
+ if (lv != lv_seg->lv)
+ /*
+ * If the info is requested for an LV and segment
+ * status for segment that belong to another LV,
+ * we need to acquire info and status separately!
+ */
+ return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
+ _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
- /*
- * If the info is requested for an LV and segment
- * status for segment that belong to another LV,
- * we need to acquire info and status separately!
- */
- return _lv_info(cmd, lv, use_layer, &status->info, NULL, NULL, with_open_count, with_read_ahead) &&
- _lv_info(cmd, lv_seg->lv, use_layer, NULL, lv_seg, &status->seg_status, 0, 0);
+ return _lv_info(cmd, lv, use_layer, &status->info, lv_seg, &status->seg_status,
+ with_open_count, with_read_ahead);
}
#define OPEN_COUNT_CHECK_RETRIES 25
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4a4b22e11413ac76…
Commit: 4a4b22e11413ac76164fbdd9b3c353151c8dde70
Parent: 325c2c5687e42afd2c8611e4cefd73f4fb7fb6ed
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Dec 2 13:57:52 2016 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Mon Dec 5 17:04:24 2016 +0100
activation: status check switch to warn
When we can't parse status, switch to warning as this is not
considered an errornous case. LVS is not supposed to return
error status code when device is not what it's been expected to
be - but it should be WARNING a user there is something unexpected.
---
WHATS_NEW | 1 +
lib/activate/dev_manager.c | 29 +++++++++++++++--------------
2 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index fbf4f61..3aedebb 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.169 -
=====================================
+ Report log_warn when status cannot be parsed.
Test segment type before accessing segment members when checking status.
Implement compatible target function for stripe segment.
Use status info to report merge failed and snapshot invalid lvs fields.
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
index b8b1235..8ace08c 100644
--- a/lib/activate/dev_manager.c
+++ b/lib/activate/dev_manager.c
@@ -126,7 +126,14 @@ static int _get_segment_status_from_target_params(const char *target_name,
{
struct segment_type *segtype;
- seg_status->type = SEG_STATUS_UNKNOWN;
+ seg_status->type = SEG_STATUS_UNKNOWN; /* Parsing failed */
+
+ if (!params) {
+ log_warn("WARNING: Cannot find matching %s segment for %s.",
+ seg_status->seg->segtype->name,
+ display_lvname(seg_status->seg->lv));
+ return 0;
+ }
/*
* TODO: Add support for other segment types too!
@@ -141,19 +148,14 @@ static int _get_segment_status_from_target_params(const char *target_name,
if (!(segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, TARGET_NAME_SNAPSHOT)))
return_0;
} else {
- if (strcmp(target_name, TARGET_NAME_CACHE) &&
- strcmp(target_name, TARGET_NAME_SNAPSHOT) &&
- strcmp(target_name, TARGET_NAME_THIN_POOL) &&
- strcmp(target_name, TARGET_NAME_THIN))
- return 1; /* TODO: Do not know how to handle yet */
-
if (!(segtype = get_segtype_from_string(seg_status->seg->lv->vg->cmd, target_name)))
return_0;
+ /* Validate segtype from DM table and lvm2 metadata */
if (segtype != seg_status->seg->segtype) {
- log_error(INTERNAL_ERROR "_get_segment_status_from_target_params: "
- "segment type %s found does not match expected segment type %s",
- segtype->name, seg_status->seg->segtype->name);
+ log_warn("WARNING: segment type %s found does not match "
+ "expected segment type %s.",
+ segtype->name, seg_status->seg->segtype->name);
return 0;
}
}
@@ -178,10 +180,9 @@ static int _get_segment_status_from_target_params(const char *target_name,
if (!dm_get_status_snapshot(seg_status->mem, params, &seg_status->snapshot))
return_0;
seg_status->type = SEG_STATUS_SNAPSHOT;
- } else {
- log_error(INTERNAL_ERROR "Unsupported segment type %s.", segtype->name);
- return 0;
- }
+ } else
+ /* Status not supported */
+ seg_status->type = SEG_STATUS_NONE;
return 1;
}
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=07f9889b53eb3314…
Commit: 07f9889b53eb3314e3ca816ffbeb72d087e9282a
Parent: bb5eb324e3d503bf6dd8923531f63d3e1933ff0d
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu Dec 1 14:39:21 2016 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Thu Dec 1 14:55:29 2016 +0100
report: order fields by type for field defintions in columns.h
When displaying <reporting_command> -o help, we'd like to have fields
grouped nicely, not starting having groups interleaved as it was before.
The code that displays the help output for fields takes the order as
written in columns.h file - this caused output like:
$ lvs -o help
Logical Volume Fields
---------------------
...field list...
Logical Volume Device Info and Status Combined Fields
-----------------------------------------------------
...field list...
Logical Volume Fields
---------------------
...field list...
Logical Volume Device Status Fields
-----------------------------------
...field list...
Logical Volume Fields
---------------------
...field list...
Instead, let's have it without groups interleaved which may be
a bit confusing, so:
Logical Volume Fields
---------------------
...field list...
Logical Volume Device Status Fields
-----------------------------------
...field list...
Logical Volume Device Info and Status Combined Fields
-----------------------------------------------------
...field list...
..and so on.
---
lib/report/columns.h | 77 ++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 71 insertions(+), 6 deletions(-)
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 212f9ed..ffc92c0 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -21,9 +21,19 @@
* determines the order the entries appear in this file.
*
* When adding new entries take care to use the existing style.
+ *
+ * Do not interleave fields from different report types - for example,
+ * if you have a field of type "LVS" add it in between "LVS type fields"
+ * and "End of LVS type fields" comment. If you interleaved fields of
+ * different types here in this file, they would end up interleaved in
+ * the <reporting_command> -o help output too which may be confusing
+ * for users.
+ *
* Displayed fields names normally have a type prefix and use underscores.
+ *
* Field-specific internal functions names normally match the displayed
* field names but without underscores.
+ *
* Help text ends with a full stop.
*/
@@ -32,13 +42,15 @@
*/
/* *INDENT-OFF* */
+/*
+ * LVS type fields
+ */
FIELD(LVS, lv, STR, "LV UUID", lvid, 38, lvuuid, lv_uuid, "Unique identifier.", 0)
FIELD(LVS, lv, STR, "LV", lvid, 4, lvname, lv_name, "Name. LVs created for internal use are enclosed in brackets.", 0)
FIELD(LVS, lv, STR, "LV", lvid, 4, lvfullname, lv_full_name, "Full name of LV including its VG, namely VG/LV.", 0)
FIELD(LVS, lv, STR, "Path", lvid, 0, lvpath, lv_path, "Full pathname for LV. Blank for internal LVs.", 0)
FIELD(LVS, lv, STR, "DMPath", lvid, 0, lvdmpath, lv_dm_path, "Internal device-mapper pathname for LV (in /dev/mapper directory).", 0)
FIELD(LVS, lv, STR, "Parent", lvid, 0, lvparent, lv_parent, "For LVs that are components of another LV, the parent LV.", 0)
-FIELD(LVSINFOSTATUS, lv, STR, "Attr", lvid, 0, lvstatus, lv_attr, "Various attributes - see man page.", 0)
FIELD(LVS, lv, STR_LIST, "Layout", lvid, 10, lvlayout, lv_layout, "LV layout.", 0)
FIELD(LVS, lv, STR_LIST, "Role", lvid, 10, lvrole, lv_role, "LV role.", 0)
FIELD(LVS, lv, BIN, "InitImgSync", lvid, 10, lvinitialimagesync, lv_initial_image_sync, "Set if mirror/RAID images underwent initial resynchronization.", 0)
@@ -69,11 +81,6 @@ FIELD(LVS, lv, STR_LIST, "Ancestors", lvid, 0, lvancestors, lv_ancestors, "LV an
FIELD(LVS, lv, STR_LIST, "FAncestors", lvid, 0, lvfullancestors, lv_full_ancestors, "LV ancestors including stored history of the ancestry chain.", 0)
FIELD(LVS, lv, STR_LIST, "Descendants", lvid, 0, lvdescendants, lv_descendants, "LV descendants ignoring any stored history of the ancestry chain.", 0)
FIELD(LVS, lv, STR_LIST, "FDescendants", lvid, 0, lvfulldescendants, lv_full_descendants, "LV descendants including stored history of the ancestry chain.", 0)
-FIELD(LVSSTATUS, lv, PCT, "Data%", lvid, 6, datapercent, data_percent, "For snapshot, cache and thin pools and volumes, the percentage full if LV is active.", 0)
-FIELD(LVSSTATUS, lv, PCT, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0)
-FIELD(LVSSTATUS, lv, PCT, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For cache and thin pools, the percentage of metadata full if LV is active.", 0)
-FIELD(LVSSTATUS, lv, PCT, "Cpy%Sync", lvid, 0, copypercent, copy_percent, "For Cache, RAID, mirrors and pvmove, current percentage in-sync.", 0)
-FIELD(LVSSTATUS, lv, PCT, "Cpy%Sync", lvid, 0, copypercent, sync_percent, "For Cache, RAID, mirrors and pvmove, current percentage in-sync.", 0)
FIELD(LVS, lv, NUM, "Mismatches", lvid, 0, raidmismatchcount, raid_mismatch_count, "For RAID, number of mismatches found or repaired.", 0)
FIELD(LVS, lv, STR, "SyncAction", lvid, 0, raidsyncaction, raid_sync_action, "For RAID, the current synchronization action being performed.", 0)
FIELD(LVS, lv, NUM, "WBehind", lvid, 0, raidwritebehind, raid_write_behind, "For RAID1, the number of outstanding writes allowed to writemostly devices.", 0)
@@ -99,7 +106,13 @@ FIELD(LVS, lv, TIM, "RTime", lvid, 26, lvtimeremoved, lv_time_removed, "Removal
FIELD(LVS, lv, STR, "Host", lvid, 10, lvhost, lv_host, "Creation host of the LV, if known.", 0)
FIELD(LVS, lv, STR_LIST, "Modules", lvid, 0, modules, lv_modules, "Kernel device-mapper modules required for this LV.", 0)
FIELD(LVS, lv, BIN, "Historical", lvid, 0, lvhistorical, lv_historical, "Set if the LV is historical.", 0)
+/*
+ * End of LVS type fields
+ */
+/*
+ * LVSINFO type fields
+ */
FIELD(LVSINFO, lv, SNUM, "KMaj", lvid, 0, lvkmaj, lv_kernel_major, "Currently assigned major number or -1 if LV is not active.", 0)
FIELD(LVSINFO, lv, SNUM, "KMin", lvid, 0, lvkmin, lv_kernel_minor, "Currently assigned minor number or -1 if LV is not active.", 0)
FIELD(LVSINFO, lv, SIZ, "KRahead", lvid, 0, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0)
@@ -108,7 +121,18 @@ FIELD(LVSINFO, lv, BIN, "Suspended", lvid, 10, lvsuspended, lv_suspended, "Set i
FIELD(LVSINFO, lv, BIN, "LiveTable", lvid, 20, lvlivetable, lv_live_table, "Set if LV has live table present.", 0)
FIELD(LVSINFO, lv, BIN, "InactiveTable", lvid, 20, lvinactivetable, lv_inactive_table, "Set if LV has inactive table present.", 0)
FIELD(LVSINFO, lv, BIN, "DevOpen", lvid, 10, lvdeviceopen, lv_device_open, "Set if LV device is open.", 0)
+/*
+ * End of LVSINFO type fields
+ */
+/*
+ * LVSSTATUS type fields
+ */
+FIELD(LVSSTATUS, lv, PCT, "Data%", lvid, 6, datapercent, data_percent, "For snapshot, cache and thin pools and volumes, the percentage full if LV is active.", 0)
+FIELD(LVSSTATUS, lv, PCT, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0)
+FIELD(LVSSTATUS, lv, PCT, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For cache and thin pools, the percentage of metadata full if LV is active.", 0)
+FIELD(LVSSTATUS, lv, PCT, "Cpy%Sync", lvid, 0, copypercent, copy_percent, "For Cache, RAID, mirrors and pvmove, current percentage in-sync.", 0)
+FIELD(LVSSTATUS, lv, PCT, "Cpy%Sync", lvid, 0, copypercent, sync_percent, "For Cache, RAID, mirrors and pvmove, current percentage in-sync.", 0)
FIELD(LVSSTATUS, lv, NUM, "CacheTotalBlocks", lvid, 0, cache_total_blocks, cache_total_blocks, "Total cache blocks.", 0)
FIELD(LVSSTATUS, lv, NUM, "CacheUsedBlocks", lvid, 16, cache_used_blocks, cache_used_blocks, "Used cache blocks.", 0)
FIELD(LVSSTATUS, lv, NUM, "CacheDirtyBlocks", lvid, 0, cache_dirty_blocks, cache_dirty_blocks, "Dirty cache blocks.", 0)
@@ -121,7 +145,21 @@ FIELD(LVSSTATUS, lv, STR, "KCachePolicy", lvid, 18, kernel_cache_policy, kernel_
FIELD(LVSSTATUS, lv, STR, "Health", lvid, 15, lvhealthstatus, lv_health_status, "LV health status.", 0)
FIELD(LVSSTATUS, lv, STR, "KDiscards", lvid, 0, kdiscards, kernel_discards, "For thin pools, how discards are handled in kernel.", 0)
FIELD(LVSSTATUS, lv, BIN, "CheckNeeded", lvid, 15, lvcheckneeded, lv_check_needed, "For thin pools and cache volumes, whether metadata check is needed.", 0)
+/*
+ * End of LVSSTATUS type fields
+ */
+/*
+ * LVSINFOSTATUS type fields
+ */
+FIELD(LVSINFOSTATUS, lv, STR, "Attr", lvid, 0, lvstatus, lv_attr, "Various attributes - see man page.", 0)
+/*
+ * End of LVSINFOSTATUS type fields
+ */
+
+/*
+ * LABEL type fields
+ */
FIELD(LABEL, label, STR, "Fmt", type, 0, pvfmt, pv_fmt, "Type of metadata.", 0)
FIELD(LABEL, label, STR, "PV UUID", type, 38, pvuuid, pv_uuid, "Unique identifier.", 0)
FIELD(LABEL, label, SIZ, "DevSize", dev, 0, devsize, dev_size, "Size of underlying device in current units.", 0)
@@ -131,7 +169,13 @@ FIELD(LABEL, label, STR, "Min", dev, 0, devminor, pv_minor, "Device minor number
FIELD(LABEL, label, SIZ, "PMdaFree", type, 9, pvmdafree, pv_mda_free, "Free metadata area space on this device in current units.", 0)
FIELD(LABEL, label, SIZ, "PMdaSize", type, 9, pvmdasize, pv_mda_size, "Size of smallest metadata area on this device in current units.", 0)
FIELD(LABEL, label, NUM, "PExtVsn", type, 0, pvextvsn, pv_ext_vsn, "PV header extension version.", 0)
+/*
+ * End of LABEL type fields
+ */
+/*
+ * PVS type fields
+ */
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, pe_start, "Offset to the start of data on the underlying device.", 0)
FIELD(PVS, pv, SIZ, "PSize", id, 0, pvsize, pv_size, "Size of PV in current units.", 0)
FIELD(PVS, pv, SIZ, "PFree", id, 0, pvfree, pv_free, "Total amount of unallocated space in current units.", 0)
@@ -149,7 +193,13 @@ FIELD(PVS, pv, SIZ, "BA Start", ba_start, 0, size64, pv_ba_start, "Offset to the
FIELD(PVS, pv, SIZ, "BA Size", ba_size, 0, size64, pv_ba_size, "Size of PV Bootloader Area in current units.", 0)
FIELD(PVS, pv, BIN, "PInUse", id, 0, pvinuse, pv_in_use, "Set if PV is used.", 0)
FIELD(PVS, pv, BIN, "Duplicate", id, 0, pvduplicate, pv_duplicate, "Set if PV is an unchosen duplicate.", 0)
+/*
+ * End of PVS type fields
+ */
+/*
+ * VGS type fields
+ */
FIELD(VGS, vg, STR, "Fmt", cmd, 0, vgfmt, vg_fmt, "Type of metadata.", 0)
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, vg_uuid, "Unique identifier.", 0)
FIELD(VGS, vg, STR, "VG", name, 0, string, vg_name, "Name.", 0)
@@ -183,7 +233,13 @@ FIELD(VGS, vg, NUM, "#VMdaUse", cmd, 0, vgmdasused, vg_mda_used_count, "Number o
FIELD(VGS, vg, SIZ, "VMdaFree", cmd, 9, vgmdafree, vg_mda_free, "Free metadata area space for this VG in current units.", 0)
FIELD(VGS, vg, SIZ, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smallest metadata area for this VG in current units.", 0)
FIELD(VGS, vg, NUM, "#VMdaCps", cmd, 0, vgmdacopies, vg_mda_copies, "Target number of in use metadata areas in the VG.", 1)
+/*
+ * End of VGS type fields
+ */
+/*
+ * SEGS type fields
+ */
FIELD(SEGS, seg, STR, "Type", list, 0, segtype, segtype, "Type of LV segment.", 0)
FIELD(SEGS, seg, NUM, "#Str", area_count, 0, uint32, stripes, "Number of stripes or mirror legs.", 0)
FIELD(SEGS, seg, SIZ, "Stripe", stripe_size, 0, size32, stripe_size, "For stripes, amount of data placed on one device before switching to the next.", 0)
@@ -208,7 +264,16 @@ FIELD(SEGS, seg, STR_LIST, "Metadata Devs", list, 0, metadatadevices, metadata_d
FIELD(SEGS, seg, STR, "Monitor", list, 0, segmonitor, seg_monitor, "Dmeventd monitoring status of the segment.", 0)
FIELD(SEGS, seg, STR, "CachePolicy", list, 0, cache_policy, cache_policy, "The cache policy (cached segments only).", 0)
FIELD(SEGS, seg, STR_LIST, "CacheSettings", list, 0, cache_settings, cache_settings, "Cache settings/parameters (cached segments only).", 0)
+/*
+ * End of SEGS type fields
+ */
+/*
+ * PVSEGS type fields
+ */
FIELD(PVSEGS, pvseg, NUM, "Start", pe, 0, uint32, pvseg_start, "Physical Extent number of start of segment.", 0)
FIELD(PVSEGS, pvseg, NUM, "SSize", len, 0, uint32, pvseg_size, "Number of extents in segment.", 0)
+/*
+ * End of PVSEGS type fields
+ */
/* *INDENT-ON* */