Marcus Meissner
f45a4f9a5e
forward-port several patches from sle11sp3.bnc#831518 OBS-URL: https://build.opensuse.org/request/show/227422 OBS-URL: https://build.opensuse.org/package/show/Base:System/lvm2?expand=0&rev=85
145 lines
5.4 KiB
Diff
145 lines
5.4 KiB
Diff
commit b248ba0a396d7fc9a459eea02cfdc70b33ce3441
|
|
Author: Jonathan Brassow <jbrassow@redhat.com>
|
|
Date: Thu Oct 25 00:42:45 2012 -0500
|
|
|
|
mirror: Avoid reading mirrors with failed devices in mirrored log
|
|
|
|
Commit 9fd7ac7d035f0b2f8dcc3cb19935eb181816bd76 did not handle mirrors
|
|
that contained mirrored logs. This is because the status line of the
|
|
mirror does not give an indication of the health of the mirrored log,
|
|
as you can see here:
|
|
[root@bp-01 lvm2]# dmsetup status vg-lv vg-lv_mlog
|
|
vg-lv: 0 409600 mirror 2 253:6 253:7 400/400 1 AA 3 disk 253:5 A
|
|
vg-lv_mlog: 0 8192 mirror 2 253:3 253:4 7/8 1 AD 1 core
|
|
Thus, the possibility for LVM commands to hang still persists when mirror
|
|
have mirrored logs. I discovered this while performing some testing that
|
|
does polling with 'pvs' while doing I/O and killing devices. The 'pvs'
|
|
managed to get between the mirrored log device failure and the attempt
|
|
by dmeventd to repair it. The result was a very nasty block in LVM
|
|
commands that is very difficult to remove - even for someone who knows
|
|
what is going on. Thus, it is absolutely essential that the log of a
|
|
mirror be recursively checked for mirror devices which may be failed
|
|
as well.
|
|
|
|
Despite what the code comment says in the aforementioned commit...
|
|
+ * _mirrored_transient_status(). FIXME: It is unable to handle mirrors
|
|
+ * with mirrored logs because it does not have a way to get the status of
|
|
+ * the mirror that forms the log, which could be blocked.
|
|
... it is possible to get the status of the log because the log device
|
|
major/minor is given to us by the status output of the top-level mirror.
|
|
We can use that to query the log device for any DM status and see if it
|
|
is a mirror that needs to be bypassed. This patch does just that and is
|
|
now able to avoid reading from mirrors that have failed devices in a
|
|
mirrored log.
|
|
|
|
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c
|
|
index 6cc57d0..40f719e 100644
|
|
--- a/lib/activate/dev_manager.c
|
|
+++ b/lib/activate/dev_manager.c
|
|
@@ -139,6 +139,7 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
|
* _parse_mirror_status
|
|
* @mirror_status_string
|
|
* @image_health: return for allocated copy of image health characters
|
|
+ * @log_device: return for 'dev_t' of log device
|
|
* @log_health: NULL if corelog, otherwise alloc'ed log health char
|
|
*
|
|
* This function takes the mirror status string, breaks it up and returns
|
|
@@ -149,8 +150,10 @@ static int _info_run(const char *name, const char *dlid, struct dm_info *info,
|
|
* Returns: 1 on success, 0 on failure
|
|
*/
|
|
static int _parse_mirror_status(char *mirror_status_str,
|
|
- char **images_health, char **log_health)
|
|
+ char **images_health,
|
|
+ dev_t *log_dev, char **log_health)
|
|
{
|
|
+ int major, minor;
|
|
char *p = NULL;
|
|
char **args, **log_args;
|
|
unsigned num_devs, log_argc;
|
|
@@ -174,10 +177,14 @@ static int _parse_mirror_status(char *mirror_status_str,
|
|
return_0;
|
|
|
|
*log_health = NULL;
|
|
- if (!strcmp(log_args[0], "disk") &&
|
|
- !(*log_health = dm_strdup(log_args[2])))
|
|
- return_0;
|
|
-
|
|
+ *log_dev = 0;
|
|
+ if (!strcmp(log_args[0], "disk")) {
|
|
+ if (!(*log_health = dm_strdup(log_args[2])))
|
|
+ return_0;
|
|
+ if (sscanf(log_args[1], "%d:%d", &major, &minor) != 2)
|
|
+ return_0;
|
|
+ *log_dev = MKDEV((dev_t)major, minor);
|
|
+ }
|
|
if (!(*images_health = dm_strdup(args[2 + num_devs])))
|
|
return_0;
|
|
|
|
@@ -199,9 +206,7 @@ static int _parse_mirror_status(char *mirror_status_str,
|
|
* attempting to read a mirror, a circular dependency would be created.)
|
|
*
|
|
* This function is a slimmed-down version of lib/mirror/mirrored.c:
|
|
- * _mirrored_transient_status(). FIXME: It is unable to handle mirrors
|
|
- * with mirrored logs because it does not have a way to get the status of
|
|
- * the mirror that forms the log, which could be blocked.
|
|
+ * _mirrored_transient_status().
|
|
*
|
|
* If a failed device is detected in the status string, then it must be
|
|
* determined if 'block_on_error' or 'handle_errors' was used when
|
|
@@ -217,23 +222,17 @@ static int _ignore_blocked_mirror_devices(struct device *dev,
|
|
char *mirror_status_str)
|
|
{
|
|
unsigned i, check_for_blocking = 0;
|
|
+ dev_t log_dev;
|
|
char *images_health, *log_health;
|
|
-
|
|
uint64_t s,l;
|
|
char *params, *target_type = NULL;
|
|
void *next = NULL;
|
|
struct dm_task *dmt;
|
|
|
|
if (!_parse_mirror_status(mirror_status_str,
|
|
- &images_health, &log_health))
|
|
+ &images_health, &log_dev, &log_health))
|
|
goto_out;
|
|
|
|
- if (log_health && (log_health[0] != 'A')) {
|
|
- log_debug("%s: Mirror log device marked as failed",
|
|
- dev_name(dev));
|
|
- check_for_blocking = 1;
|
|
- }
|
|
-
|
|
for (i = 0; images_health[i]; i++)
|
|
if (images_health[i] != 'A') {
|
|
log_debug("%s: Mirror image %d marked as failed",
|
|
@@ -241,6 +240,29 @@ static int _ignore_blocked_mirror_devices(struct device *dev,
|
|
check_for_blocking = 1;
|
|
}
|
|
|
|
+ if (!check_for_blocking && log_dev) {
|
|
+ if (log_health[0] != 'A') {
|
|
+ log_debug("%s: Mirror log device marked as failed",
|
|
+ dev_name(dev));
|
|
+ check_for_blocking = 1;
|
|
+ } else {
|
|
+ struct device *tmp_dev;
|
|
+ char buf[16];
|
|
+
|
|
+ if (dm_snprintf(buf, sizeof(buf), "%d:%d",
|
|
+ (int)MAJOR(log_dev),
|
|
+ (int)MINOR(log_dev)) < 0)
|
|
+ goto_out;
|
|
+
|
|
+ if (!(tmp_dev = dev_create_file(buf, NULL, NULL, 1)))
|
|
+ goto_out;
|
|
+
|
|
+ tmp_dev->dev = log_dev;
|
|
+ if (!device_is_usable(tmp_dev))
|
|
+ goto_out;
|
|
+ }
|
|
+ }
|
|
+
|
|
if (!check_for_blocking)
|
|
return 0;
|
|
|