From 3f084b06e99c29faa1fc3fba8ca9f6bd643ae624 Mon Sep 17 00:00:00 2001 From: Zdenek Kabelac Date: Thu, 26 Oct 2023 21:57:59 +0200 Subject: [PATCH] device_mapper: raid status handle all a chars When getting raid status from some older kernels, we may get an 'a' for 'A' leg when doing initial synchronization. This may prohibit removal of newly synchronized leg until synchronization is finished. So in this case change the status to look like being reported from a newer kernel version. --- device_mapper/libdm-targets.c | 60 ++++++++++++++++++++--------------- libdm/libdm-targets.c | 60 ++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 52 deletions(-) diff --git a/device_mapper/libdm-targets.c b/device_mapper/libdm-targets.c index bfe76c5ff..43fe88d4c 100644 --- a/device_mapper/libdm-targets.c +++ b/device_mapper/libdm-targets.c @@ -106,26 +106,22 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, /* Second field holds the device count */ msg_fields = "<#devs> "; - if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1)) + if (!(pp = _skip_fields(params, 1)) || (sscanf(pp, "%d", &i) != 1) || !(p = _skip_fields(pp, 1))) goto_bad; msg_fields = ""; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid)))) goto_bad; - if (!(s->raid_type = dm_pool_zalloc(mem, p - params))) + msg_fields = " <#devices> and "; + if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1))) goto_bad; /* memory is freed when pool is destroyed */ - if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */ + if (!(s->dev_health = dm_pool_strndup(mem, p, i)) || !(p = _skip_fields(p, 1))) /* health chars */ goto_bad; - msg_fields = " <#devices> and "; - if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64, - s->raid_type, - &s->dev_count, - s->dev_health, - &s->insync_regions, - &s->total_regions) != 5) + s->dev_count = i; + if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2) goto_bad; /* @@ -141,13 +137,13 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, msg_fields = " and "; /* Skip pre-1.5.0 params */ - if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1))) + if (!(pp = _skip_fields(params, 4)) || !(p = _skip_fields(pp, 1))) goto_bad; - if (!(s->sync_action = dm_pool_zalloc(mem, pp - p))) + if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1))) goto_bad; - if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2) + if (sscanf(p, FMTu64, &s->mismatch_count) != 1) goto_bad; if (num_fields < 7) @@ -166,23 +162,35 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, if (sscanf(p, FMTu64, &s->data_offset) != 1) goto bad; + /* - 'A' - active write-through journal device. + * - 'a' - active write-back journal device. + * - 'D' - dead journal device. + * - '-' - no journal device. + */ + out: *status = s; - if (s->insync_regions == s->total_regions) { - /* FIXME: kernel gives misleading info here - * Trying to recognize a true state */ - while (i-- > 0) - if (s->dev_health[i] == 'a') - a++; /* Count number of 'a' */ + while (i-- > 0) + if (s->dev_health[i] == 'a') + a++; /* Count number of 'a' */ - if (a && a < s->dev_count) { - /* SOME legs are in 'a' */ - if (!strcasecmp(s->sync_action, "recover") - || !strcasecmp(s->sync_action, "idle")) - /* Kernel may possibly start some action - * in near-by future, do not report 100% */ - s->insync_regions--; + if (a) { + if ((a < s->dev_count) && /* SOME legs are in 'a' */ + /* FIXME: kernel gives misleading info here + * Trying to recognize a true state */ + (s->insync_regions == s->total_regions) && + (!strcasecmp(s->sync_action, "recover") || + !strcasecmp(s->sync_action, "idle"))) { + /* Kernel may possibly start some action + * in near-by future, do not report 100% */ + s->insync_regions--; + } + if ((a == s->dev_count) && /* all legs are in 'a' */ + (!strcasecmp(s->sync_action, "resync") || + !strcasecmp(s->sync_action, "idle"))) { + /* Mark 1st. leg in sync */ + s->dev_health[0] = 'A'; } } diff --git a/libdm/libdm-targets.c b/libdm/libdm-targets.c index 164d51564..d94480b64 100644 --- a/libdm/libdm-targets.c +++ b/libdm/libdm-targets.c @@ -106,26 +106,22 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, /* Second field holds the device count */ msg_fields = "<#devs> "; - if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1)) + if (!(pp = _skip_fields(params, 1)) || (sscanf(pp, "%d", &i) != 1) || !(p = _skip_fields(pp, 1))) goto_bad; msg_fields = ""; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid)))) goto_bad; - if (!(s->raid_type = dm_pool_zalloc(mem, p - params))) + msg_fields = " <#devices> and "; + if (!(s->raid_type = dm_pool_strndup(mem, params, pp - params - 1))) goto_bad; /* memory is freed when pool is destroyed */ - if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */ + if (!(s->dev_health = dm_pool_strndup(mem, p, i)) || !(p = _skip_fields(p, 1))) /* health chars */ goto_bad; - msg_fields = " <#devices> and "; - if (sscanf(params, "%s %u %s " FMTu64 "/" FMTu64, - s->raid_type, - &s->dev_count, - s->dev_health, - &s->insync_regions, - &s->total_regions) != 5) + s->dev_count = i; + if (sscanf(p, FMTu64 "/" FMTu64, &s->insync_regions, &s->total_regions) != 2) goto_bad; /* @@ -141,13 +137,13 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, msg_fields = " and "; /* Skip pre-1.5.0 params */ - if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1))) + if (!(pp = _skip_fields(params, 4)) || !(p = _skip_fields(pp, 1))) goto_bad; - if (!(s->sync_action = dm_pool_zalloc(mem, pp - p))) + if (!(s->sync_action = dm_pool_strndup(mem, pp, p - pp - 1))) goto_bad; - if (sscanf(p, "%s " FMTu64, s->sync_action, &s->mismatch_count) != 2) + if (sscanf(p, FMTu64, &s->mismatch_count) != 1) goto_bad; if (num_fields < 7) @@ -166,23 +162,35 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, if (sscanf(p, FMTu64, &s->data_offset) != 1) goto bad; + /* - 'A' - active write-through journal device. + * - 'a' - active write-back journal device. + * - 'D' - dead journal device. + * - '-' - no journal device. + */ + out: *status = s; - if (s->insync_regions == s->total_regions) { - /* FIXME: kernel gives misleading info here - * Trying to recognize a true state */ - while (i-- > 0) - if (s->dev_health[i] == 'a') - a++; /* Count number of 'a' */ + while (i-- > 0) + if (s->dev_health[i] == 'a') + a++; /* Count number of 'a' */ - if (a && a < s->dev_count) { - /* SOME legs are in 'a' */ - if (!strcasecmp(s->sync_action, "recover") - || !strcasecmp(s->sync_action, "idle")) - /* Kernel may possibly start some action - * in near-by future, do not report 100% */ - s->insync_regions--; + if (a) { + if ((a < s->dev_count) && /* SOME legs are in 'a' */ + /* FIXME: kernel gives misleading info here + * Trying to recognize a true state */ + (s->insync_regions == s->total_regions) && + (!strcasecmp(s->sync_action, "recover") || + !strcasecmp(s->sync_action, "idle"))) { + /* Kernel may possibly start some action + * in near-by future, do not report 100% */ + s->insync_regions--; + } + if ((a == s->dev_count) && /* all legs are in 'a' */ + (!strcasecmp(s->sync_action, "resync") || + !strcasecmp(s->sync_action, "idle"))) { + /* Mark 1st. leg in sync */ + s->dev_health[0] = 'A'; } }