dev-prajnoha-pv-ext-flag-used - dmsetup: Report timestamps of ioctls with -vvv.
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=559ca8bc6593a9...
Commit: 559ca8bc6593a9ef0b0b012ff0933b80f5d3e367
Parent: 2f334afb9836a792fd4e277d02ad6f317faa78ab
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Wed Aug 5 08:28:35 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Wed Aug 5 08:28:35 2015 +0100
dmsetup: Report timestamps of ioctls with -vvv.
If enabled, record timestamp immediately after the ioctl() returns.
---
WHATS_NEW_DM | 1 +
libdm/.exported_symbols.DM_1_02_104 | 2 +
libdm/ioctl/libdm-iface.c | 31 ++++++++++++++++-
libdm/ioctl/libdm-targets.h | 2 +
libdm/libdevmapper.h | 9 ++++-
libdm/libdm-common.c | 1 +
libdm/libdm-timestamp.c | 4 ++
tools/dmsetup.c | 63 ++++++++++++++++++++++++++---------
8 files changed, 93 insertions(+), 20 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 57cfce4..c0cdadc 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.104 -
=================================
+ Report timestamps of ioctls with dmsetup -vvv.
Recognize report field name variants without any underscores too.
Add dmsetup --interval and --count to repeat reports at specified intervals.
Add report interval and waiting functions to libdevmapper.
diff --git a/libdm/.exported_symbols.DM_1_02_104 b/libdm/.exported_symbols.DM_1_02_104
index 0039419..ec5c50b 100644
--- a/libdm/.exported_symbols.DM_1_02_104
+++ b/libdm/.exported_symbols.DM_1_02_104
@@ -4,6 +4,8 @@ dm_report_set_interval_ms
dm_report_set_interval_ns
dm_report_wait
dm_size_to_string
+dm_task_get_ioctl_timestamp
+dm_task_set_record_timestamp
dm_timestamp_alloc
dm_timestamp_compare
dm_timestamp_delta
diff --git a/libdm/ioctl/libdm-iface.c b/libdm/ioctl/libdm-iface.c
index e3b33b8..73af12b 100644
--- a/libdm/ioctl/libdm-iface.c
+++ b/libdm/ioctl/libdm-iface.c
@@ -68,6 +68,7 @@ static unsigned _dm_version = DM_VERSION_MAJOR;
static unsigned _dm_version_minor = 0;
static unsigned _dm_version_patchlevel = 0;
static int _log_suppress = 0;
+static struct dm_timestamp *_dm_ioctl_timestamp = NULL;
/*
* If the kernel dm driver only supports one major number
@@ -919,6 +920,24 @@ int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr)
return 1;
}
+int dm_task_set_record_timestamp(struct dm_task *dmt)
+{
+ if (!_dm_ioctl_timestamp)
+ _dm_ioctl_timestamp = dm_timestamp_alloc();
+
+ if (!_dm_ioctl_timestamp)
+ return_0;
+
+ dmt->record_timestamp = 1;
+
+ return 1;
+}
+
+struct dm_timestamp *dm_task_get_ioctl_timestamp(struct dm_task *dmt)
+{
+ return dmt->record_timestamp ? _dm_ioctl_timestamp : NULL;
+}
+
struct target *create_target(uint64_t start, uint64_t len, const char *type,
const char *params)
{
@@ -1716,6 +1735,7 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
{
struct dm_ioctl *dmi;
int ioctl_with_uevent;
+ int r;
dmt->ioctl_errno = 0;
@@ -1803,8 +1823,13 @@ static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command,
dmt->sector, _sanitise_message(dmt->message),
dmi->data_size, retry_repeat_count);
#ifdef DM_IOCTLS
- if (ioctl(_control_fd, command, dmi) < 0 &&
- dmt->expected_errno != errno) {
+ r = ioctl(_control_fd, command, dmi);
+
+ if (dmt->record_timestamp)
+ if (!dm_timestamp_get(_dm_ioctl_timestamp))
+ stack;
+
+ if (r < 0 && dmt->expected_errno != errno) {
dmt->ioctl_errno = errno;
if (dmt->ioctl_errno == ENXIO && ((dmt->type == DM_DEVICE_INFO) ||
(dmt->type == DM_DEVICE_MKNODES) ||
@@ -2049,6 +2074,8 @@ repeat_ioctl:
void dm_lib_release(void)
{
_close_control_fd();
+ dm_timestamp_destroy(_dm_ioctl_timestamp);
+ _dm_ioctl_timestamp = NULL;
update_devs();
}
diff --git a/libdm/ioctl/libdm-targets.h b/libdm/ioctl/libdm-targets.h
index 5545459..a3c1cb7 100644
--- a/libdm/ioctl/libdm-targets.h
+++ b/libdm/ioctl/libdm-targets.h
@@ -70,6 +70,8 @@ struct dm_task {
int expected_errno;
int ioctl_errno;
+ int record_timestamp;
+
char *uuid;
char *mangled_uuid;
};
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 4a1703e..ed9a79e 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -128,6 +128,7 @@ enum {
*/
struct dm_task;
+struct dm_timestamp;
struct dm_task *dm_task_create(int type);
void dm_task_destroy(struct dm_task *dmt);
@@ -229,6 +230,12 @@ int dm_task_retry_remove(struct dm_task *dmt);
int dm_task_deferred_remove(struct dm_task *dmt);
/*
+ * Record timestamp immediately after the ioctl returns.
+ */
+int dm_task_set_record_timestamp(struct dm_task *dmt);
+struct dm_timestamp *dm_task_get_ioctl_timestamp(struct dm_task *dmt);
+
+/*
* Enable checks for common mistakes such as issuing ioctls in an unsafe order.
*/
int dm_task_enable_checks(struct dm_task *dmt);
@@ -1669,8 +1676,6 @@ dm_percent_t dm_make_percent(uint64_t numerator, uint64_t denominator);
* timestamp handling
********************/
-struct dm_timestamp;
-
/*
* Create a dm_timestamp object to use with dm_timestamp_get.
*/
diff --git a/libdm/libdm-common.c b/libdm/libdm-common.c
index 0811db0..e1bd44e 100644
--- a/libdm/libdm-common.c
+++ b/libdm/libdm-common.c
@@ -277,6 +277,7 @@ struct dm_task *dm_task_create(int type)
dmt->query_inactive_table = 0;
dmt->new_uuid = 0;
dmt->secure_data = 0;
+ dmt->record_timestamp = 0;
return dmt;
}
diff --git a/libdm/libdm-timestamp.c b/libdm/libdm-timestamp.c
index d2bd7bf..7690ccb 100644
--- a/libdm/libdm-timestamp.c
+++ b/libdm/libdm-timestamp.c
@@ -67,6 +67,8 @@ int dm_timestamp_get(struct dm_timestamp *ts)
if (clock_gettime(CLOCK_MONOTONIC, &ts->t)) {
log_sys_error("clock_gettime", "get_timestamp");
+ ts->t.tv_sec = 0;
+ ts->t.tv_nsec = 0;
return 0;
}
@@ -113,6 +115,8 @@ int dm_timestamp_get(struct dm_timestamp *ts)
if (gettimeofday(&ts->t, NULL)) {
log_sys_error("gettimeofday", "get_timestamp");
+ ts->t.tv_sec = 0;
+ ts->t.tv_usec = 0;
return 0;
}
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index 25789dc..485301a 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -185,6 +185,7 @@ static struct dm_report *_report;
static report_type_t _report_type;
static dev_name_t _dev_name_type;
static uint32_t _count = 1; /* count of repeating reports */
+static struct dm_timestamp *_initial_timestamp = NULL;
#define NSEC_PER_USEC UINT64_C(1000)
#define NSEC_PER_MSEC UINT64_C(1000000)
@@ -309,6 +310,24 @@ struct dmsetup_report_obj {
struct dm_split_name *split_name;
};
+static int _task_run(struct dm_task *dmt)
+{
+ int r;
+ uint64_t delta;
+
+ if (_initial_timestamp)
+ dm_task_set_record_timestamp(dmt);
+
+ r = dm_task_run(dmt);
+
+ if (_initial_timestamp) {
+ delta = dm_timestamp_delta(dm_task_get_ioctl_timestamp(dmt), _initial_timestamp);
+ log_debug("Timestamp: %7" PRIu64 ".%09" PRIu64 " seconds", delta / NSEC_PER_SEC, delta % NSEC_PER_SEC);
+ }
+
+ return r;
+}
+
static struct dm_task *_get_deps_task(int major, int minor)
{
struct dm_task *dmt;
@@ -330,7 +349,7 @@ static struct dm_task *_get_deps_task(int major, int minor)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto err;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto err;
if (!dm_task_get_info(dmt, &info))
@@ -601,7 +620,7 @@ static int _load(CMD_ARGS)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
r = 1;
@@ -687,7 +706,7 @@ static int _create(CMD_ARGS)
udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
- !dm_task_run(dmt))
+ !_task_run(dmt))
goto out;
r = 1;
@@ -743,7 +762,7 @@ static int _do_rename(const char *name, const char *new_name, const char *new_uu
udev_flags |= DM_UDEV_DISABLE_LIBRARY_FALLBACK;
if (!dm_task_set_cookie(dmt, &cookie, udev_flags) ||
- !dm_task_run(dmt))
+ !_task_run(dmt))
goto out;
r = 1;
@@ -833,7 +852,7 @@ static int _message(CMD_ARGS)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
if ((response = dm_task_get_message_response(dmt))) {
@@ -882,7 +901,7 @@ static int _setgeometry(CMD_ARGS)
goto out;
/* run the task */
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
r = 1;
@@ -1322,7 +1341,7 @@ static int _simple(int task, const char *name, uint32_t event_nr, int display)
if (_switches[DEFERRED_ARG] && (task == DM_DEVICE_REMOVE || task == DM_DEVICE_REMOVE_ALL))
dm_task_deferred_remove(dmt);
- r = dm_task_run(dmt);
+ r = _task_run(dmt);
out:
if (!_udev_cookie && udev_wait_flag)
@@ -1383,7 +1402,7 @@ static int _process_all(const struct command *cmd, const char *subcommand, int a
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt)) {
+ if (!_task_run(dmt)) {
r = 0;
goto out;
}
@@ -1434,7 +1453,7 @@ static uint64_t _get_device_size(const char *name)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info) || !info.exists)
@@ -1483,7 +1502,7 @@ static int _error_device(CMD_ARGS)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto error;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto error;
if (!_simple(DM_DEVICE_RESUME, name, 0, 0)) {
@@ -1671,7 +1690,7 @@ static int _status(CMD_ARGS)
if (_switches[NOFLUSH_ARG] && !dm_task_no_flush(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info) || !info.exists)
@@ -1747,7 +1766,7 @@ static int _targets(CMD_ARGS)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
target = dm_task_get_versions(dmt);
@@ -1799,7 +1818,7 @@ static int _info(CMD_ARGS)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
r = _display_info(dmt);
@@ -1843,7 +1862,7 @@ static int _deps(CMD_ARGS)
if (_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info))
@@ -3001,7 +3020,7 @@ static int _mangle(CMD_ARGS)
if (!_switches[CHECKS_ARG] && !dm_task_enable_checks(dmt))
goto out;
- if (!dm_task_run(dmt))
+ if (!_task_run(dmt))
goto out;
if (!dm_task_get_info(dmt, &info) || !info.exists)
@@ -3808,8 +3827,17 @@ static int _process_switches(int *argcp, char ***argvp, const char *dev_dir)
_switches[VERSION_ARG]++;
}
- if (_switches[VERBOSE_ARG] > 1)
+ if (_switches[VERBOSE_ARG] > 1) {
dm_log_init_verbose(_switches[VERBOSE_ARG] - 1);
+ if (_switches[VERBOSE_ARG] > 2) {
+ if (!(_initial_timestamp = dm_timestamp_alloc()))
+ stack;
+ else if (!dm_timestamp_get(_initial_timestamp))
+ stack;
+ else
+ log_debug("Timestamp: 0.000000000 seconds");
+ }
+ }
if ((_switches[MAJOR_ARG] && !_switches[MINOR_ARG]) ||
(!_switches[MAJOR_ARG] && _switches[MINOR_ARG])) {
@@ -3960,5 +3988,8 @@ out:
dm_free(_table);
+ if (_initial_timestamp)
+ dm_timestamp_destroy(_initial_timestamp);
+
return r;
}
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - lockd: remove ignorelockingfailure checks
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=72f754e2bc571a...
Commit: 72f754e2bc571ada133057c5a248162dc349cf93
Parent: 439a579aa2aaf13c2e420b6e7888dbd71d7021c0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jul 31 15:46:51 2015 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Jul 31 15:51:50 2015 -0500
lockd: remove ignorelockingfailure checks
These code paths were effectively unused. The checks
had been added long ago without any real thought behind
what they should do or be used for.
---
lib/locking/lvmlockd.c | 11 +----------
1 files changed, 1 insertions(+), 10 deletions(-)
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
index 15abd54..4e85ec1 100644
--- a/lib/locking/lvmlockd.c
+++ b/lib/locking/lvmlockd.c
@@ -1475,11 +1475,7 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
log_warn("Duplicate sanlock global locks should be corrected");
if (result < 0) {
- if (ignorelockingfailure()) {
- log_debug("Ignore failed locking for global lock");
- lvmetad_validate_global_cache(cmd, 1);
- return 1;
- } else if (result == -EAGAIN) {
+ if (result == -EAGAIN) {
/*
* Most of the time, retries should avoid this case.
*/
@@ -1770,11 +1766,6 @@ out:
if ((lockd_flags & LD_RF_DUP_GL_LS) && strcmp(mode, "un"))
log_warn("Duplicate sanlock global lock in VG %s", vg_name);
- if (!ret && ignorelockingfailure()) {
- log_debug("Ignore failed locking for VG %s", vg_name);
- return 1;
- }
-
return ret;
}
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - dmsetup: Add --count and --interval to reports.
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=a161e29c59e016...
Commit: a161e29c59e01605401c9096f5ad5ace2ae03d9a
Parent: 72f754e2bc571ada133057c5a248162dc349cf93
Author: Bryn M. Reeves <breeves(a)redhat.com>
AuthorDate: Fri Jul 31 21:59:34 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Jul 31 21:59:34 2015 +0100
dmsetup: Add --count and --interval to reports.
For example, to monitor active devices every second you can now run
dmsetup info -c --count 0.
---
WHATS_NEW_DM | 2 +
libdm/.exported_symbols.DM_1_02_104 | 5 +++
libdm/libdevmapper.h | 44 ++++++++++++++++++++++++
libdm/libdm-report.c | 44 ++++++++++++++++++++++++
man/dmsetup.8.in | 18 ++++++++++
tools/dmsetup.c | 64 ++++++++++++++++++++++++++++++-----
6 files changed, 168 insertions(+), 9 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 81acfe9..2a006db 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,7 @@
Version 1.02.104 -
=================================
+ Add dmsetup --interval and --count to repeat reports at specified intervals.
+ Add report interval and waiting functions to libdevmapper.
Add dm_timestamp functions to libdevmapper.
Version 1.02.103 - 24th July 2015
diff --git a/libdm/.exported_symbols.DM_1_02_104 b/libdm/.exported_symbols.DM_1_02_104
index 9fafa48..815c689 100644
--- a/libdm/.exported_symbols.DM_1_02_104
+++ b/libdm/.exported_symbols.DM_1_02_104
@@ -1,3 +1,8 @@
+dm_report_set_interval_ms
+dm_report_set_interval_ns
+dm_report_get_interval_ms
+dm_report_get_interval_ns
+dm_report_wait
dm_size_to_string
dm_timestamp_alloc
dm_timestamp_compare
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 001d4c0..11ba0a3 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1928,6 +1928,50 @@ int dm_report_field_percent(struct dm_report *rh, struct dm_report_field *field,
void dm_report_field_set_value(struct dm_report_field *field, const void *value,
const void *sortvalue);
+/*
+ * Set an interval (in nanoseconds) for this dm_report object that will
+ * be used by any subsequent call to dm_report_wait_interval. This is
+ * only useful for repeating reports (e.g. statistics).
+ *
+ * The default value is zero: no interval.
+ */
+void dm_report_set_interval_ns(struct dm_report *rh, uint64_t interval_ns);
+
+/*
+ * Set an interval in milliseconds for this dm_report object that will
+ * be used by any subsequent call to dm_report_wait. This is only
+ * useful for repeating reports (e.g. statistics).
+ *
+ * The default value is zero: no interval.
+ */
+void dm_report_set_interval_ms(struct dm_report *rh, uint64_t interval_ms);
+
+/*
+ * Retrieve the configured interval of the dm_report handle rh in
+ * nanoseconds.
+ */
+uint64_t dm_report_get_interval_ns(struct dm_report *rh);
+
+/*
+ * Retrieve the configured interval of the dm_report handle rh in
+ * milliseconds.
+ */
+uint64_t dm_report_get_interval_ms(struct dm_report *rh);
+
+/*
+ * Suspend the calling thread until the current reporting interval
+ * expires. When this function returns the caller should obtain updated
+ * report data and call dm_report_object() and dm_report_output() as
+ * necessary in order to produce the new interval's reporting output.
+ *
+ * Delivery of a non-blocked signal to the thread carrying out the
+ * wait will cause the function to return prematurely with an error.
+ *
+ * Attempting to wait on a report that has no interval set is also
+ * treated as an error.
+ */
+int dm_report_wait(struct dm_report *rh);
+
/*************************
* config file parse/print
*************************/
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 34374bb..5ae994d 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -43,6 +43,8 @@ struct dm_report {
uint32_t flags;
const char *separator;
+ uint64_t interval_ns; /* Reporting interval in nanoseconds */
+
uint32_t keys_count;
/* Ordered list of fields needed for this report */
@@ -4210,3 +4212,45 @@ int dm_report_output(struct dm_report *rh)
else
return _output_as_columns(rh);
}
+
+#define NSEC_PER_USEC UINT64_C(1000)
+#define NSEC_PER_MSEC UINT64_C(1000000)
+#define NSEC_PER_SEC UINT64_C(1000000000)
+
+void dm_report_set_interval_ns(struct dm_report *rh, uint64_t interval_ns)
+{
+ rh->interval_ns = interval_ns;
+}
+
+void dm_report_set_interval_ms(struct dm_report *rh, uint64_t interval_ms)
+{
+ rh->interval_ns = interval_ms * NSEC_PER_MSEC;
+}
+
+uint64_t dm_report_get_interval_ns(struct dm_report *rh)
+{
+ return rh->interval_ns;
+}
+
+uint64_t dm_report_get_interval_ms(struct dm_report *rh)
+{
+ return (rh->interval_ns / NSEC_PER_MSEC);
+}
+
+int dm_report_wait(struct dm_report *rh)
+{
+ int r = 1;
+
+ if (!rh->interval_ns)
+ return_0;
+
+ if (usleep(rh->interval_ns / NSEC_PER_USEC)) {
+ if (errno == EINTR)
+ log_error("Report interval interrupted by signal.");
+ if (errno == EINVAL)
+ log_error("Report interval too short.");
+ r = 0;
+ }
+
+ return r;
+}
diff --git a/man/dmsetup.8.in b/man/dmsetup.8.in
index 57fbdf9..14e393a 100644
--- a/man/dmsetup.8.in
+++ b/man/dmsetup.8.in
@@ -42,6 +42,10 @@ dmsetup \(em low level logical volume management
.IR sort_fields ]
.RB [ \-S | \-\-select
.IR Selection ]
+.RB [ \-\-interval
+.IR seconds ]
+.RB [ \-\-count
+.IR count ]
.RI [ device_name ]
.RE
.br
@@ -187,6 +191,10 @@ In some cases these checks may slow down operations noticeably.
.BR \-c | \-C | \-\-columns
Display output in columns rather than as Field: Value lines.
.TP
+.B \-\-count \fIcount
+Specify the number of times to repeat a report. Set this to zero
+continue until interrupted. The default interval is one second.
+.TP
.BR \-h | \-\-help
Outputs a summary of the commands available, optionally including
the list of report fields (synonym with \fBhelp\fP command).
@@ -196,6 +204,12 @@ When returning any table information from the kernel report on the
inactive table instead of the live table.
Requires kernel driver version 4.16.0 or above.
.TP
+.B \-\-interval \fIseconds
+Specify the interval in seconds between successive iterations for
+repeating reports. If \-\-interval is specified but \-\-count is not,
+reports will continue to repeat until interrupted.
+The default interval is one second.
+.TP
.IR \fB\-\-manglename \ { none | hex | auto }
Mangle any character not on a whitelist using mangling_mode when
processing device-mapper device names and UUIDs. The names and UUIDs
@@ -355,6 +369,10 @@ Outputs some brief information about the device in the form:
.IR fields ]
.RB [ \-O | \-\-sort
.IR sort_fields ]
+.RB [ \-\-interval
+.IR seconds ]
+.RB [ \-\-count
+.IR count ]
.RI [ device_name ]
.br
Output you can customise.
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index f36119f..4b23d72 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -111,6 +111,7 @@ enum {
ADD_NODE_ON_RESUME_ARG,
CHECKS_ARG,
COLS_ARG,
+ COUNT_ARG,
DEFERRED_ARG,
SELECT_ARG,
EXEC_ARG,
@@ -118,6 +119,7 @@ enum {
GID_ARG,
HELP_ARG,
INACTIVE_ARG,
+ INTERVAL_ARG,
MANGLENAME_ARG,
MAJOR_ARG,
MINOR_ARG,
@@ -182,6 +184,11 @@ static struct dm_tree *_dtree;
static struct dm_report *_report;
static report_type_t _report_type;
static dev_name_t _dev_name_type;
+static uint32_t _count = 1; /* count of repeating reports */
+
+#define NSEC_PER_USEC UINT64_C(1000)
+#define NSEC_PER_MSEC UINT64_C(1000000)
+#define NSEC_PER_SEC UINT64_C(1000000000)
/*
* Commands
@@ -2845,6 +2852,7 @@ static int _report_init(const struct command *cmd)
int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
int quoted = 1, columns_as_rows = 0;
uint32_t flags = 0;
+ uint32_t interval;
size_t len = 0;
int r = 0;
@@ -2936,6 +2944,11 @@ static int _report_init(const struct command *cmd)
goto out;
}
+ /* Default interval is 1 second. */
+ interval = _switches[INTERVAL_ARG] ? _int_args[INTERVAL_ARG] : 1;
+
+ dm_report_set_interval_ns(_report, NSEC_PER_SEC * interval);
+
if (field_prefixes)
dm_report_set_output_field_name_prefix(_report, "dm_");
@@ -3110,6 +3123,7 @@ static void _dmsetup_usage(FILE *out)
" [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
" [-S|--select <selection>] [--nameprefixes] [--noheadings]\n"
+ " [--count <count>] [--interval <seconds>]\n"
" [--separator <separator>]\n\n");
for (i = 0; _dmsetup_commands[i].name; i++)
fprintf(out, "\t%s %s\n", _dmsetup_commands[i].name, _dmsetup_commands[i].help);
@@ -3523,6 +3537,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
{"readonly", 0, &ind, READ_ONLY},
{"checks", 0, &ind, CHECKS_ARG},
{"columns", 0, &ind, COLS_ARG},
+ {"count", 1, &ind, COUNT_ARG},
{"deferred", 0, &ind, DEFERRED_ARG},
{"select", 1, &ind, SELECT_ARG},
{"exec", 1, &ind, EXEC_ARG},
@@ -3530,6 +3545,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
{"gid", 1, &ind, GID_ARG},
{"help", 0, &ind, HELP_ARG},
{"inactive", 0, &ind, INACTIVE_ARG},
+ {"interval", 1, &ind, INTERVAL_ARG},
{"manglename", 1, &ind, MANGLENAME_ARG},
{"major", 1, &ind, MAJOR_ARG},
{"minor", 1, &ind, MINOR_ARG},
@@ -3674,6 +3690,14 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
_switches[ADD_NODE_ON_CREATE_ARG]++;
if (ind == CHECKS_ARG)
_switches[CHECKS_ARG]++;
+ if (ind == COUNT_ARG) {
+ _switches[COUNT_ARG]++;
+ _int_args[COUNT_ARG] = atoi(optarg);
+ if (_int_args[COUNT_ARG] < 0) {
+ log_error("Count must be zero or greater.");
+ return 0;
+ }
+ }
if (ind == UDEVCOOKIE_ARG) {
_switches[UDEVCOOKIE_ARG]++;
_udev_cookie = _get_cookie_value(optarg);
@@ -3709,6 +3733,14 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
}
if (ind == INACTIVE_ARG)
_switches[INACTIVE_ARG]++;
+ if (ind == INTERVAL_ARG) {
+ _switches[INTERVAL_ARG]++;
+ _int_args[INTERVAL_ARG] = atoi(optarg);
+ if (_int_args[INTERVAL_ARG] <= 0) {
+ log_error("Interval must be a positive integer.");
+ return 0;
+ }
+ }
if (ind == MANGLENAME_ARG) {
_switches[MANGLENAME_ARG]++;
if (!strcasecmp(optarg, "none"))
@@ -3880,13 +3912,18 @@ unknown:
goto out;
}
- if (_switches[COLS_ARG] && !_report_init(cmd))
+#ifdef UDEV_SYNC_SUPPORT
+ if (!_set_up_udev_support(dev_dir))
goto out;
+#endif
- #ifdef UDEV_SYNC_SUPPORT
- if (!_set_up_udev_support(dev_dir))
+ if (_switches[COLS_ARG] && !_report_init(cmd))
goto out;
- #endif
+
+ if (_switches[COUNT_ARG])
+ _count = _int_args[COUNT_ARG] ? : UINT32_MAX;
+ else if (_switches[INTERVAL_ARG])
+ _count = UINT32_MAX;
/*
* Extract subcommand?
@@ -3897,17 +3934,26 @@ unknown:
argc--, argv++;
}
- doit:
+doit:
multiple_devices = (cmd->repeatable_cmd && argc != 2 &&
(argc != 1 || (!_switches[UUID_ARG] && !_switches[MAJOR_ARG])));
- r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
+ do {
+ r = _perform_command_for_all_repeatable_args(cmd, subcommand, argc, argv, NULL, multiple_devices);
+
+ if (_report) {
+ dm_report_output(_report);
+
+ if (_count > 1) {
+ printf("\n");
+ dm_report_wait(_report);
+ }
+ }
+ } while (--_count);
out:
- if (_report) {
- dm_report_output(_report);
+ if (_report)
dm_report_free(_report);
- }
if (_dtree)
dm_tree_free(_dtree);
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - dmsetup: Fix dmsetup return code.
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=6a93206882cb62...
Commit: 6a93206882cb628a88dbd372d36dc8fc8cc5053a
Parent: 043fb32c4b67d1456a77ab7caf0d077f419fae88
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Fri Aug 14 00:09:40 2015 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Aug 14 00:09:40 2015 +0100
dmsetup: Fix dmsetup return code.
---
tools/dmsetup.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index b3820fe..c5be193 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -5832,7 +5832,7 @@ static int _do_report_wait(void)
int main(int argc, char **argv)
{
- int r = 1;
+ int ret = 1, r;
const char *dev_dir;
const struct command *cmd;
const char *subcommand = NULL;
@@ -5975,9 +5975,12 @@ doit:
}
if (!r)
- break;
+ goto_out;
} while (--_count);
+ /* Success */
+ ret = 0;
+
out:
if (_report)
dm_report_free(_report);
@@ -5990,5 +5993,5 @@ out:
if (_initial_timestamp)
dm_timestamp_destroy(_initial_timestamp);
- return r;
+ return ret;
}
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - cache: api update
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=f0c18fceb43d77...
Commit: f0c18fceb43d77b0a79685fc7b1c8bbe64df7e97
Parent: 22a1337a9ba1ebf73c3f0b27f621d9d8917bf6cf
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Aug 11 14:01:12 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Wed Aug 12 14:32:24 2015 +0200
cache: api update
Change logic and naming of some internal API functions.
cache_set_mode() and cache_set_policy() both take segment.
cache mode is now correctly 'masked-in'.
If the passed segment is 'cache' segment - it will automatically
try to find 'defaults' according to profiles if the are NOT
specified on command line or they are NOT already set for cache-pool.
These defaults are never set for cache-pool.
---
WHATS_NEW | 1 +
lib/cache_segtype/cache.c | 53 +++++++--------
lib/metadata/cache_manip.c | 129 ++++++++++++++++++++++++++++++--------
lib/metadata/lv.c | 2 +-
lib/metadata/lv_manip.c | 31 +++++++---
lib/metadata/metadata-exported.h | 9 ++-
lib/report/report.c | 2 +-
tools/lvchange.c | 2 +-
tools/lvconvert.c | 8 ++-
9 files changed, 166 insertions(+), 71 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index 7c35d13..7fcf49a 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.128 -
===================================
+ Enhance internal API cache_set_mode() and cache_set_policy().
Enhance toollib's get_cache_params().
Runtime detect presence of cache smq policy.
Add demo cache-mq and cache-smq profiles.
diff --git a/lib/cache_segtype/cache.c b/lib/cache_segtype/cache.c
index 93436a3..0526173 100644
--- a/lib/cache_segtype/cache.c
+++ b/lib/cache_segtype/cache.c
@@ -71,23 +71,15 @@ static int _cache_pool_text_import(struct lv_segment *seg,
if (dm_config_has_node(sn, "cache_mode")) {
if (!(str = dm_config_find_str(sn, "cache_mode", NULL)))
return SEG_LOG_ERROR("cache_mode must be a string in");
- if (!set_cache_pool_feature(&seg->feature_flags, str))
+ if (!cache_set_mode(seg, str))
return SEG_LOG_ERROR("Unknown cache_mode in");
- } else
- /* When missed in metadata, it's an old stuff - use writethrough */
- seg->feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
+ }
if (dm_config_has_node(sn, "policy")) {
if (!(str = dm_config_find_str(sn, "policy", NULL)))
return SEG_LOG_ERROR("policy must be a string in");
if (!(seg->policy_name = dm_pool_strdup(mem, str)))
return SEG_LOG_ERROR("Failed to duplicate policy in");
- } else {
- /* Cannot use 'just' default, so pick one */
- seg->policy_name = DEFAULT_CACHE_POLICY; /* FIXME make configurable */
- /* FIXME maybe here should be always 'mq' */
- log_warn("WARNING: cache_policy undefined, using default \"%s\" policy.",
- seg->policy_name);
}
/*
@@ -136,28 +128,33 @@ static int _cache_pool_text_export(const struct lv_segment *seg,
{
const char *cache_mode;
- if (!(cache_mode = get_cache_pool_cachemode_name(seg)))
- return_0;
-
- if (!seg->policy_name) {
- log_error(INTERNAL_ERROR "Policy name for %s is not defined.",
- display_lvname(seg->lv));
- return 0;
- }
-
outf(f, "data = \"%s\"", seg_lv(seg, 0)->name);
outf(f, "metadata = \"%s\"", seg->metadata_lv->name);
outf(f, "chunk_size = %" PRIu32, seg->chunk_size);
- outf(f, "cache_mode = \"%s\"", cache_mode);
- outf(f, "policy = \"%s\"", seg->policy_name);
- if (seg->policy_settings) {
- if (strcmp(seg->policy_settings->key, "policy_settings")) {
- log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
- seg->policy_settings->key);
- return 0;
+ /*
+ * Cache pool used by a cache LV holds data. Not ideal,
+ * but not worth to break backward compatibility, by shifting
+ * content to cache segment
+ */
+ if (cache_mode_is_set(seg)) {
+ if (!(cache_mode = get_cache_mode_name(seg)))
+ return_0;
+ outf(f, "cache_mode = \"%s\"", cache_mode);
+ }
+
+ if (seg->policy_name) {
+ outf(f, "policy = \"%s\"", seg->policy_name);
+
+ if (seg->policy_settings) {
+ if (strcmp(seg->policy_settings->key, "policy_settings")) {
+ log_error(INTERNAL_ERROR "Incorrect policy_settings tree, %s.",
+ seg->policy_settings->key);
+ return 0;
+ }
+ if (seg->policy_settings->child)
+ out_config_node(f, seg->policy_settings);
}
- out_config_node(f, seg->policy_settings);
}
return 1;
diff --git a/lib/metadata/cache_manip.c b/lib/metadata/cache_manip.c
index 91fcd3b..fbd0663 100644
--- a/lib/metadata/cache_manip.c
+++ b/lib/metadata/cache_manip.c
@@ -29,7 +29,17 @@
#define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
#define DM_MAX_HINT_WIDTH (4+16) /* bytes. FIXME Configurable? */
-const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
+int cache_mode_is_set(const struct lv_segment *seg)
+{
+ if (seg_is_cache(seg))
+ seg = first_seg(seg->pool_lv);
+
+ return (seg->feature_flags & (DM_CACHE_FEATURE_WRITEBACK |
+ DM_CACHE_FEATURE_WRITETHROUGH |
+ DM_CACHE_FEATURE_PASSTHROUGH)) ? 1 : 0;
+}
+
+const char *get_cache_mode_name(const struct lv_segment *seg)
{
if (seg->feature_flags & DM_CACHE_FEATURE_WRITEBACK)
return "writeback";
@@ -46,19 +56,48 @@ const char *get_cache_pool_cachemode_name(const struct lv_segment *seg)
return NULL;
}
-int set_cache_pool_feature(uint64_t *feature_flags, const char *str)
+int cache_set_mode(struct lv_segment *seg, const char *str)
{
+ struct cmd_context *cmd = seg->lv->vg->cmd;
+ int id;
+ uint64_t mode;
+
+ if (!str && !seg_is_cache(seg))
+ return 1; /* Defaults only for cache */
+
+ if (seg_is_cache(seg))
+ seg = first_seg(seg->pool_lv);
+
+ if (!str) {
+ if (cache_mode_is_set(seg))
+ return 1; /* Default already set in cache pool */
+
+ id = allocation_cache_mode_CFG;
+
+ /* If present, check backward compatible settings */
+ if (!find_config_node(cmd, cmd->cft, id) &&
+ find_config_node(cmd, cmd->cft, allocation_cache_pool_cachemode_CFG))
+ id = allocation_cache_pool_cachemode_CFG;
+
+ str = find_config_tree_str(cmd, id, NULL);
+ }
+
if (!strcmp(str, "writeback"))
- *feature_flags |= DM_CACHE_FEATURE_WRITEBACK;
+ mode = DM_CACHE_FEATURE_WRITEBACK;
else if (!strcmp(str, "writethrough"))
- *feature_flags |= DM_CACHE_FEATURE_WRITETHROUGH;
- else if (!strcmp(str, "passhrough"))
- *feature_flags |= DM_CACHE_FEATURE_PASSTHROUGH;
+ mode = DM_CACHE_FEATURE_WRITETHROUGH;
+ else if (!strcmp(str, "passthrough"))
+ mode = DM_CACHE_FEATURE_PASSTHROUGH;
else {
- log_error("Cache pool feature \"%s\" is unknown.", str);
+ log_error("Cannot set unknown cache mode \"%s\".", str);
return 0;
}
+ seg->feature_flags &= ~(DM_CACHE_FEATURE_WRITEBACK |
+ DM_CACHE_FEATURE_WRITETHROUGH |
+ DM_CACHE_FEATURE_PASSTHROUGH);
+ seg->feature_flags |= mode;
+
return 1;
}
@@ -395,36 +434,72 @@ int lv_is_cache_origin(const struct logical_volume *lv)
return seg && lv_is_cache(seg->lv) && !lv_is_pending_delete(seg->lv) && (seg_lv(seg, 0) == lv);
}
-int lv_cache_set_policy(struct logical_volume *lv, const char *name,
- const struct dm_config_tree *settings)
+int cache_set_policy(struct lv_segment *seg, const char *name,
+ const struct dm_config_tree *settings)
{
struct dm_config_node *cn;
+ const struct dm_config_node *cns;
struct dm_config_tree *old = NULL, *new = NULL, *tmp = NULL;
int r = 0;
- struct lv_segment *seg = first_seg(lv);
+ const int passed_seg_is_cache = seg_is_cache(seg);
- if (lv_is_cache(lv))
+ if (passed_seg_is_cache)
seg = first_seg(seg->pool_lv);
- if (seg->policy_settings) {
- if (!(old = dm_config_create()))
- goto_out;
- if (!(new = dm_config_create()))
- goto_out;
- new->root = settings->root;
- old->root = seg->policy_settings;
- new->cascade = old;
- if (!(tmp = dm_config_flatten(new)))
+ if (name) {
+ if (!(seg->policy_name = dm_pool_strdup(seg->lv->vg->vgmem, name))) {
+ log_error("Failed to duplicate policy name.");
+ return 0;
+ }
+ } else if (!seg->policy_name && passed_seg_is_cache)
+ seg->policy_name = find_config_tree_str(seg->lv->vg->cmd, allocation_cache_policy_CFG, NULL);
+
+ if (settings) {
+ if (!seg->policy_name) {
+ log_error(INTERNAL_ERROR "Can't set policy settings without policy name.");
+ return 0;
+ }
+
+ if (seg->policy_settings) {
+ if (!(old = dm_config_create()))
+ goto_out;
+ if (!(new = dm_config_create()))
+ goto_out;
+ new->root = settings->root;
+ old->root = seg->policy_settings;
+ new->cascade = old;
+ if (!(tmp = dm_config_flatten(new)))
+ goto_out;
+ }
+
+ if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
+ !(seg->policy_settings = dm_config_clone_node_with_mem(seg->lv->vg->vgmem, cn, 0)))
goto_out;
- }
+ } else if (passed_seg_is_cache && /* Look for command's profile cache_policies */
+ (cns = find_config_tree_node(seg->lv->vg->cmd, allocation_cache_settings_CFG_SECTION, NULL))) {
+ /* Try to find our section for given policy */
+ for (cn = cns->child; cn; cn = cn->sib) {
+ /* Only matching section names */
+ if (cn->v || strcmp(cn->key, seg->policy_name) != 0)
+ continue;
+
+ if (!cn->child)
+ break;
+
+ if (!(new = dm_config_create()))
+ goto_out;
- if ((cn = dm_config_find_node((tmp) ? tmp->root : settings->root, "policy_settings")) &&
- !(seg->policy_settings = dm_config_clone_node_with_mem(lv->vg->vgmem, cn, 0)))
- goto_out;
+ if (!(new->root = dm_config_clone_node_with_mem(new->mem,
+ cn->child, 1)))
+ goto_out;
- if (name && !(seg->policy_name = dm_pool_strdup(lv->vg->vgmem, name))) {
- log_error("Failed to duplicate policy name.");
- goto out;
+ if (!(seg->policy_settings = dm_config_create_node(new, "policy_settings")))
+ goto_out;
+
+ seg->policy_settings->child = new->root;
+
+ break; /* Only first match counts */
+ }
}
restart: /* remove any 'default" nodes */
diff --git a/lib/metadata/lv.c b/lib/metadata/lv.c
index df784c1..c775077 100644
--- a/lib/metadata/lv.c
+++ b/lib/metadata/lv.c
@@ -131,7 +131,7 @@ char *lvseg_discards_dup(struct dm_pool *mem, const struct lv_segment *seg)
char *lvseg_cachemode_dup(struct dm_pool *mem, const struct lv_segment *seg)
{
- const char *name = get_cache_pool_cachemode_name(seg);
+ const char *name = get_cache_mode_name(seg);
if (!name)
return_NULL;
diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c
index b22773e..f13df1b 100644
--- a/lib/metadata/lv_manip.c
+++ b/lib/metadata/lv_manip.c
@@ -7264,17 +7264,26 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
memlock_unlock(vg->cmd);
if (seg_is_cache_pool(lp) || seg_is_cache(lp)) {
- pool_lv = pool_lv ? : lv;
- if (!lv_cache_set_policy(pool_lv, lp->policy_name, lp->policy_settings))
- return_NULL; /* revert? */
- first_seg(pool_lv)->chunk_size = lp->chunk_size;
- first_seg(pool_lv)->feature_flags = lp->feature_flags;
- /* TODO: some calc_policy solution for cache ? */
- if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
- THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
+ if (!cache_set_mode(first_seg(lv), lp->cache_mode)) {
+ stack;
+ goto revert_new_lv;
+ }
+
+ if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings)) {
stack;
goto revert_new_lv;
}
+
+ pool_lv = pool_lv ? : lv;
+ if (lp->chunk_size) {
+ first_seg(pool_lv)->chunk_size = lp->chunk_size;
+ /* TODO: some calc_policy solution for cache ? */
+ if (!recalculate_pool_chunk_size_with_dev_hints(pool_lv, lp->passed_args,
+ THIN_CHUNK_SIZE_CALC_METHOD_GENERIC)) {
+ stack;
+ goto revert_new_lv;
+ }
+ }
} else if (seg_is_raid(lp)) {
first_seg(lv)->min_recovery_rate = lp->min_recovery_rate;
first_seg(lv)->max_recovery_rate = lp->max_recovery_rate;
@@ -7478,6 +7487,12 @@ static struct logical_volume *_lv_create_an_lv(struct volume_group *vg,
}
lv = tmp_lv;
+ if (!cache_set_mode(first_seg(lv), lp->cache_mode))
+ return_NULL; /* revert? */
+
+ if (!cache_set_policy(first_seg(lv), lp->policy_name, lp->policy_settings))
+ return_NULL; /* revert? */
+
if (!lv_update_and_reload(lv)) {
/* FIXME Do a better revert */
log_error("Aborting. Manual intervention required.");
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 03a866a..fff24f0 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -1153,8 +1153,11 @@ struct lv_status_cache {
dm_percent_t dirty_usage;
};
-const char *get_cache_pool_cachemode_name(const struct lv_segment *seg);
-int set_cache_pool_feature(uint64_t *feature_flags, const char *str);
+const char *get_cache_mode_name(const struct lv_segment *cache_seg);
+int cache_mode_is_set(const struct lv_segment *seg);
+int cache_set_mode(struct lv_segment *cache_seg, const char *str);
+int cache_set_policy(struct lv_segment *cache_seg, const char *name,
+ const struct dm_config_tree *settings);
int update_cache_pool_params(const struct segment_type *segtype,
struct volume_group *vg, unsigned attr,
int passed_args, uint32_t pool_data_extents,
@@ -1165,8 +1168,6 @@ int validate_lv_cache_create_origin(const struct logical_volume *origin_lv);
struct logical_volume *lv_cache_create(struct logical_volume *pool,
struct logical_volume *origin);
int lv_cache_remove(struct logical_volume *cache_lv);
-int lv_cache_set_policy(struct logical_volume *cache_lv, const char *name,
- const struct dm_config_tree *settings);
int wipe_cache_pool(struct logical_volume *cache_pool_lv);
/* -- metadata/cache_manip.c */
diff --git a/lib/report/report.c b/lib/report/report.c
index c2ab991..a17af32 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -2079,7 +2079,7 @@ static int _cachemode_disp(struct dm_report *rh, struct dm_pool *mem,
seg = first_seg(seg->pool_lv);
if (seg_is_cache_pool(seg)) {
- if (!(cachemode_str = get_cache_pool_cachemode_name(seg)))
+ if (!(cachemode_str = get_cache_mode_name(seg)))
return_0;
return dm_report_field_string(rh, field, &cachemode_str);
diff --git a/tools/lvchange.c b/tools/lvchange.c
index a6ad343..e24c07a 100644
--- a/tools/lvchange.c
+++ b/tools/lvchange.c
@@ -692,7 +692,7 @@ static int _lvchange_cachepolicy(struct cmd_context *cmd, struct logical_volume
if (!get_cache_params(cmd, NULL, &name, &settings))
goto_out;
- if (!lv_cache_set_policy(lv, name, settings))
+ if (!cache_set_policy(first_seg(lv), name, settings))
goto_out;
if (!lv_update_and_reload(lv))
goto_out;
diff --git a/tools/lvconvert.c b/tools/lvconvert.c
index d48af62..040272a 100644
--- a/tools/lvconvert.c
+++ b/tools/lvconvert.c
@@ -3070,7 +3070,7 @@ mda_write:
seg->zero_new_blocks = lp->zero ? 1 : 0;
if ((lp->policy_name || lp->policy_settings) &&
- !lv_cache_set_policy(seg->lv, lp->policy_name, lp->policy_settings))
+ !cache_set_policy(seg, lp->policy_name, lp->policy_settings))
return_0;
/* Rename deactivated metadata LV to have _tmeta suffix */
@@ -3178,6 +3178,12 @@ static int _lvconvert_cache(struct cmd_context *cmd,
if (!(cache_lv = lv_cache_create(pool_lv, origin_lv)))
return_0;
+ if (!cache_set_mode(first_seg(cache_lv), lp->cache_mode))
+ return_0;
+
+ if (!cache_set_policy(first_seg(cache_lv), lp->policy_name, lp->policy_settings))
+ return_0;
+
if (!lv_update_and_reload(cache_lv))
return_0;
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - lvmlockd: handle loss of sanlock lease storage
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=fd1782b5fc41f3...
Commit: fd1782b5fc41f3b9aceba6c27ba23098b0b4b6e2
Parent: 559ca8bc6593a9ef0b0b012ff0933b80f5d3e367
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jul 31 13:38:38 2015 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Wed Aug 5 10:21:45 2015 -0500
lvmlockd: handle loss of sanlock lease storage
This adds the infrastructure, code paths, error reporting,
etc. to handle storage errors, or storage loss, under the
sanlock leases in a VG that is being used. The loss of
storage means sanlock cannot renew its leases, which means
that the host needs to stop using the shared VG before its
leases expire.
This still requires manually shutting down a VG that has
lost lease storage, e.g. unmounting file systems,
deactivating LVs in the VG. The next step is to
automatically use a command like blkdeactivate to do that.
---
daemons/lvmlockd/lvmlockctl.c | 128 +++++++++++++++++++++--
daemons/lvmlockd/lvmlockd-client.h | 2 +
daemons/lvmlockd/lvmlockd-core.c | 99 ++++++++++++++++--
daemons/lvmlockd/lvmlockd-internal.h | 4 +
daemons/lvmlockd/lvmlockd-sanlock.c | 189 ++++++++++++++++++++++++----------
lib/locking/lvmlockd.c | 75 +++++++++++---
lib/locking/lvmlockd.h | 3 +-
7 files changed, 415 insertions(+), 85 deletions(-)
diff --git a/daemons/lvmlockd/lvmlockctl.c b/daemons/lvmlockd/lvmlockctl.c
index cb67296..148077e 100644
--- a/daemons/lvmlockd/lvmlockctl.c
+++ b/daemons/lvmlockd/lvmlockctl.c
@@ -17,6 +17,7 @@
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
+#include <syslog.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
@@ -26,14 +27,16 @@ static int info = 0;
static int dump = 0;
static int wait_opt = 0;
static int force_opt = 0;
+static int kill_vg = 0;
+static int drop_vg = 0;
static int gl_enable = 0;
static int gl_disable = 0;
static int stop_lockspaces = 0;
-static char *able_vg_name = NULL;
+static char *arg_vg_name = NULL;
#define DUMP_SOCKET_NAME "lvmlockd-dump.sock"
#define DUMP_BUF_SIZE (1024 * 1024)
-static char dump_buf[DUMP_BUF_SIZE];
+static char dump_buf[DUMP_BUF_SIZE+1];
static int dump_len;
static struct sockaddr_un dump_addr;
static socklen_t dump_addrlen;
@@ -446,9 +449,9 @@ static int do_able(const char *req_name)
int rv;
reply = _lvmlockd_send(req_name,
- "cmd = %s", "lvmlock",
+ "cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
- "vg_name = %s", able_vg_name,
+ "vg_name = %s", arg_vg_name,
NULL);
if (!_lvmlockd_result(reply, &result)) {
@@ -477,7 +480,7 @@ static int do_stop_lockspaces(void)
strcat(opts, "force ");
reply = _lvmlockd_send("stop_all",
- "cmd = %s", "lvmlock",
+ "cmd = %s", "lvmlockctl",
"pid = %d", getpid(),
"opts = %s", opts[0] ? opts : "none",
NULL);
@@ -493,6 +496,87 @@ static int do_stop_lockspaces(void)
return rv;
}
+static int do_kill(void)
+{
+ daemon_reply reply;
+ int result;
+ int rv;
+
+ syslog(LOG_EMERG, "Lost access to sanlock lease storage in VG %s.", arg_vg_name);
+ /* These two lines explain the manual alternative to the FIXME below. */
+ syslog(LOG_EMERG, "Immediately deactivate LVs in VG %s.", arg_vg_name);
+ syslog(LOG_EMERG, "Once VG is unused, run lvmlockctl --drop %s.", arg_vg_name);
+
+ /*
+ * It may not be strictly necessary to notify lvmlockd of the kill, but
+ * lvmlockd can use this information to avoid attempting any new lock
+ * requests in the VG (which would fail anyway), and can return an
+ * error indicating that the VG has been killed.
+ */
+
+ reply = _lvmlockd_send("kill_vg",
+ "cmd = %s", "lvmlockctl",
+ "pid = %d", getpid(),
+ "vg_name = %s", arg_vg_name,
+ NULL);
+
+ if (!_lvmlockd_result(reply, &result)) {
+ log_error("lvmlockd result %d", result);
+ rv = result;
+ } else {
+ rv = 0;
+ }
+
+ daemon_reply_destroy(reply);
+
+ /*
+ * FIXME: here is where we should implement a strong form of
+ * blkdeactivate, and if it completes successfully, automatically call
+ * do_drop() afterward. (The drop step may not always be necessary
+ * if the lvm commands run while shutting things down release all the
+ * leases.)
+ *
+ * run_strong_blkdeactivate();
+ * do_drop();
+ */
+
+ return rv;
+}
+
+static int do_drop(void)
+{
+ daemon_reply reply;
+ int result;
+ int rv;
+
+ syslog(LOG_WARNING, "Dropping locks for VG %s.", arg_vg_name);
+
+ /*
+ * Check for misuse by looking for any active LVs in the VG
+ * and refusing this operation if found? One possible way
+ * to kill LVs (e.g. if fs cannot be unmounted) is to suspend
+ * them, or replace them with the error target. In that
+ * case the LV will still appear to be active, but it is
+ * safe to release the lock.
+ */
+
+ reply = _lvmlockd_send("drop_vg",
+ "cmd = %s", "lvmlockctl",
+ "pid = %d", getpid(),
+ "vg_name = %s", arg_vg_name,
+ NULL);
+
+ if (!_lvmlockd_result(reply, &result)) {
+ log_error("lvmlockd result %d", result);
+ rv = result;
+ } else {
+ rv = 0;
+ }
+
+ daemon_reply_destroy(reply);
+ return rv;
+}
+
static void print_usage(void)
{
printf("lvmlockctl options\n");
@@ -509,12 +593,16 @@ static void print_usage(void)
printf(" Wait option for other commands.\n");
printf("--force | -f 0|1>\n");
printf(" Force option for other commands.\n");
- printf("--stop-lockspaces | -S\n");
- printf(" Stop all lockspaces.\n");
+ printf("--kill | -k <vg_name>\n");
+ printf(" Kill access to the vg when sanlock cannot renew lease.\n");
+ printf("--drop | -r <vg_name>\n");
+ printf(" Clear locks for the vg after it has been killed and is no longer used.\n");
printf("--gl-enable <vg_name>\n");
printf(" Tell lvmlockd to enable the global lock in a sanlock vg.\n");
printf("--gl-disable <vg_name>\n");
printf(" Tell lvmlockd to disable the global lock in a sanlock vg.\n");
+ printf("--stop-lockspaces | -S\n");
+ printf(" Stop all lockspaces.\n");
}
static int read_options(int argc, char *argv[])
@@ -529,6 +617,8 @@ static int read_options(int argc, char *argv[])
{"dump", no_argument, 0, 'd' },
{"wait", required_argument, 0, 'w' },
{"force", required_argument, 0, 'f' },
+ {"kill", required_argument, 0, 'k' },
+ {"drop", required_argument, 0, 'r' },
{"gl-enable", required_argument, 0, 'E' },
{"gl-disable", required_argument, 0, 'D' },
{"stop-lockspaces", no_argument, 0, 'S' },
@@ -541,7 +631,7 @@ static int read_options(int argc, char *argv[])
}
while (1) {
- c = getopt_long(argc, argv, "hqidE:D:w:S", long_options, &option_index);
+ c = getopt_long(argc, argv, "hqidE:D:w:k:r:S", long_options, &option_index);
if (c == -1)
break;
@@ -565,13 +655,21 @@ static int read_options(int argc, char *argv[])
case 'w':
wait_opt = atoi(optarg);
break;
+ case 'k':
+ kill_vg = 1;
+ arg_vg_name = strdup(optarg);
+ break;
+ case 'r':
+ drop_vg = 1;
+ arg_vg_name = strdup(optarg);
+ break;
case 'E':
gl_enable = 1;
- able_vg_name = strdup(optarg);
+ arg_vg_name = strdup(optarg);
break;
case 'D':
gl_disable = 1;
- able_vg_name = strdup(optarg);
+ arg_vg_name = strdup(optarg);
break;
case 'S':
stop_lockspaces = 1;
@@ -616,6 +714,16 @@ int main(int argc, char **argv)
goto out;
}
+ if (kill_vg) {
+ rv = do_kill();
+ goto out;
+ }
+
+ if (drop_vg) {
+ rv = do_drop();
+ goto out;
+ }
+
if (gl_enable) {
rv = do_able("enable_gl");
goto out;
diff --git a/daemons/lvmlockd/lvmlockd-client.h b/daemons/lvmlockd/lvmlockd-client.h
index e1d69d2..0a1424f 100644
--- a/daemons/lvmlockd/lvmlockd-client.h
+++ b/daemons/lvmlockd/lvmlockd-client.h
@@ -45,5 +45,7 @@ static inline void lvmlockd_close(daemon_handle h)
#define EMANAGER 214
#define EPREPARE 215
#define ELOCKD 216
+#define EVGKILLED 217 /* sanlock lost access to leases and VG is killed. */
+#define ELOCKIO 218 /* sanlock io errors during lock op, may be transient. */
#endif /* _LVM_LVMLOCKD_CLIENT_H */
diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c
index 266339d..7493d11 100644
--- a/daemons/lvmlockd/lvmlockd-core.c
+++ b/daemons/lvmlockd/lvmlockd-core.c
@@ -735,6 +735,10 @@ static const char *op_str(int x)
return "find_free_lock";
case LD_OP_FORGET_VG_NAME:
return "forget_vg_name";
+ case LD_OP_KILL_VG:
+ return "kill_vg";
+ case LD_OP_DROP_VG:
+ return "drop_vg";
default:
return "op_unknown";
};
@@ -786,6 +790,7 @@ int version_from_args(char *args, unsigned int *major, unsigned int *minor, unsi
char *major_str, *minor_str, *patch_str;
char *n, *d1, *d2;
+ memset(version, 0, sizeof(version));
strncpy(version, args, MAX_ARGS);
version[MAX_ARGS] = '\0';
@@ -1828,7 +1833,7 @@ static int for_each_lock(struct lockspace *ls, int locks_do)
return 0;
}
-static int clear_locks(struct lockspace *ls, int free_vg)
+static int clear_locks(struct lockspace *ls, int free_vg, int drop_vg)
{
struct resource *r, *r_safe;
struct lock *lk, *lk_safe;
@@ -1847,10 +1852,10 @@ static int clear_locks(struct lockspace *ls, int free_vg)
/*
* Stopping a lockspace shouldn't happen with LV locks
* still held, but it will be stopped with GL and VG
- * locks held.
+ * locks held. The drop_vg case may see LV locks.
*/
- if (lk->flags & LD_LF_PERSISTENT)
+ if (lk->flags & LD_LF_PERSISTENT && !drop_vg)
log_error("S %s R %s clear lock persistent", ls->name, r->name);
else
log_debug("S %s R %s clear lock mode %s client %d", ls->name, r->name, mode_str(lk->mode), lk->client_id);
@@ -1884,8 +1889,8 @@ static int clear_locks(struct lockspace *ls, int free_vg)
rv = lm_unlock(ls, r, NULL, r_version, free_vg ? LMUF_FREE_VG : 0);
if (rv < 0) {
/* should never happen */
- log_error("S %s R %s clear_locks free %d lm unlock error %d",
- ls->name, r->name, free_vg, rv);
+ log_error("S %s R %s clear_locks free %d drop %d lm unlock error %d",
+ ls->name, r->name, free_vg, drop_vg, rv);
}
list_for_each_entry_safe(act, act_safe, &r->actions, list) {
@@ -1991,6 +1996,28 @@ static int other_sanlock_vgs_exist(struct lockspace *ls_rem)
}
/*
+ * LOCK is the main thing we're interested in; the others are unlikely.
+ */
+
+static int process_op_during_kill(struct action *act)
+{
+ if (act->op == LD_OP_LOCK && act->mode == LD_LK_UN)
+ return 1;
+
+ switch (act->op) {
+ case LD_OP_LOCK:
+ case LD_OP_ENABLE:
+ case LD_OP_DISABLE:
+ case LD_OP_UPDATE:
+ case LD_OP_RENAME_BEFORE:
+ case LD_OP_RENAME_FINAL:
+ case LD_OP_FIND_FREE_LOCK:
+ return 0;
+ };
+ return 1;
+}
+
+/*
* Process actions queued for this lockspace by
* client_recv_action / add_lock_action.
*
@@ -2010,6 +2037,7 @@ static void *lockspace_thread_main(void *arg_in)
struct list_head tmp_act;
struct list_head act_close;
int free_vg = 0;
+ int drop_vg = 0;
int error = 0;
int adopt_flag = 0;
int wait_flag = 0;
@@ -2114,7 +2142,43 @@ static void *lockspace_thread_main(void *arg_in)
act = list_first_entry(&ls->actions, struct action, list);
+ if (act->op == LD_OP_KILL_VG && act->rt == LD_RT_VG) {
+ /* Continue processing until DROP_VG arrives. */
+ log_debug("S %s kill_vg", ls->name);
+ ls->kill_vg = 1;
+ list_del(&act->list);
+ act->result = 0;
+ add_client_result(act);
+ continue;
+ }
+
+ if (ls->kill_vg && !process_op_during_kill(act)) {
+ log_debug("S %s disallow op %s after kill_vg", ls->name, op_str(act->op));
+ list_del(&act->list);
+ act->result = -EVGKILLED;
+ add_client_result(act);
+ continue;
+ }
+
+ if (act->op == LD_OP_DROP_VG && act->rt == LD_RT_VG) {
+ /*
+ * If leases are released after i/o errors begin
+ * but before lvmlockctl --kill, then the VG is not
+ * killed, but drop is still needed to clean up the
+ * VG, so in that case there would be a drop op without
+ * a preceding kill op.
+ */
+ if (!ls->kill_vg)
+ log_debug("S %s received drop without kill", ls->name);
+ log_debug("S %s drop_vg", ls->name);
+ ls->thread_work = 0;
+ ls->thread_stop = 1;
+ drop_vg = 1;
+ break;
+ }
+
if (act->op == LD_OP_STOP) {
+ /* thread_stop is already set */
ls->thread_work = 0;
break;
}
@@ -2238,6 +2302,9 @@ out_rem:
* allowed in emergency/force situations, otherwise it's
* obviously dangerous, since the lock holders are still
* operating under the assumption that they hold the lock.
+ * drop_vg drops all existing locks, but should only
+ * happen when the VG access has been forcibly and
+ * succesfully terminated.
*
* For vgremove of a sanlock vg, the vg lock will be held,
* and possibly the gl lock if this vg holds the gl.
@@ -2246,7 +2313,7 @@ out_rem:
log_debug("S %s clearing locks", ls->name);
- rv = clear_locks(ls, free_vg);
+ rv = clear_locks(ls, free_vg, drop_vg);
/*
* Tell any other hosts in the lockspace to leave it
@@ -2284,6 +2351,8 @@ out_act:
act->result = 0;
} else if (act->op == LD_OP_STOP)
act->result = 0;
+ else if (act->op == LD_OP_DROP_VG)
+ act->result = 0;
else if (act->op == LD_OP_RENAME_BEFORE)
act->result = 0;
else
@@ -2317,6 +2386,7 @@ out_act:
pthread_mutex_lock(&lockspaces_mutex);
ls->thread_done = 1;
ls->free_vg = free_vg;
+ ls->drop_vg = drop_vg;
pthread_mutex_unlock(&lockspaces_mutex);
/*
@@ -3539,7 +3609,6 @@ static int add_lock_action(struct action *act)
if (ls_create_fail)
act->flags |= LD_AF_ADD_LS_ERROR;
return -ENOLS;
-
} else {
log_debug("lockspace not found %s", ls_name);
return -ENOLS;
@@ -3714,6 +3783,16 @@ static int str_to_op_rt(const char *req_name, int *op, int *rt)
*rt = LD_RT_VG;
return 0;
}
+ if (!strcmp(req_name, "kill_vg")) {
+ *op = LD_OP_KILL_VG;
+ *rt = LD_RT_VG;
+ return 0;
+ }
+ if (!strcmp(req_name, "drop_vg")) {
+ *op = LD_OP_DROP_VG;
+ *rt = LD_RT_VG;
+ return 0;
+ }
out:
return -1;
}
@@ -3864,6 +3943,8 @@ static int print_lockspace(struct lockspace *ls, const char *prefix, int pos, in
"thread_work=%d "
"thread_stop=%d "
"thread_done=%d "
+ "kill_vg=%d "
+ "drop_vg=%d "
"sanlock_gl_enabled=%d\n",
prefix,
ls->name,
@@ -3878,6 +3959,8 @@ static int print_lockspace(struct lockspace *ls, const char *prefix, int pos, in
ls->thread_work ? 1 : 0,
ls->thread_stop ? 1 : 0,
ls->thread_done ? 1 : 0,
+ ls->kill_vg,
+ ls->drop_vg,
ls->sanlock_gl_enabled ? 1 : 0);
}
@@ -4273,6 +4356,8 @@ static void client_recv_action(struct client *cl)
case LD_OP_FREE:
case LD_OP_RENAME_BEFORE:
case LD_OP_FIND_FREE_LOCK:
+ case LD_OP_KILL_VG:
+ case LD_OP_DROP_VG:
rv = add_lock_action(act);
break;
case LD_OP_FORGET_VG_NAME:
diff --git a/daemons/lvmlockd/lvmlockd-internal.h b/daemons/lvmlockd/lvmlockd-internal.h
index 78ae88d..a1f74a7 100644
--- a/daemons/lvmlockd/lvmlockd-internal.h
+++ b/daemons/lvmlockd/lvmlockd-internal.h
@@ -51,6 +51,8 @@ enum {
LD_OP_RUNNING_LM,
LD_OP_FIND_FREE_LOCK,
LD_OP_FORGET_VG_NAME,
+ LD_OP_KILL_VG,
+ LD_OP_DROP_VG,
};
/* resource types */
@@ -184,6 +186,8 @@ struct lockspace {
unsigned int sanlock_gl_enabled: 1;
unsigned int sanlock_gl_dup: 1;
unsigned int free_vg: 1;
+ unsigned int kill_vg: 1;
+ unsigned int drop_vg: 1;
struct list_head actions; /* new client actions */
struct list_head resources; /* resource/lock state for gl/vg/lv */
diff --git a/daemons/lvmlockd/lvmlockd-sanlock.c b/daemons/lvmlockd/lvmlockd-sanlock.c
index 44926da..4317aad 100644
--- a/daemons/lvmlockd/lvmlockd-sanlock.c
+++ b/daemons/lvmlockd/lvmlockd-sanlock.c
@@ -33,52 +33,101 @@
#include <sys/socket.h>
/*
- * If access to the pv containing the vg's leases is lost, sanlock cannot renew
- * the leases we have acquired for locked LVs. This means that we could soon
- * loose the lease to another host which could activate our LV exclusively. We
- * do not want to get to the point of two hosts having the same LV active
- * exclusively (it obviously violates the purpose of LV locks.)
- *
- * The default method of preventing this problem is for lvmlockd to do nothing,
- * which produces a safe but potentially inconvenient result. Doing nothing
- * leads to our LV leases not being released, which leads to sanlock using the
- * local watchdog to reset us before another host can acquire our lock. It
- * would often be preferrable to avoid the abrupt hard reset from the watchdog.
- *
- * There are other options to avoid being reset by our watchdog. If we can
- * quickly stop using the LVs in question and release the locks for them, then
- * we could avoid a reset (there's a certain grace period of about 40 seconds
- * in which we can attempt this.) To do this, we can tell sanlock to run a
- * specific program when it has lost access to our leases. We could use this
- * program to:
- *
- * 1. Deactivate all lvs in the effected vg. If all the leases are
- * deactivated, then our LV locks would be released and sanlock would no longer
- * use the watchdog to reset us. If file systems are mounted on the active
- * lvs, then deactivating them would fail, so this option would be of limited
- * usefulness.
- *
- * 2. Option 1 could be extended to kill pids using the fs on the lv, unmount
- * the fs, and deactivate the lv. This is probably out of scope for lvm
- * directly, and would likely need the help of another system service.
- *
- * 3. Use dmsetup suspend to block access to lvs in the effected vg. If this
- * was successful, the local host could no longer write to the lvs, we could
- * safely release the LV locks, and sanlock would no longer reset us. At this
- * point, with suspended lvs, the host would be in a fairly hobbled state, and
- * would almost certainly need a manual, forcible reset.
- *
- * 4. Option 3 could be extended to monitor the lost storage, and if it is
- * reconnected, the leases could be reacquired, and the suspended lvs resumed
- * (reacquiring leases will fail if another host has acquired them since they
- * were released.) This complexity of this option, combined with the fact that
- * the error conditions are often not as simple as storage being lost and then
- * later connecting, will result in this option being too unreliable.
- *
- * Add a config option that we could use to select a different behavior than
- * the default. Then implement one of the simpler options as a proof of
- * concept, which could be extended if needed.
- */
+-------------------------------------------------------------------------------
+For each VG, lvmlockd creates a sanlock lockspace that holds the leases for
+that VG. There's a lease for the VG lock, and there's a lease for each active
+LV. sanlock maintains (reads/writes) these leases, which exist on storage.
+That storage is a hidden LV within the VG: /dev/vg/lvmlock. lvmlockd gives the
+path of this internal LV to sanlock, which then reads/writes the leases on it.
+
+# lvs -a cc -o+uuid
+ LV VG Attr LSize LV UUID
+ lv1 cc -wi-a----- 2.00g 7xoDtu-yvNM-iwQx-C94t-BbYs-UzBl-o8hAIa
+ lv2 cc -wi-a----- 100.00g exxNPX-wZdO-uCNy-yiGa-aJGT-JKVl-arfcYT
+ [lvmlock] cc -wi-ao---- 256.00m iLpDel-hR0T-hJ3u-rnVo-PcDh-mcjt-sF9egM
+
+# sanlock status
+s lvm_cc:1:/dev/mapper/cc-lvmlock:0
+r lvm_cc:exxNPX-wZdO-uCNy-yiGa-aJGT-JKVl-arfcYT:/dev/mapper/cc-lvmlock:71303168:13 p 26099
+r lvm_cc:7xoDtu-yvNM-iwQx-C94t-BbYs-UzBl-o8hAIa:/dev/mapper/cc-lvmlock:70254592:3 p 26099
+
+This shows that sanlock is maintaining leases on /dev/mapper/cc-lvmlock.
+
+sanlock acquires a lockspace lease when the lockspace is joined, i.e. when the
+VG is started by 'vgchange --lock-start cc'. This lockspace lease exists at
+/dev/mapper/cc-lvmlock offset 0, and sanlock regularly writes to it to maintain
+ownership of it. Joining the lockspace (by acquiring the lockspace lease in
+it) then allows standard resource leases to be acquired in the lockspace for
+whatever the application wants. lvmlockd uses resource leases for the VG lock
+and LV locks.
+
+sanlock acquires a resource lease for each actual lock that lvm commands use.
+Above, there are two LV locks that are held because the two LVs are active.
+These are on /dev/mapper/cc-lvmlock at offsets 71303168 and 70254592. sanlock
+does not write to these resource leases except when acquiring and releasing
+them (e.g. lvchange -ay/-an). The renewal of the lockspace lease maintains
+ownership of all the resource leases in the lockspace.
+
+If the host loses access to the disk that the sanlock lv lives on, then sanlock
+can no longer renew its lockspace lease. The lockspace lease will eventually
+expire, at which point the host will lose ownership of it, and of all resource
+leases it holds in the lockspace. Eventually, other hosts will be able to
+acquire those leases. sanlock ensures that another host will not be able to
+acquire one of the expired leases until the current host has quit using it.
+
+It is important that the host "quit using" the leases it is holding if the
+sanlock storage is lost and they begin expiring. If the host cannot quit using
+the leases and release them within a limited time, then sanlock will use the
+local watchdog to forcibly reset the host before any other host can acquire
+them. This is severe, but preferable to possibly corrupting the data protected
+by the lease. It ensures that two nodes will not be using the same lease at
+once. For LV leases, that means that another host will not be able to activate
+the LV while another host still has it active.
+
+sanlock notifies the application that it cannot renew the lockspace lease. The
+application needs to quit using all leases in the lockspace and release them as
+quickly as possible. In the initial version, lvmlockd ignored this
+notification, so sanlock would eventually reach the point where it would use
+the local watchdog to reset the host. However, it's better to attempt a
+response. If that response succeeds, the host can avoid being reset. If the
+response fails, then sanlock will eventually reset the host as the last resort.
+sanlock gives the application about 40 seconds to complete its response and
+release its leases before resetting the host.
+
+An application can specify the path and args of a program that sanlock should
+run to notify it if the lockspace lease cannot be renewed. This program should
+carry out the application's response to the expiring leases: attempt to quit
+using the leases and then release them. lvmlockd gives this command to sanlock
+for each VG when that VG is started: 'lvmlockctl --kill vg_name'
+
+If sanlock loses access to lease storage in that VG, it runs lvmlockctl --kill,
+which:
+
+1. Uses syslog to explain what is happening.
+
+2. Notifies lvmlockd that the VG is being killed, so lvmlockd can
+ immediatley return an error for this condition if any new lock
+ requests are made. (This step would not be strictly necessary.)
+
+3. Attempts to quit using the VG. This is not yet implemented, but
+ will eventually use blkdeactivate on the VG (or a more forceful
+ equivalent.)
+
+4. If step 3 was successful at terminating all use of the VG, then
+ lvmlockd is told to release all the leases for the VG. If this
+ is all done without about 40 seconds, the host can avoid being
+ reset.
+
+Until steps 3 and 4 are fully implemented, manual steps can be substituted.
+This is primarily for testing since the problem needs to be noticed and
+responded to in a very short time. The manual alternative to step 3 is to kill
+any processes using file systems on LV's in the VG, unmount all file systems on
+the LVs, and deactivate all the LVs. Once this is done, the manual alternative
+to step 4 is to run 'lvmlockctl --drop vg_name', which tells lvmlockd to
+release all the leases for the VG.
+-------------------------------------------------------------------------------
+*/
+
/*
* Each lockspace thread has its own sanlock daemon connection.
@@ -961,12 +1010,24 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
char lock_lv_name[MAX_ARGS+1];
char lsname[SANLK_NAME_LEN + 1];
char disk_path[SANLK_PATH_LEN];
+ char killpath[SANLK_PATH_LEN];
+ char killargs[SANLK_PATH_LEN];
int gl_found;
int ret, rv;
memset(disk_path, 0, sizeof(disk_path));
memset(lock_lv_name, 0, sizeof(lock_lv_name));
+ /*
+ * Construct the path to lvmlockctl by using the path to the lvm binary
+ * and appending "lockctl" to get /path/to/lvmlockctl.
+ */
+ memset(killpath, 0, sizeof(killpath));
+ snprintf(killpath, SANLK_PATH_LEN - 1, "%slockctl", LVM_PATH);
+
+ memset(killargs, 0, sizeof(killargs));
+ snprintf(killargs, SANLK_PATH_LEN - 1, "--kill %s", ls->vg_name);
+
rv = check_args_version(ls->vg_args, VG_LOCK_ARGS_MAJOR);
if (rv < 0) {
ret = -EARGS;
@@ -1051,6 +1112,15 @@ int lm_prepare_lockspace_sanlock(struct lockspace *ls)
goto fail;
}
+ log_debug("set killpath to %s %s", killpath, killargs);
+
+ rv = sanlock_killpath(lms->sock, 0, killpath, killargs);
+ if (rv < 0) {
+ log_error("S %s killpath error %d", lsname, rv);
+ ret = -EMANAGER;
+ goto fail;
+ }
+
rv = sanlock_restrict(lms->sock, SANLK_RESTRICT_SIGKILL);
if (rv < 0) {
log_error("S %s restrict error %d", lsname, rv);
@@ -1397,11 +1467,6 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
log_error("S %s R %s lock_san acquire error %d",
ls->name, r->name, rv);
- if (added) {
- lm_rem_resource_sanlock(ls, r);
- return rv;
- }
-
/* if the gl has been disabled, remove and free the gl resource */
if ((rv == SANLK_LEADER_RESOURCE) && (r->type == LD_RT_GL)) {
if (!lm_gl_is_enabled(ls)) {
@@ -1413,6 +1478,22 @@ int lm_lock_sanlock(struct lockspace *ls, struct resource *r, int ld_mode,
}
}
+ if (added)
+ lm_rem_resource_sanlock(ls, r);
+
+ /* sanlock gets i/o errors trying to read/write the leases. */
+ if (rv == -EIO)
+ rv = -ELOCKIO;
+
+ /*
+ * The sanlock lockspace can disappear if the lease storage fails,
+ * the delta lease renewals fail, the lockspace enters recovery,
+ * lvmlockd holds no leases in the lockspace, so sanlock can
+ * stop and free the lockspace.
+ */
+ if (rv == -ENOSPC)
+ rv = -ELOCKIO;
+
return rv;
}
@@ -1594,9 +1675,11 @@ int lm_unlock_sanlock(struct lockspace *ls, struct resource *r,
}
rv = sanlock_release(lms->sock, -1, 0, 1, &rs);
- if (rv < 0) {
+ if (rv < 0)
log_error("S %s R %s unlock_san release error %d", ls->name, r->name, rv);
- }
+
+ if (rv == -EIO)
+ rv = -ELOCKIO;
return rv;
}
diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c
index 4e85ec1..7f14a86 100644
--- a/lib/locking/lvmlockd.c
+++ b/lib/locking/lvmlockd.c
@@ -1357,6 +1357,7 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
const char *mode = NULL;
const char *opts = NULL;
uint32_t lockd_flags;
+ int force_cache_update = 0;
int retries = 0;
int result;
@@ -1401,8 +1402,8 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
/* We can continue reading if a shared lock fails. */
if (!strcmp(mode, "sh")) {
log_warn("Reading without shared global lock.");
- lvmetad_validate_global_cache(cmd, 1);
- return 1;
+ force_cache_update = 1;
+ goto allow;
}
log_error("Global lock failed: check that lvmlockd is running.");
@@ -1425,9 +1426,19 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
*
* ESTARTING: the lockspace with the gl is starting.
* The VG with the global lock is starting and should finish shortly.
+ *
+ * ELOCKIO: sanlock gets i/o errors when trying to read/write leases
+ * (This can progress to EVGKILLED.)
+ *
+ * EVGKILLED: the sanlock lockspace is being killed after losing
+ * access to lease storage.
*/
- if (result == -ENOLS || result == -ESTARTING) {
+ if (result == -ENOLS ||
+ result == -ESTARTING ||
+ result == -EVGKILLED ||
+ result == -ELOCKIO) {
+
if (!strcmp(mode, "un"))
return 1;
@@ -1436,9 +1447,13 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
*/
if (strcmp(mode, "sh")) {
if (result == -ESTARTING)
- log_error("Global lock failed: lockspace is starting.");
+ log_error("Global lock failed: lockspace is starting");
else if (result == -ENOLS)
- log_error("Global lock failed: check that global lockspace is started.");
+ log_error("Global lock failed: check that global lockspace is started");
+ else if (result == -ELOCKIO)
+ log_error("Global lock failed: storage errors for sanlock leases");
+ else if (result == -EVGKILLED)
+ log_error("Global lock failed: storage failed for sanlock leases");
else
log_error("Global lock failed: error %d", result);
return 0;
@@ -1452,14 +1467,21 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
if (result == -ESTARTING) {
log_warn("Skipping global lock: lockspace is starting");
- lvmetad_validate_global_cache(cmd, 1);
- return 1;
+ force_cache_update = 1;
+ goto allow;
+ }
+
+ if (result == -ELOCKIO || result == -EVGKILLED) {
+ log_warn("Skipping global lock: storage %s for sanlock leases",
+ result == -ELOCKIO ? "errors" : "failed");
+ force_cache_update = 1;
+ goto allow;
}
if ((lockd_flags & LD_RF_NO_GL_LS) || (lockd_flags & LD_RF_NO_LOCKSPACES)) {
log_warn("Skipping global lock: lockspace not found or started");
- lvmetad_validate_global_cache(cmd, 1);
- return 1;
+ force_cache_update = 1;
+ goto allow;
}
/*
@@ -1492,9 +1514,8 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
}
}
- if (!(flags & LDGL_SKIP_CACHE_VALIDATE))
- lvmetad_validate_global_cache(cmd, 0);
-
+ allow:
+ lvmetad_validate_global_cache(cmd, force_cache_update);
return 1;
}
@@ -1510,7 +1531,7 @@ int lockd_gl(struct cmd_context *cmd, const char *def_mode, uint32_t flags)
*
* The result of the VG lock operation needs to be saved in lockd_state
* because the result needs to be passed into vg_read so it can be
- * assessed in combination with vg->lock_state.
+ * assessed in combination with vg->lock_type.
*
* The VG lock protects the VG metadata on disk from concurrent access
* among hosts. The VG lock also ensures that the local lvmetad cache
@@ -1687,6 +1708,28 @@ int lockd_vg(struct cmd_context *cmd, const char *vg_name, const char *def_mode,
}
/*
+ * sanlock is getting i/o errors while reading/writing leases, or the
+ * lockspace/VG is being killed after failing to renew its lease for
+ * too long.
+ */
+ if (result == -EVGKILLED || result == -ELOCKIO) {
+ const char *problem = (result == -ELOCKIO ? "errors" : "failed");
+
+ if (!strcmp(mode, "un")) {
+ ret = 1;
+ goto out;
+ } else if (!strcmp(mode, "sh")) {
+ log_warn("VG %s lock skipped: storage %s for sanlock leases", vg_name, problem);
+ ret = 1;
+ goto out;
+ } else {
+ log_error("VG %s lock failed: storage %s for sanlock leases", vg_name, problem);
+ ret = 0;
+ goto out;
+ }
+ }
+
+ /*
* An unused/previous lockspace for the VG was found.
* This means it must be a lockd VG, not local. The
* lockspace needs to be started to be used.
@@ -1903,6 +1946,12 @@ int lockd_lv_name(struct cmd_context *cmd, struct volume_group *vg,
return 0;
}
+ if (result == -EVGKILLED || result == -ELOCKIO) {
+ const char *problem = (result == -ELOCKIO ? "errors" : "failed");
+ log_error("LV %s/%s lock failed: storage %s for sanlock leases", vg->name, lv_name, problem);
+ return 0;
+ }
+
if (result < 0) {
log_error("LV %s/%s lock failed: error %d", vg->name, lv_name, result);
return 0;
diff --git a/lib/locking/lvmlockd.h b/lib/locking/lvmlockd.h
index b0edeae..64b3ce9 100644
--- a/lib/locking/lvmlockd.h
+++ b/lib/locking/lvmlockd.h
@@ -17,8 +17,7 @@
#define LOCKD_SANLOCK_LV_NAME "lvmlock"
/* lockd_gl flags */
-#define LDGL_SKIP_CACHE_VALIDATE 0x00000001
-#define LDGL_UPDATE_NAMES 0x00000002
+#define LDGL_UPDATE_NAMES 0x00000001
/* lockd_lv flags */
#define LDLV_MODE_NO_SH 0x00000001
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - libdm: ensure new dm_timestamp objects are initialized
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=974e7b9220f261...
Commit: 974e7b9220f26154c5f491ca8ec49f57dd834c66
Parent: b59cdf089217e1b86b2106bdccb990bda92690e5
Author: Bryn M. Reeves <bmr(a)redhat.com>
AuthorDate: Fri Aug 7 13:10:34 2015 +0100
Committer: Bryn M. Reeves <bmr(a)redhat.com>
CommitterDate: Sat Aug 8 10:42:14 2015 +0100
libdm: ensure new dm_timestamp objects are initialized
Allocate a dm_timestamp with dm_zalloc() to ensure the memory is
initialized to a known state.
---
libdm/libdm-timestamp.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-timestamp.c b/libdm/libdm-timestamp.c
index 7690ccb..fe006d5 100644
--- a/libdm/libdm-timestamp.c
+++ b/libdm/libdm-timestamp.c
@@ -54,7 +54,7 @@ struct dm_timestamp *dm_timestamp_alloc(void)
{
struct dm_timestamp *ts = NULL;
- if (!(ts = dm_malloc(sizeof(*ts))))
+ if (!(ts = dm_zalloc(sizeof(*ts))))
stack;
return ts;
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - tests: add pv-ext-flags.sh test
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8056a6eaa7d3df...
Commit: 8056a6eaa7d3df9eeb51d0a5a06ac4c9417e90c8
Parent: 5ff2a9ad73b0fafb4f507d64a8992edd0e41cd13
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Tue Apr 7 13:50:54 2015 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Fri Aug 21 11:15:53 2015 +0200
tests: add pv-ext-flags.sh test
Testing PV extension flags. Currently, there's only one PV extension
flag present - the PV_EXT_USED flag (marking PV as used in a VG).
---
test/shell/pv-ext-flags.sh | 160 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 160 insertions(+), 0 deletions(-)
diff --git a/test/shell/pv-ext-flags.sh b/test/shell/pv-ext-flags.sh
new file mode 100644
index 0000000..8d653df
--- /dev/null
+++ b/test/shell/pv-ext-flags.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+# Copyright (C) 2015 Red Hat, Inc. All rights reserved.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+. lib/inittest
+
+aux prepare_devs 2
+
+# PV_EXT_USED flag
+MARKED_AS_USED_MSG="marked as used"
+
+######################################
+### CHECK PV WITH 0 METADATA AREAS ###
+######################################
+
+pvcreate -ff -y --metadatacopies 0 "$dev1"
+pvcreate -ff -y --metadatacopies 1 "$dev2"
+
+# $dev1 and $dev2 not in any VG - pv_in_use field should be blank
+check pv_field "$dev1" pv_in_use ""
+check pv_field "$dev2" pv_in_use ""
+
+# $dev1 and $dev now in a VG - pv_in_use should display "used"
+vgcreate $vg1 "$dev1" "$dev2"
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev2" pv_in_use "used"
+
+# disable $dev2 and dev1 with 0 MDAs remains, but still
+# marked as used, so pvcreate/vgcreate/pvremove should fail
+aux disable_dev "$dev2"
+pvscan --cache
+
+check pv_field "$dev1" pv_in_use "used"
+not pvcreate "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not pvchange -u "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not vgcreate $vg2 "$dev1" 2>err
+grep "$MARKED_AS_USED" err
+not pvremove "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+
+# save PV signature from dev1 for reuse later on in this
+# test so we don't need to initialize all the VG stuff again
+dd if="$dev1" of=dev1_backup bs=1M
+
+# pvcreate and pvremove can be forced even if the PV is marked as used
+pvremove -ff "$dev1"
+dd if=dev1_backup of="$dev1" bs=1M
+pvcreate -ff "$dev1"
+dd if=dev1_backup of="$dev1" bs=1M
+
+# prepare a VG with $dev1 and $dev both having 1 MDA
+aux enable_dev "$dev2"
+vgremove -ff $vg1
+pvcreate --metadatacopies 1 "$dev1"
+vgcreate $vg1 "$dev1" "$dev2"
+
+# disable $dev1, then repair the VG - $dev1 is removed from VG
+aux disable_dev "$dev1"
+vgreduce --removemissing $vg1
+# now, enable $dev1, automatic repair will happen on pvs call
+# (or any other lvm command that does vg_read with repair inside)
+aux enable_dev "$dev1"
+
+# FIXME: once persistent cache does not cause races with timestamps
+# causing LVM tools to not see the VG inconsistency and once
+# VG repair is always done, delete this line which removes
+# persistent .cache as a workaround
+rm -f $TESTDIR/etc/.cache
+
+vgck $vg1
+# check $dev1 does not contain the PV_EXT_FLAG anymore - it
+# should be removed as part of the repaid during vg_read since
+# $dev1 is not part of $vg1 anymore
+check pv_field "$dev1" pv_in_use ""
+
+#############################################
+### CHECK PV WITH DISABLED METADATA AREAS ###
+#############################################
+
+pvcreate -ff -y --metadatacopies 1 "$dev1"
+pvcreate -ff -y --metadatacopies 1 "$dev2"
+
+# $dev1 and $dev2 not in any VG - pv_in_use field should be blank
+check pv_field "$dev1" pv_in_use ""
+check pv_field "$dev2" pv_in_use ""
+
+# $dev1 and $dev now in a VG - pv_in_use should display "used"
+vgcreate $vg1 "$dev1" "$dev2"
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev2" pv_in_use "used"
+
+pvchange --metadataignore y "$dev1"
+aux disable_dev "$dev2"
+pvscan --cache
+
+check pv_field "$dev1" pv_in_use "used"
+not pvcreate "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not pvchange -u "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not vgcreate $vg2 "$dev1" 2>err
+grep "$MARKED_AS_USED" err
+not pvremove "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+
+# save PV signature from dev1 for reuse later on in this
+# test so we don't need to initialize all the VG stuff again
+dd if="$dev1" of=dev1_backup bs=1M
+
+# pvcreate and pvremove can be forced even if the PV is marked as used
+pvremove -ff "$dev1"
+dd if=dev1_backup of="$dev1" bs=1M
+pvcreate -ff "$dev1"
+dd if=dev1_backup of="$dev1" bs=1M
+
+# prepare a VG with $dev1 and $dev both having 1 MDA
+aux enable_dev "$dev2"
+vgremove -ff $vg1
+pvcreate --metadatacopies 1 "$dev1"
+vgcreate $vg1 "$dev1" "$dev2"
+
+# disable $dev1, then repair the VG - $dev1 is removed from VG
+aux disable_dev "$dev1"
+vgreduce --removemissing $vg1
+# now, enable $dev1, automatic repair will happen on pvs call
+# (or any other lvm command that does vg_read with repair inside)
+aux enable_dev "$dev1"
+
+# FIXME: once persistent cache does not cause races with timestamps
+# causing LVM tools to not see the VG inconsistency and once
+# VG repair is always done, delete this line which removes
+# persistent .cache as a workaround
+rm -f $TESTDIR/etc/.cache
+
+vgck $vg1
+# check $dev1 does not contain the PV_EXT_FLAG anymore - it
+# should be removed as part of the repaid during vg_read since
+# $dev1 is not part of $vg1 anymore
+check pv_field "$dev1" pv_in_use ""
+
+###########################
+# OTHER PV-RELATED CHECKS #
+###########################
+
+# vgcfgrestore should also set PV_EXT_FLAG on PVs where VG is restored
+vgcfgbackup -f vg_backup $vg1
+check pv_field "$dev2" pv_in_use "used"
+vgremove -ff $vg1
+check pv_field "$dev2" pv_in_use ""
+vgcfgrestore -f vg_backup $vg1
+check pv_field "$dev2" pv_in_use "used"
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - backup: backup_restore_vg: register PVs that need writing via vg->pvs_to_write list
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5ff2a9ad73b0fa...
Commit: 5ff2a9ad73b0fafb4f507d64a8992edd0e41cd13
Parent: 921b994187f9c5e0dca2a6963f090a3aa9ae9d09
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu Mar 26 14:20:46 2015 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Fri Aug 21 11:15:53 2015 +0200
backup: backup_restore_vg: register PVs that need writing via vg->pvs_to_write list
The backup_restore_vg is used directly for restoring the VG from backup.
It's also used to do the VG conversions from one metadata format to
another which means vgconvert calls backup_restore_vg too.
When restoring VG from backup, we need to rewrite/write PV headers as
PVs may have been orphans before and now they're becoming part of some
VG - we need to write the PV_EXT_USED flag at least.
When using the backup_restore_vg for vgconvert, we need to write
completely new PV header in different format.
Avoid the special "pv_write" call and handling that was used before
this patch in vgconvert (vgconvert_single function to be more precise)
and reuse existing internal interface to register PV header for writing
(or rewriting) via vg->pvs_to_write list instead like we do it elsewhere
in the code.
This patch also resolves a problem in which PV headers with target
format were written in the vgconvert_single fn as orphans and VG
metadata were added later on - this was a tiny hack actually.
We can't do this now - we need to write the PV as belonging
to a VG because otherwise the PV_EXT_USED flag won't be written
properly (if the PV header is written as orphan, the PV_EXT_USED
is set to 0, of course, even though metadata are attached later).
So this patch removes this tiny inconsistency which was passing
just fine before because we didn't have any relation to the VG
in PV header before. Now we have the PV_EXT_USED flag which says
the "PV is used in some VG".
---
lib/format_text/archiver.c | 126 ++++++++++++++++++++++++++++++++++++++------
lib/format_text/archiver.h | 3 +-
tools/vgconvert.c | 89 +++++--------------------------
3 files changed, 125 insertions(+), 93 deletions(-)
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index fa7ce88..5d34f3b 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -319,28 +319,110 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
return vg;
}
+static int _restore_vg_should_write_pv(struct physical_volume *pv, struct pvcreate_params *pp)
+{
+ struct lvmcache_info *info;
+
+ if (pp)
+ return 1;
+
+ if (!(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
+ log_error("Failed to find cached info for PV %s.", pv_dev_name(pv));
+ return -1;
+ }
+
+ /*
+ * We're restoring a VG and if the PV_EXT_USED
+ * flag is not set yet in PV, we need to set it now!
+ * This may happen if we have plain PVs without a VG
+ * and we're restoring former VG from backup on top
+ * of these PVs.
+ */
+ if (!(lvmcache_ext_flags(info) & PV_EXT_USED))
+ return 1;
+
+ return 0;
+}
+
/* ORPHAN and VG locks held before calling this */
-int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, int drop_lvmetad)
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg,
+ struct pvcreate_params *pp, int drop_lvmetad)
{
- struct pv_list *pvl;
+ struct dm_list new_pvs;
+ struct pv_list *pvl, *new_pvl;
+ struct physical_volume *existing_pv, *pv;
+ struct dm_list *pvs = &vg->pvs;;
struct format_instance *fid;
struct format_instance_ctx fic;
+ int should_write_pv;
struct pv_to_write *pvw;
- uint32_t tmp;
+ uint32_t tmp_extent_size;
/*
* FIXME: Check that the PVs referenced in the backup are
* not members of other existing VGs.
*/
+ /* Prepare new PVs if needed. */
+ if (pp) {
+ dm_list_init(&new_pvs);
+
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ existing_pv = pvl->pv;
+
+ pp->rp.id = existing_pv->id;
+ pp->rp.idp = &pp->rp.id;
+ pp->rp.pe_start = pv_pe_start(existing_pv);
+ pp->rp.extent_count = pv_pe_count(existing_pv);
+ pp->rp.extent_size = pv_pe_size(existing_pv);
+ /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1 */
+
+ if (!(pv = pv_create(cmd, pv_dev(existing_pv),
+ 0, 0, 0,
+ pp->labelsector,
+ pp->pvmetadatacopies,
+ pp->pvmetadatasize,
+ 0, &pp->rp))) {
+ log_error("Failed to setup physical volume \"%s\".",
+ pv_dev_name(existing_pv));
+ return 0;
+ }
+ pv->vg_name = vg->name;
+ pv->vgid = vg->id;
+
+ if (!(new_pvl = dm_pool_zalloc(vg->vgmem, sizeof(*new_pvl)))) {
+ log_error("Failed to allocate PV list item for \"%s\".",
+ pv_dev_name(pvl->pv));
+ return 0;
+ }
+ new_pvl->pv = pv;
+ dm_list_add(&new_pvs, &new_pvl->list);
+
+ log_verbose("Set up physical volume for \"%s\" with %" PRIu64
+ " available sectors.", pv_dev_name(pv), pv_size(pv));
+ }
+
+ pvs = &new_pvs;
+ }
+
/* Attempt to write out using currently active format */
fic.type = FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vg->name;
fic.context.vg_ref.vg_id = NULL;
if (!(fid = cmd->fmt->ops->create_instance(cmd->fmt, &fic))) {
- log_error("Failed to allocate format instance");
+ log_error("Failed to allocate format instance.");
return 0;
}
+
+ if (pp) {
+ log_verbose("Deleting existing metadata for VG %s.", vg->name);
+ if (!vg_remove_mdas(vg)) {
+ cmd->fmt->ops->destroy_instance(fid);
+ log_error("Removal of existing metadata for VG %s failed.", vg->name);
+ return 0;
+ }
+ }
+
vg_set_fid(vg, fid);
/*
@@ -352,24 +434,36 @@ int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, int drop
return 0;
}
- /* Add any metadata areas on the PVs */
- dm_list_iterate_items(pvl, &vg->pvs) {
- if (!(pvw = dm_pool_zalloc(vg->vgmem, sizeof(*pvw)))) {
- log_error("pv_to_write allocation for '%s' failed", pv_dev_name(pvl->pv));
- return 0;
+ dm_list_iterate_items(pvl, pvs) {
+ if ((should_write_pv = _restore_vg_should_write_pv(pvl->pv, pp)) < 0)
+ return_0;
+
+ if (should_write_pv) {
+ if (!(pvw = dm_pool_zalloc(vg->vgmem, sizeof(*pvw)))) {
+ log_error("Failed to allocate structure for scheduled "
+ "writing of PV '%s'.", pv_dev_name(pvl->pv));
+ return 0;
+ }
+
+ if (pp) {
+ pvw->new_pv = 1;
+ pvw->pp = pp;
+ }
+
+ pvw->pv = pvl->pv;
+ dm_list_add(&vg->pvs_to_write, &pvw->list);
}
- pvw->pv = pvl->pv;
- dm_list_add(&vg->pvs_to_write, &pvw->list);
- tmp = vg->extent_size;
+ /* Add any metadata areas on the PV. */
+ tmp_extent_size = vg->extent_size;
vg->extent_size = 0;
if (!vg->fid->fmt->ops->pv_setup(vg->fid->fmt, pvl->pv, vg)) {
- vg->extent_size = tmp;
- log_error("Format-specific setup for %s failed",
+ vg->extent_size = tmp_extent_size;
+ log_error("Format-specific setup for %s failed.",
pv_dev_name(pvl->pv));
return 0;
}
- vg->extent_size = tmp;
+ vg->extent_size = tmp_extent_size;
}
if (!vg_write(vg))
@@ -423,7 +517,7 @@ int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
missing_pvs = vg_missing_pv_count(vg);
if (missing_pvs == 0)
- r = backup_restore_vg(cmd, vg, 1);
+ r = backup_restore_vg(cmd, vg, NULL, 1);
else
log_error("Cannot restore Volume Group %s with %i PVs "
"marked as missing.", vg->name, missing_pvs);
diff --git a/lib/format_text/archiver.h b/lib/format_text/archiver.h
index bc756d5..a24721e 100644
--- a/lib/format_text/archiver.h
+++ b/lib/format_text/archiver.h
@@ -51,7 +51,8 @@ int backup_remove(struct cmd_context *cmd, const char *vg_name);
struct volume_group *backup_read_vg(struct cmd_context *cmd,
const char *vg_name, const char *file);
-int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg, int drop_lvmetad);
+int backup_restore_vg(struct cmd_context *cmd, struct volume_group *vg,
+ struct pvcreate_params *pp, int drop_lvmetad);
int backup_restore_from_file(struct cmd_context *cmd, const char *vg_name,
const char *file, int force);
int backup_restore(struct cmd_context *cmd, const char *vg_name, int force);
diff --git a/tools/vgconvert.c b/tools/vgconvert.c
index c4bb37a..f34db28 100644
--- a/tools/vgconvert.c
+++ b/tools/vgconvert.c
@@ -19,14 +19,9 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
struct volume_group *vg,
struct processing_handle *handle __attribute__((unused)))
{
- struct physical_volume *pv, *existing_pv;
- struct pvcreate_restorable_params rp;
+ struct pvcreate_params pp;
struct logical_volume *lv;
struct lv_list *lvl;
- int pvmetadatacopies = 0;
- uint64_t pvmetadatasize = 0;
- struct pv_list *pvl;
- int change_made = 0;
struct lvinfo info;
int active = 0;
@@ -39,21 +34,22 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
return ECMD_FAILED;
}
+ pvcreate_params_set_defaults(&pp);
+
if (cmd->fmt->features & FMT_MDAS) {
if (arg_sign_value(cmd, metadatasize_ARG, SIGN_NONE) == SIGN_MINUS) {
log_error("Metadata size may not be negative");
return EINVALID_CMD_LINE;
}
- pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG,
- UINT64_C(0));
- if (!pvmetadatasize)
- pvmetadatasize =
+ pp.pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0));
+ if (!pp.pvmetadatasize)
+ pp.pvmetadatasize =
find_config_tree_int(cmd, metadata_pvmetadatasize_CFG, NULL);
- pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1);
- if (pvmetadatacopies < 0)
- pvmetadatacopies =
+ pp.pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1);
+ if (pp.pvmetadatacopies < 0)
+ pp.pvmetadatacopies =
find_config_tree_int(cmd, metadata_pvmetadatacopies_CFG, NULL);
}
@@ -63,9 +59,11 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
return EINVALID_CMD_LINE;
}
- rp.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, UINT64_C(0));
+ pp.rp.ba_size = arg_uint64_value(cmd, bootloaderareasize_ARG, UINT64_C(0));
}
+ pp.labelsector = arg_int64_value(cmd, labelsector_ARG, DEFAULT_LABELSECTOR);
+
if (!vg_check_new_extent_size(cmd->fmt, vg->extent_size))
return_ECMD_FAILED;
@@ -124,67 +122,6 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
if (active)
return_ECMD_FAILED;
- dm_list_iterate_items(pvl, &vg->pvs) {
- existing_pv = pvl->pv;
-
- rp.id = existing_pv->id;
- rp.idp = &rp.id;
- rp.pe_start = pv_pe_start(existing_pv);
- rp.extent_count = pv_pe_count(existing_pv);
- rp.extent_size = pv_pe_size(existing_pv);
-
- /* pe_end = pv_pe_count(existing_pv) * pv_pe_size(existing_pv) + pe_start - 1; */
-
- if (!(pv = pv_create(cmd, pv_dev(existing_pv),
- 0, 0, 0,
- arg_int64_value(cmd, labelsector_ARG,
- DEFAULT_LABELSECTOR),
- pvmetadatacopies, pvmetadatasize, 0, &rp))) {
- log_error("Failed to setup physical volume \"%s\"",
- pv_dev_name(existing_pv));
- if (change_made)
- log_error("Use pvcreate and vgcfgrestore to "
- "repair from archived metadata.");
- return ECMD_FAILED;
- }
-
- /* Need to revert manually if it fails after this point */
- change_made = 1;
-
- log_verbose("Set up physical volume for \"%s\" with %" PRIu64
- " available sectors", pv_dev_name(pv), pv_size(pv));
-
- /* Wipe existing label first */
- if (!label_remove(pv_dev(pv))) {
- log_error("Failed to wipe existing label on %s",
- pv_dev_name(pv));
- log_error("Use pvcreate and vgcfgrestore to repair "
- "from archived metadata.");
- return ECMD_FAILED;
- }
-
- log_very_verbose("Writing physical volume data to disk \"%s\"",
- pv_dev_name(pv));
- if (!(pv_write(cmd, pv, 0))) {
- log_error("Failed to write physical volume \"%s\"",
- pv_dev_name(pv));
- log_error("Use pvcreate and vgcfgrestore to repair "
- "from archived metadata.");
- return ECMD_FAILED;
- }
- log_verbose("Physical volume \"%s\" successfully created",
- pv_dev_name(pv));
- }
-
- log_verbose("Deleting existing metadata for VG %s", vg_name);
- if (!vg_remove_mdas(vg)) {
- log_error("Removal of existing metadata for %s failed.",
- vg_name);
- log_error("Use pvcreate and vgcfgrestore to repair "
- "from archived metadata.");
- return ECMD_FAILED;
- }
-
/* FIXME Cache the label format change so we don't have to skip this */
if (test_mode()) {
log_verbose("Test mode: Skipping metadata writing for VG %s in"
@@ -194,7 +131,7 @@ static int vgconvert_single(struct cmd_context *cmd, const char *vg_name,
log_verbose("Writing metadata for VG %s using format %s", vg_name,
cmd->fmt->name);
- if (!backup_restore_vg(cmd, vg, 0)) {
+ if (!backup_restore_vg(cmd, vg, &pp, 0)) {
log_error("Conversion failed for volume group %s.", vg_name);
log_error("Use pvcreate and vgcfgrestore to repair from "
"archived metadata.");
8 years, 8 months
dev-prajnoha-pv-ext-flag-used - metadata: _vg_read: check if PV_EXT_USED flag is set correctly for non-orphan PVs and do a repair if needed
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=921b994187f9c5...
Commit: 921b994187f9c5e0dca2a6963f090a3aa9ae9d09
Parent: 12752adfa9fe864cd32a43c0f5f43886c3f58588
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu Mar 19 07:53:22 2015 +0100
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Fri Aug 21 11:15:53 2015 +0200
metadata: _vg_read: check if PV_EXT_USED flag is set correctly for non-orphan PVs and do a repair if needed
The same check as we already do for orphan PVs, just the other way
round now: if the PV is surely part of some VG and any PV the VG
contains does not have the PV_EXT_USED flag set, repair it.
For example - /dev/sda here is in VG vg and it's incorrectly not
marked as used by PV_EXT_USED flag:
pvs --binary -o+pv_in_use
WARNING: Volume Group vg is not consistent.
WARNING: Repairing Physical Volume /dev/sda that is in Volume Group vg but not marked as used.
PV VG Fmt Attr PSize PFree ExtVsn InUse InUse
/dev/sda vg lvm2 a-- 124.00m 124.00m 2 1 1
---
lib/metadata/metadata.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 56 insertions(+), 1 deletions(-)
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 8670fd6..02aebac 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3535,6 +3535,52 @@ static int _check_reappeared_pv(struct volume_group *correct_vg,
return rv;
}
+static int _check_or_repair_pv_ext(struct cmd_context *cmd,
+ struct physical_volume *pv,
+ int repair, int *inconsistent_pvs)
+{
+ struct lvmcache_info *info;
+ uint32_t ext_version, ext_flags;
+
+ /* Missing PV - nothing to do. */
+ if (!pv->dev)
+ return 1;
+
+ if (!(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
+ log_error("Failed to find cached info for PV %s.", pv_dev_name(pv));
+ return 0;
+ }
+
+ ext_version = lvmcache_ext_version(info);
+ if (ext_version < 2) {
+ *inconsistent_pvs = 0;
+ return 1;
+ }
+
+ ext_flags = lvmcache_ext_flags(info);
+ if (!(ext_flags & PV_EXT_USED)) {
+ if (!repair) {
+ *inconsistent_pvs = 1;
+ return 1;
+ }
+
+ log_warn("WARNING: Repairing Physical Volume %s that is "
+ "in Volume Group %s but not marked as used.",
+ pv_dev_name(pv), pv->vg->name);
+
+ /* pv write will set correct ext_flags */
+ if (!pv_write(cmd, pv, 1)) {
+ *inconsistent_pvs = 1;
+ log_error("Failed to repair physical volume \"%s\".",
+ pv_dev_name(pv));
+ return 0;
+ }
+ }
+
+ *inconsistent_pvs = 0;
+ return 1;
+}
+
static int _repair_inconsistent_vg(struct volume_group *vg)
{
unsigned saved_handles_missing_pvs = vg->cmd->handles_missing_pvs;
@@ -3793,6 +3839,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
inconsistent_pvs = 1;
break;
}
+
if (lvmcache_mda_count(info)) {
if (!lvmcache_fid_add_mdas_pv(info, fid)) {
release_vg(correct_vg);
@@ -4069,7 +4116,15 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
return NULL;
}
- *consistent = 1;
+ /* We have the VG now finally, check if PV ext info is in sycn with VG metadata. */
+ dm_list_iterate_items(pvl, &correct_vg->pvs) {
+ if (!_check_or_repair_pv_ext(cmd, pvl->pv, *consistent, &inconsistent_pvs)) {
+ release_vg(correct_vg);
+ return_NULL;
+ }
+ }
+
+ *consistent = !inconsistent_pvs;
return correct_vg;
}
8 years, 8 months