master - lvmcache: add optional dev arg to lvmcache_info_from_pvid
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=01156de6f70ba5...
Commit: 01156de6f70ba5b1c8e2ae23c655ccd36ac59441
Parent: ed6ffc7a342149dab60086bcabd5fbd2d12ceeb7
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jun 6 14:04:17 2016 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 7 15:15:47 2016 -0500
lvmcache: add optional dev arg to lvmcache_info_from_pvid
A number of places are working on a specific dev when they
call lvmcache_info_from_pvid() to look up an info struct
based on a pvid. In those cases, pass the dev being used
to lvmcache_info_from_pvid(). When a dev is specified,
lvmcache_info_from_pvid() will verify that the cached
info it's using matches the dev being processed before
returning the info. Calling code will not mistakenly
get info for the wrong dev when duplicate devs exist.
This confusion was happening when scanning labels when
duplicate devs existed. label_read for the first dev
would add an info struct to lvmcache for that dev/pvid.
label_read for the second dev would see the pvid in
lvmcache from first dev, and mistakenly conclude that
the label_read from the second dev can be skipped
because it's already been done. By verifying that the
dev for the cached pvid matches the dev being read,
this mismatch is avoided and the label is actually read
from the second duplicate.
---
lib/cache/lvmcache.c | 33 ++++++++++++++++++++++++---------
lib/cache/lvmcache.h | 2 +-
lib/cache/lvmetad.c | 8 ++++----
lib/format_text/archiver.c | 2 +-
lib/format_text/format-text.c | 10 +++++-----
lib/label/label.c | 12 +++++++-----
lib/metadata/metadata.c | 12 ++++++------
lib/metadata/pv.c | 14 +++++++-------
lib/metadata/pv_manip.c | 2 +-
tools/toollib.c | 8 ++++++--
10 files changed, 62 insertions(+), 41 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 9e232f6..1af6363 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -690,8 +690,11 @@ static int _vginfo_is_invalid(struct lvmcache_vginfo *vginfo)
/*
* If valid_only is set, data will only be returned if the cached data is
* known still to be valid.
+ *
+ * When the device being worked with is known, pass that dev as the second arg.
+ * This ensures that when duplicates exist, the wrong dev isn't used.
*/
-struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only)
+struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only)
{
struct lvmcache_info *info;
char id[ID_LEN + 1] __attribute__((aligned(8)));
@@ -705,6 +708,15 @@ struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only)
if (!(info = dm_hash_lookup(_pvid_hash, id)))
return NULL;
+ /*
+ * When handling duplicate PVs, more than one device can have this pvid.
+ */
+ if (dev && info->dev && (info->dev != dev)) {
+ log_debug_cache("Ignoring lvmcache info for dev %s because dev %s was requested for PVID %s.",
+ dev_name(info->dev), dev_name(dev), id);
+ return NULL;
+ }
+
if (valid_only && !_info_is_valid(info))
return NULL;
@@ -733,7 +745,7 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
return NULL;
}
- info = lvmcache_info_from_pvid(pvid, 0);
+ info = lvmcache_info_from_pvid(pvid, NULL, 0);
if (!info)
return_NULL;
@@ -868,7 +880,7 @@ next:
* Find the device for the pvid that's currently in lvmcache.
*/
- if (!(info = lvmcache_info_from_pvid(alt->dev->pvid, 0))) {
+ if (!(info = lvmcache_info_from_pvid(alt->dev->pvid, NULL, 0))) {
/* This shouldn't happen */
log_warn("WARNING: PV %s on duplicate device %s not found in cache.",
alt->dev->pvid, dev_name(alt->dev));
@@ -1110,7 +1122,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_iterate_items(devl, &del_cache_devs) {
log_debug_cache("Drop duplicate device %s in lvmcache", dev_name(devl->dev));
- if ((info = lvmcache_info_from_pvid(devl->dev->pvid, 0)))
+ if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
lvmcache_del(info);
}
@@ -1381,7 +1393,7 @@ static struct device *_device_from_pvid(const struct id *pvid,
struct lvmcache_info *info;
struct label *label;
- if ((info = lvmcache_info_from_pvid((const char *) pvid, 0))) {
+ if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
if (lvmetad_used()) {
if (info->label && label_sector)
*label_sector = info->label->sector;
@@ -1962,7 +1974,7 @@ int lvmcache_update_vg(struct volume_group *vg, unsigned precommitted)
dm_list_iterate_items(pvl, &vg->pvs) {
strncpy(pvid_s, (char *) &pvl->pv->id, sizeof(pvid_s) - 1);
/* FIXME Could pvl->pv->dev->pvid ever be different? */
- if ((info = lvmcache_info_from_pvid(pvid_s, 0)) &&
+ if ((info = lvmcache_info_from_pvid(pvid_s, pvl->pv->dev, 0)) &&
!lvmcache_update_vgname_and_id(info, &vgsummary))
return_0;
}
@@ -2072,12 +2084,15 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller,
/*
* Find existing info struct in _pvid_hash or create a new one.
+ *
+ * Don't pass the known "dev" as an arg here. The mismatching
+ * devs for the duplicate case is checked below.
*/
- info = lvmcache_info_from_pvid(pvid_s, 0);
+ info = lvmcache_info_from_pvid(pvid_s, NULL, 0);
if (!info)
- info = lvmcache_info_from_pvid(dev->pvid, 0);
+ info = lvmcache_info_from_pvid(dev->pvid, NULL, 0);
if (!info) {
info = _create_info(labeller, dev);
@@ -2262,7 +2277,7 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset)
int lvmcache_pvid_is_locked(const char *pvid) {
struct lvmcache_info *info;
- info = lvmcache_info_from_pvid(pvid, 0);
+ info = lvmcache_info_from_pvid(pvid, NULL, 0);
if (!info || !info->vginfo)
return 0;
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 4fb74db..5f85b03 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -102,7 +102,7 @@ int lvmcache_vginfo_holders_dec_and_test_for_zero(struct lvmcache_vginfo *vginfo
struct lvmcache_vginfo *lvmcache_vginfo_from_vgname(const char *vgname,
const char *vgid);
struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
-struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, int valid_only);
+struct lvmcache_info *lvmcache_info_from_pvid(const char *pvid, struct device *dev, int valid_only);
const char *lvmcache_vgname_from_vgid(struct dm_pool *mem, const char *vgid);
const char *lvmcache_vgid_from_vgname(struct cmd_context *cmd, const char *vgname);
struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 02f0897..70adbb4 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -937,7 +937,7 @@ static int _pv_update_struct_pv(struct physical_volume *pv, struct format_instan
{
struct lvmcache_info *info;
- if ((info = lvmcache_info_from_pvid((const char *)&pv->id, 0))) {
+ if ((info = lvmcache_info_from_pvid((const char *)&pv->id, pv->dev, 0))) {
pv->label_sector = lvmcache_get_label(info)->sector;
pv->dev = lvmcache_device(info);
if (!pv->dev)
@@ -1175,7 +1175,7 @@ int lvmetad_vg_update(struct volume_group *vg)
if ((num = strchr(mda_id, '_'))) {
*num = 0;
++num;
- if ((info = lvmcache_info_from_pvid(mda_id, 0))) {
+ if ((info = lvmcache_info_from_pvid(mda_id, NULL, 0))) {
memset(&baton, 0, sizeof(baton));
baton.find = atoi(num);
baton.ignore = mda_is_ignored(mda);
@@ -1496,7 +1496,7 @@ int lvmetad_pv_found(struct cmd_context *cmd, const struct id *pvid, struct devi
if (!pvmeta)
return_0;
- info = lvmcache_info_from_pvid((const char *)pvid, 0);
+ info = lvmcache_info_from_pvid((const char *)pvid, dev, 0);
if (!(pvmeta->root = make_config_node(pvmeta, "pv", NULL, NULL))) {
dm_config_destroy(pvmeta);
@@ -1682,7 +1682,7 @@ static struct volume_group *lvmetad_pvscan_vg(struct cmd_context *cmd, struct vo
if (!pvl->pv->dev)
continue;
- if (!(info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, 0))) {
+ if (!(info = lvmcache_info_from_pvid((const char *)&pvl->pv->id, pvl->pv->dev, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
return NULL;
}
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 8220c38..4e85e0e 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -339,7 +339,7 @@ static int _restore_vg_should_write_pv(struct physical_volume *pv, int do_pvcrea
if (!(pv->fmt->features & FMT_PV_FLAGS))
return 0;
- if (!(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
+ if (!(info = lvmcache_info_from_pvid(pv->dev->pvid, pv->dev, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pv));
return -1;
}
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 095ae97..533fece 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -453,7 +453,7 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
"not match expected name %s.", vgname);
bad:
- if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, 0)) &&
+ if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
stack;
@@ -1447,7 +1447,7 @@ static int _text_pv_needs_rewrite(const struct format_type *fmt, struct physical
if (!pv->is_labelled)
return 1;
- if (!(info = lvmcache_info_from_pvid((const char *)&pv->id, 0))) {
+ if (!(info = lvmcache_info_from_pvid((const char *)&pv->id, pv->dev, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pv));
return 0;
}
@@ -1526,10 +1526,10 @@ static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
return_0;
if (lvmetad_used()) {
- info = lvmcache_info_from_pvid(dev->pvid, 0);
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
if (!info && !lvmetad_pv_lookup_by_dev(fmt->cmd, dev, NULL))
return 0;
- info = lvmcache_info_from_pvid(dev->pvid, 0);
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
} else {
struct label *label;
if (!(label_read(dev, &label, UINT64_C(0))))
@@ -1815,7 +1815,7 @@ static int _text_pv_setup(const struct format_type *fmt,
*/
else {
if (!pv->dev ||
- !(info = lvmcache_info_from_pvid(pv->dev->pvid, 0))) {
+ !(info = lvmcache_info_from_pvid(pv->dev->pvid, pv->dev, 0))) {
log_error("PV %s missing from cache", pv_dev_name(pv));
return 0;
}
diff --git a/lib/label/label.c b/lib/label/label.c
index b633aa3..b52cb42 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -184,7 +184,7 @@ static struct labeller *_find_labeller(struct device *dev, char *buf,
out:
if (!found) {
- if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
+ if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
_update_lvmcache_orphan(info);
log_very_verbose("%s: No label detected", dev_name(dev));
}
@@ -271,16 +271,18 @@ int label_read(struct device *dev, struct label **result,
struct lvmcache_info *info;
int r = 0;
- if ((info = lvmcache_info_from_pvid(dev->pvid, 1))) {
- log_debug_devs("Using cached label for %s", dev_name(dev));
+ if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 1))) {
+ log_debug_devs("Reading label from lvmcache for %s", dev_name(dev));
*result = lvmcache_get_label(info);
return 1;
}
+ log_debug_devs("Reading label from device %s", dev_name(dev));
+
if (!dev_open_readonly(dev)) {
stack;
- if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
+ if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
_update_lvmcache_orphan(info);
return r;
@@ -355,7 +357,7 @@ int label_verify(struct device *dev)
int r = 0;
if (!dev_open_readonly(dev)) {
- if ((info = lvmcache_info_from_pvid(dev->pvid, 0)))
+ if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
_update_lvmcache_orphan(info);
return_0;
}
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index bd97cd2..ea42fb7 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -160,7 +160,7 @@ void del_pvl_from_vgs(struct volume_group *vg, struct pv_list *pvl)
dm_list_del(&pvl->list);
pvl->pv->vg = vg->fid->fmt->orphan_vg; /* orphan */
- if ((info = lvmcache_info_from_pvid((const char *) &pvl->pv->id, 0)))
+ if ((info = lvmcache_info_from_pvid((const char *) &pvl->pv->id, pvl->pv->dev, 0)))
lvmcache_fid_add_mdas(info, vg->fid->fmt->orphan_vg->fid,
(const char *) &pvl->pv->id, ID_LEN);
pv_set_fid(pvl->pv, vg->fid->fmt->orphan_vg->fid);
@@ -4035,7 +4035,7 @@ static int _check_or_repair_pv_ext(struct cmd_context *cmd,
if (is_missing_pv(pvl->pv))
continue;
- if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, 0))) {
+ if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, pvl->pv->dev, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pvl->pv));
goto out;
}
@@ -4313,7 +4313,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
* Check it's an orphan without metadata area
* not ignored.
*/
- if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, 1)) ||
+ if (!(info = lvmcache_info_from_pvid(pvl->pv->dev->pvid, pvl->pv->dev, 1)) ||
!lvmcache_is_orphan(info)) {
inconsistent_pvs = 1;
break;
@@ -4917,7 +4917,7 @@ const char *find_vgname_from_pvid(struct cmd_context *cmd,
vgname = lvmcache_vgname_from_pvid(cmd, pvid);
if (is_orphan_vg(vgname)) {
- if (!(info = lvmcache_info_from_pvid(pvid, 0))) {
+ if (!(info = lvmcache_info_from_pvid(pvid, NULL, 0))) {
return_NULL;
}
/*
@@ -4975,7 +4975,7 @@ static struct physical_volume *_pv_read(struct cmd_context *cmd,
return_NULL;
if (lvmetad_used()) {
- info = lvmcache_info_from_pvid(dev->pvid, 0);
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
if (!info) {
if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found))
return_NULL;
@@ -4985,7 +4985,7 @@ static struct physical_volume *_pv_read(struct cmd_context *cmd,
pv_name);
return NULL;
}
- if (!(info = lvmcache_info_from_pvid(dev->pvid, 0))) {
+ if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
if (warn_flags & WARN_PV_READ)
log_error("No cache info in lvmetad cache for %s.",
pv_name);
diff --git a/lib/metadata/pv.c b/lib/metadata/pv.c
index 7169f31..9bf6075 100644
--- a/lib/metadata/pv.c
+++ b/lib/metadata/pv.c
@@ -157,7 +157,7 @@ uint32_t pv_mda_count(const struct physical_volume *pv)
{
struct lvmcache_info *info;
- info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0);
+ info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, pv->dev, 0);
return info ? lvmcache_mda_count(info) : UINT64_C(0);
}
@@ -177,7 +177,7 @@ uint32_t pv_mda_used_count(const struct physical_volume *pv)
struct lvmcache_info *info;
uint32_t used_count=0;
- info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0);
+ info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, pv->dev, 0);
if (!info)
return 0;
lvmcache_foreach_mda(info, _count_unignored, &used_count);
@@ -222,7 +222,7 @@ int is_used_pv(const struct physical_volume *pv)
if (!(pv->fmt->features & FMT_PV_FLAGS))
return 0;
- if (!(info = lvmcache_info_from_pvid((const char *)&pv->id, 0))) {
+ if (!(info = lvmcache_info_from_pvid((const char *)&pv->id, pv->dev, 0))) {
log_error("Failed to find cached info for PV %s.", pv_dev_name(pv));
return -1;
}
@@ -268,7 +268,7 @@ uint64_t pv_mda_size(const struct physical_volume *pv)
const char *pvid = (const char *)(&pv->id.uuid);
/* PVs could have 2 mdas of different sizes (rounding effect) */
- if ((info = lvmcache_info_from_pvid(pvid, 0)))
+ if ((info = lvmcache_info_from_pvid(pvid, pv->dev, 0)))
min_mda_size = lvmcache_smallest_mda_size(info);
return min_mda_size;
}
@@ -306,7 +306,7 @@ uint64_t pv_mda_free(const struct physical_volume *pv)
const char *pvid = (const char *)&pv->id.uuid;
struct lvmcache_info *info;
- if ((info = lvmcache_info_from_pvid(pvid, 0)))
+ if ((info = lvmcache_info_from_pvid(pvid, pv->dev, 0)))
return lvmcache_info_mda_free(info);
return 0;
@@ -359,7 +359,7 @@ unsigned pv_mda_set_ignored(const struct physical_volume *pv, unsigned mda_ignor
struct _pv_mda_set_ignored_baton baton;
struct metadata_area *mda;
- if (!(info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0)))
+ if (!(info = lvmcache_info_from_pvid((const char *)&pv->id.uuid, pv->dev, 0)))
return_0;
baton.mda_ignored = mda_ignored;
@@ -405,7 +405,7 @@ unsigned pv_mda_set_ignored(const struct physical_volume *pv, unsigned mda_ignor
struct label *pv_label(const struct physical_volume *pv)
{
struct lvmcache_info *info =
- lvmcache_info_from_pvid((const char *)&pv->id.uuid, 0);
+ lvmcache_info_from_pvid((const char *)&pv->id.uuid, pv->dev, 0);
if (info)
return lvmcache_get_label(info);
diff --git a/lib/metadata/pv_manip.c b/lib/metadata/pv_manip.c
index fa18c99..567cede 100644
--- a/lib/metadata/pv_manip.c
+++ b/lib/metadata/pv_manip.c
@@ -792,7 +792,7 @@ int pvremove_single(struct cmd_context *cmd, const char *pv_name,
goto out;
}
- info = lvmcache_info_from_pvid(dev->pvid, 0);
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
if (!dev_test_excl(dev)) {
/* FIXME Detect whether device-mapper is still using the device */
diff --git a/tools/toollib.c b/tools/toollib.c
index 0563fea..7cde806 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -3104,7 +3104,11 @@ static int _process_duplicate_pvs(struct cmd_context *cmd,
log_very_verbose("Processing duplicate device %s.", dev_name(devl->dev));
- info = lvmcache_info_from_pvid(devl->dev->pvid, 0);
+ /*
+ * Don't pass dev to lvmcache_info_from_pvid because we looking
+ * for the chosen/preferred dev for this pvid.
+ */
+ info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0);
if (info)
vgname = lvmcache_vgname_from_info(info);
if (vgname)
@@ -4643,7 +4647,7 @@ do_command:
continue;
}
- info = lvmcache_info_from_pvid(pd->pvid, 0);
+ info = lvmcache_info_from_pvid(pd->pvid, pd->dev, 0);
if (info)
lvmcache_del(info);
7 years, 11 months
master - lvmetad: handle update failures
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=ed6ffc7a342149...
Commit: ed6ffc7a342149dab60086bcabd5fbd2d12ceeb7
Parent: 851ccfccaf3dae184e0bd5f222bdcfcef33fa3b8
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri May 20 13:32:14 2016 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 7 10:17:00 2016 -0500
lvmetad: handle update failures
If a command gets stuck during an lvmetad update, lvmetad
will cancel that update after the timeout. The next command
to check the lvmetad will see that lvmetad needs to be
populated because lvmetad will return token of "none" after
a timed out update (same as when lvmetad is not populated
at all after starting.)
If a command gets an error during an lvmetad update, it
will now just quit and leave its updating token in place.
That update will be cancelled after the timeout.
---
daemons/lvmetad/lvmetactl.c | 26 +++
daemons/lvmetad/lvmetad-core.c | 210 +++++++++++++++++++---
lib/cache/lvmetad.c | 389 +++++++++++++++++++++++++++++----------
3 files changed, 498 insertions(+), 127 deletions(-)
diff --git a/daemons/lvmetad/lvmetactl.c b/daemons/lvmetad/lvmetactl.c
index 30ca1d6..dd2ee1e 100644
--- a/daemons/lvmetad/lvmetactl.c
+++ b/daemons/lvmetad/lvmetactl.c
@@ -55,24 +55,32 @@ int main(int argc, char **argv)
if (!strcmp(cmd, "dump")) {
reply = daemon_send_simple(h, "dump",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "pv_list")) {
reply = daemon_send_simple(h, "pv_list",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "vg_list")) {
reply = daemon_send_simple(h, "vg_list",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
} else if (!strcmp(cmd, "get_global_info")) {
reply = daemon_send_simple(h, "get_global_info",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@@ -86,6 +94,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "set_global_info",
"global_invalid = " FMTd64, (int64_t) val,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
print_reply(reply);
@@ -100,6 +110,8 @@ int main(int argc, char **argv)
"global_disable = " FMTd64, (int64_t) val,
"disable_reason = %s", LVMETAD_DISABLE_REASON_DIRECT,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
print_reply(reply);
@@ -123,18 +135,24 @@ int main(int argc, char **argv)
"name = %s", name,
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
} else if (uuid) {
reply = daemon_send_simple(h, "set_vg_info",
"uuid = %s", uuid,
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
} else if (name) {
reply = daemon_send_simple(h, "set_vg_info",
"name = %s", name,
"version = " FMTd64, (int64_t) ver,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
} else {
printf("name or uuid required\n");
@@ -153,6 +171,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"name = %s", name,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@@ -166,6 +186,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
@@ -182,6 +204,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "vg_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
/* printf("%s\n", reply.buffer.mem); */
@@ -208,6 +232,8 @@ int main(int argc, char **argv)
reply = daemon_send_simple(h, "pv_lookup",
"uuid = %s", uuid,
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", "lvmetactl",
NULL);
printf("%s\n", reply.buffer.mem);
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index 51db92f..ca1e4ed 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -207,6 +207,8 @@ struct vg_info {
#define VGFL_INVALID 0x00000001
+#define CMD_NAME_SIZE 32
+
typedef struct {
daemon_idle *idle;
log_state *log; /* convenience */
@@ -222,12 +224,25 @@ typedef struct {
struct dm_hash_table *vgname_to_vgid;
struct dm_hash_table *pvid_to_vgid;
char token[128];
+ char update_cmd[CMD_NAME_SIZE];
+ int update_pid;
+ int update_timeout;
+ uint64_t update_begin;
uint32_t flags; /* GLFL_ */
pthread_mutex_t token_lock;
pthread_mutex_t info_lock;
pthread_rwlock_t cache_lock;
} lvmetad_state;
+static uint64_t _monotonic_seconds(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
+ return 0;
+ return ts.tv_sec;
+}
+
static void destroy_metadata_hashes(lvmetad_state *s)
{
struct dm_hash_node *n = NULL;
@@ -2366,24 +2381,28 @@ static response set_global_info(lvmetad_state *s, request r)
#define REASON_BUF_SIZE 64
/*
- * FIXME: save the time when "updating" begins, and add a config setting for
- * how long we'll allow an update to take. Before returning "updating" as the
- * token value in get_global_info, check if the update has exceeded the max
- * allowed time. If so, then clear the current cache state and return "none"
- * as the current token value, so that the command will repopulate our cache.
+ * Save the time when "updating" begins, and the config setting for how long
+ * the update is allowed to take. Before returning "updating" as the token
+ * value in get_global_info, check if the update has exceeded the max allowed
+ * time. If so, then return "none" as the current token value (i.e.
+ * uninitialized), so that the command will repopulate our cache.
*
- * This will resolve the problem of a command starting to update the cache and
- * then failing, leaving the token set to "update in progress".
+ * This automatically clears a stuck update, where a command started to update
+ * the cache and then failed, leaving the token set to "update in progress".
*/
static response get_global_info(lvmetad_state *s, request r)
{
char reason[REASON_BUF_SIZE];
+ char flag_str[64];
+ int pid;
/* This buffer should be large enough to hold all the possible reasons. */
memset(reason, 0, sizeof(reason));
+ pid = (int)daemon_request_int(r, "pid", 0);
+
if (s->flags & GLFL_DISABLE) {
snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s",
(s->flags & GLFL_DISABLE_REASON_DIRECT) ? LVMETAD_DISABLE_REASON_DIRECT "," : "",
@@ -2394,17 +2413,46 @@ static response get_global_info(lvmetad_state *s, request r)
if (!reason[0])
strcpy(reason, "none");
- DEBUGLOG(s, "global info invalid is %d disable is %d reason %s",
- (s->flags & GLFL_INVALID) ? 1 : 0,
- (s->flags & GLFL_DISABLE) ? 1 : 0, reason);
+ /*
+ * If the current update has timed out, then return
+ * token of "none" which means "uninitialized" so that
+ * the caller will repopulate lvmetad.
+ */
+ if (s->update_begin && s->update_timeout) {
+ if (_monotonic_seconds() - s->update_begin >= s->update_timeout) {
+ DEBUGLOG(s, "global info cancel update after timeout %d len %d begin %llu pid %d cmd %s",
+ s->update_timeout,
+ (int)(_monotonic_seconds() - s->update_begin),
+ (unsigned long long)s->update_begin,
+ s->update_pid, s->update_cmd);
+ memset(s->token, 0, sizeof(s->token));
+ s->update_begin = 0;
+ s->update_timeout = 0;
+ s->update_pid = 0;
+ memset(s->update_cmd, 0, CMD_NAME_SIZE);
+ }
+ }
+
+ memset(flag_str, 0, sizeof(flag_str));
+ if (s->flags & GLFL_INVALID)
+ strcat(flag_str, "Invalid");
+ if (s->flags & GLFL_DISABLE)
+ strcat(flag_str, "Disable");
+ if (!flag_str[0])
+ strcat(flag_str, "none");
+
+ DEBUGLOG(s, "%d global info flags %s reason %s token %s update_pid %d",
+ pid, flag_str, reason, s->token[0] ? s->token : "none", s->update_pid);
- return daemon_reply_simple("OK", "global_invalid = " FMTd64,
- (int64_t)((s->flags & GLFL_INVALID) ? 1 : 0),
- "global_disable = " FMTd64,
- (int64_t)((s->flags & GLFL_DISABLE) ? 1 : 0),
+ return daemon_reply_simple("OK", "global_invalid = " FMTd64, (int64_t)((s->flags & GLFL_INVALID) ? 1 : 0),
+ "global_disable = " FMTd64, (int64_t)((s->flags & GLFL_DISABLE) ? 1 : 0),
"disable_reason = %s", reason,
- "token = %s",
- s->token[0] ? s->token : "none",
+ "daemon_pid = " FMTd64, (int64_t)getpid(),
+ "token = %s", s->token[0] ? s->token : "none",
+ "update_cmd = %s", s->update_cmd,
+ "update_pid = " FMTd64, (int64_t)s->update_pid,
+ "update_begin = " FMTd64, (int64_t)s->update_begin,
+ "update_timeout = " FMTd64, (int64_t)s->update_timeout,
NULL);
}
@@ -2593,37 +2641,145 @@ static response handler(daemon_state s, client_handle h, request r)
{
response res = { 0 };
lvmetad_state *state = s.private;
- const char *rq = daemon_request_str(r, "request", "NONE");
- const char *token = daemon_request_str(r, "token", "NONE");
char prev_token[128] = { 0 };
+ const char *rq;
+ const char *token;
+ const char *cmd;
+ int prev_in_progress, this_in_progress;
+ int update_timeout;
+ int pid;
int cache_lock = 0;
int info_lock = 0;
+ rq = daemon_request_str(r, "request", "NONE");
+ token = daemon_request_str(r, "token", "NONE");
+ pid = (int)daemon_request_int(r, "pid", 0);
+ cmd = daemon_request_str(r, "cmd", "NONE");
+ update_timeout = (int)daemon_request_int(r, "update_timeout", 0);
+
pthread_mutex_lock(&state->token_lock);
+
+ /*
+ * token_update: start populating the cache, i.e. a full update.
+ * To populate the lvmetad cache, a command does:
+ *
+ * - token_update, setting token to "update in progress"
+ * (further requests during the update continue using
+ * this same "update in progress" token)
+ * - pv_clear_all, to clear the current cache
+ * - pv_gone, for each PV
+ * - pv_found, for each PV to populate the cache
+ * - token_update, setting token to filter hash
+ */
if (!strcmp(rq, "token_update")) {
- memcpy(prev_token, state->token, 128);
- strncpy(state->token, token, 128);
- state->token[127] = 0;
+ prev_in_progress = !strcmp(state->token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+ this_in_progress = !strcmp(token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+
+ if (!prev_in_progress && this_in_progress) {
+ /* New update is starting (filter token is replaced by update token) */
+
+ memcpy(prev_token, state->token, 128);
+ strncpy(state->token, token, 128);
+ state->token[127] = 0;
+ state->update_begin = _monotonic_seconds();
+ state->update_timeout = update_timeout;
+ state->update_pid = pid;
+ strncpy(state->update_cmd, cmd, CMD_NAME_SIZE - 1);
+
+ DEBUGLOG(state, "token_update begin %llu timeout %d pid %d cmd %s",
+ (unsigned long long)state->update_begin,
+ state->update_timeout,
+ state->update_pid,
+ state->update_cmd);
+
+ } else if (prev_in_progress && this_in_progress) {
+ /* Current update is cancelled and replaced by a new update */
+
+ DEBUGLOG(state, "token_update replacing pid %d begin %llu len %d cmd %s",
+ state->update_pid,
+ (unsigned long long)state->update_begin,
+ (int)(_monotonic_seconds() - state->update_begin),
+ state->update_cmd);
+
+ memcpy(prev_token, state->token, 128);
+ strncpy(state->token, token, 128);
+ state->token[127] = 0;
+ state->update_begin = _monotonic_seconds();
+ state->update_timeout = update_timeout;
+ state->update_pid = pid;
+ strncpy(state->update_cmd, cmd, CMD_NAME_SIZE - 1);
+
+ DEBUGLOG(state, "token_update begin %llu timeout %d pid %d cmd %s",
+ (unsigned long long)state->update_begin,
+ state->update_timeout,
+ state->update_pid,
+ state->update_cmd);
+
+ } else if (prev_in_progress && !this_in_progress) {
+ /* Update is finished, update token is replaced by filter token */
+
+ if (state->update_pid != pid) {
+ /* If a pid doing update was cancelled, ignore its token update at the end. */
+ DEBUGLOG(state, "token_update ignored from cancelled update pid %d", pid);
+ pthread_mutex_unlock(&state->token_lock);
+
+ return daemon_reply_simple("token_mismatch",
+ "expected = %s", state->token,
+ "received = %s", token,
+ "update_pid = " FMTd64, (int64_t)state->update_pid,
+ "reason = %s", "another command has populated the cache");
+ }
+
+ DEBUGLOG(state, "token_update end len %d pid %d new token %s",
+ (int)(_monotonic_seconds() - state->update_begin),
+ state->update_pid, token);
+
+ memcpy(prev_token, state->token, 128);
+ strncpy(state->token, token, 128);
+ state->token[127] = 0;
+ state->update_begin = 0;
+ state->update_timeout = 0;
+ state->update_pid = 0;
+ memset(state->update_cmd, 0, CMD_NAME_SIZE);
+ }
pthread_mutex_unlock(&state->token_lock);
+
return daemon_reply_simple("OK",
"prev_token = %s", prev_token,
+ "update_pid = " FMTd64, (int64_t)state->update_pid,
NULL);
}
if (strcmp(token, state->token) && strcmp(rq, "dump") && strcmp(token, "skip")) {
pthread_mutex_unlock(&state->token_lock);
+
+ DEBUGLOG(state, "token_mismatch current \"%s\" got \"%s\" from pid %d cmd %s",
+ state->token, token, pid, cmd ?: "none");
+
+ return daemon_reply_simple("token_mismatch",
+ "expected = %s", state->token,
+ "received = %s", token,
+ "update_pid = " FMTd64, (int64_t)state->update_pid,
+ "reason = %s", "another command has populated the cache");
+ }
+
+ /* If a pid doing update was cancelled, ignore its update messages. */
+ if (!strcmp(token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS) &&
+ state->update_pid && pid && (state->update_pid != pid)) {
+ pthread_mutex_unlock(&state->token_lock);
+
+ DEBUGLOG(state, "token_mismatch ignore update from pid %d current update pid %d",
+ pid, state->update_pid);
+
return daemon_reply_simple("token_mismatch",
"expected = %s", state->token,
"received = %s", token,
- "reason = %s",
- "lvmetad cache is invalid due to a global_filter change or due to a running rescan", NULL);
+ "update_pid = " FMTd64, (int64_t)state->update_pid,
+ "reason = %s", "another command has populated the lvmetad cache");
}
+
pthread_mutex_unlock(&state->token_lock);
- /*
- * TODO Add a stats call, with transaction count/rate, time since last
- * update &c.
- */
if (!strcmp(rq, "pv_found") ||
!strcmp(rq, "pv_gone") ||
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index bb86e88..02f0897 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -27,16 +27,15 @@
#include <time.h>
-#define SCAN_TIMEOUT_SECONDS 80
-#define MAX_RESCANS 10 /* Maximum number of times to scan all PVs and retry if the daemon returns a token mismatch error */
-
static daemon_handle _lvmetad = { .error = 0 };
static int _lvmetad_use = 0;
static int _lvmetad_connected = 0;
+static int _lvmetad_daemon_pid = 0;
static char *_lvmetad_token = NULL;
static const char *_lvmetad_socket = NULL;
static struct cmd_context *_lvmetad_cmd = NULL;
+static int64_t _lvmetad_update_timeout;
static int _found_lvm1_metadata = 0;
@@ -135,6 +134,8 @@ int lvmetad_connect(struct cmd_context *cmd)
return 0;
}
+ _lvmetad_update_timeout = find_config_tree_int(cmd, global_lvmetad_update_wait_time_CFG, NULL);
+
_lvmetad = lvmetad_open(_lvmetad_socket);
if (_lvmetad.socket_fd >= 0 && !_lvmetad.error) {
@@ -248,13 +249,15 @@ int lvmetad_token_matches(struct cmd_context *cmd)
uint64_t now = 0, wait_start = 0;
int ret = 1;
- wait_sec = (unsigned int)find_config_tree_int(cmd, global_lvmetad_update_wait_time_CFG, NULL);
+ wait_sec = (unsigned int)_lvmetad_update_timeout;
retry:
- log_debug_lvmetad("lvmetad send get_global_info");
+ log_debug_lvmetad("Sending lvmetad get_global_info");
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error) {
log_warn("WARNING: Not using lvmetad after send error (%d).", reply.error);
@@ -271,6 +274,8 @@ retry:
goto fail;
}
+ _lvmetad_daemon_pid = (int)daemon_reply_int(reply, "daemon_pid", 0);
+
/*
* If lvmetad is being updated by another command, then sleep and retry
* until the token shows the update is done, and go on to the token
@@ -278,13 +283,6 @@ retry:
*
* Between retries, sleep for a random period between 1 and 2 seconds.
* Retry in this way for up to a configurable period of time.
- *
- * If lvmetad is still being updated after the timeout period,
- * then disable this command's use of lvmetad.
- *
- * FIXME: lvmetad could return the number of objects in its cache along with
- * the update message so that callers could detect when a rescan has
- * stalled while updating lvmetad.
*/
if (!strcmp(daemon_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
if (!(now = _monotonic_seconds()))
@@ -293,7 +291,7 @@ retry:
if (!wait_start)
wait_start = now;
- if (now - wait_start >= wait_sec) {
+ if (now - wait_start > wait_sec) {
log_warn("WARNING: Not using lvmetad after %u sec lvmetad_update_wait_time.", wait_sec);
goto fail;
}
@@ -354,12 +352,14 @@ static int _lvmetad_is_updating(struct cmd_context *cmd, int do_wait)
uint64_t now = 0, wait_start = 0;
int ret = 0;
- wait_sec = (unsigned int)find_config_tree_int(cmd, global_lvmetad_update_wait_time_CFG, NULL);
+ wait_sec = (unsigned int)_lvmetad_update_timeout;
retry:
- log_debug_lvmetad("lvmetad send get_global_info");
+ log_debug_lvmetad("Sending lvmetad get_global_info");
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error)
goto out;
@@ -405,23 +405,28 @@ static daemon_reply _lvmetad_send(struct cmd_context *cmd, const char *id, ...)
va_list ap;
daemon_reply reply = { 0 };
daemon_request req;
+ const char *token_expected;
unsigned int delay_usec;
unsigned int wait_sec = 0;
uint64_t now = 0, wait_start = 0;
+ int daemon_in_update;
+ int we_are_in_update;
if (!_lvmetad_connected || !_lvmetad_use) {
reply.error = ECONNRESET;
return reply;
}
- if (cmd)
- wait_sec = (unsigned int)find_config_tree_int(cmd, global_lvmetad_update_wait_time_CFG, NULL);
+ wait_sec = (unsigned int)_lvmetad_update_timeout;
retry:
- log_debug_lvmetad("lvmetad_send %s", id);
-
req = daemon_request_make(id);
- if (_lvmetad_token && !daemon_request_extend(req, "token = %s", _lvmetad_token, NULL)) {
+ if (!daemon_request_extend(req,
+ "token = %s", _lvmetad_token ?: "none",
+ "update_timeout = " FMTd64, (int64_t)wait_sec,
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
+ NULL)) {
reply.error = ENOMEM;
return reply;
}
@@ -437,22 +442,40 @@ retry:
if (reply.error == ECONNRESET)
log_warn("WARNING: lvmetad connection failed, cannot reconnect.");
+ /*
+ * For the "token_update" message, the result is handled entirely
+ * by the _token_update() function, so return the reply immediately.
+ */
+ if (!strcmp(id, "token_update"))
+ return reply;
+
+ /*
+ * For other messages it may be useful to retry and resend the
+ * message, so check for that case before returning the reply.
+ * The reply will be checked further in lvmetad_handle_reply.
+ */
+
if (reply.error)
- goto out;
+ return reply;
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
- if (!strcmp(daemon_reply_str(reply, "expected", ""), LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
+ token_expected = daemon_reply_str(reply, "expected", "");
+ daemon_in_update = !strcmp(token_expected, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+ we_are_in_update = !strcmp(_lvmetad_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+
+ if (daemon_in_update && !we_are_in_update) {
/*
- * Another command is updating the lvmetad cache, and
- * we cannot use lvmetad until the update is finished.
- * Retry our request for a while; the update should
- * finish shortly. This should not usually happen
- * because this command already checked that the token
- * is usable in lvmetad_token_matches(), but it's
- * possible for another command's rescan to slip in
- * between the time we call lvmetad_token_matches()
- * and the time we get here to lvmetad_send().
+ * Another command is updating lvmetad, and we cannot
+ * use lvmetad until the update is finished. Retry our
+ * request for a while; the update should finish
+ * shortly. This should not usually happen because
+ * this command already checked that the token is
+ * usable in lvmetad_token_matches(), but it's possible
+ * for another command's rescan to slip in between the
+ * time we call lvmetad_token_matches() and the time we
+ * get here to lvmetad_send().
*/
+
if (!(now = _monotonic_seconds()))
goto out;
@@ -472,61 +495,122 @@ retry:
usleep(delay_usec);
daemon_reply_destroy(reply);
goto retry;
+
} else {
- /*
- * Another command has updated the lvmetad cache, and
- * has done so using a different device filter from our
- * own, which has made the lvmetad token and our token
- * not match. This should not usually happen because
- * this command has already checked for a matching token
- * in lvmetad_token_matches(), but it's possible for
- * another command's rescan to slip in between the time
- * we call lvmetad_token_matches() and the time we get
- * here to lvmetad_send(). With a mismatched token
- * (different set of devices), we cannot use the lvmetad
- * cache.
- *
- * FIXME: it would be nice to have this command ignore
- * lvmetad at this point and revert to disk scanning,
- * but the layers above lvmetad_send are not yet able
- * to switch modes in the middle of processing.
- *
- * (The advantage of lvmetad_check_token is that it
- * can rescan to get the token in sync, or if that
- * fails it can make the command revert to scanning
- * from the start.)
- */
- log_warn("WARNING: Cannot use lvmetad while it caches different devices.");
+ /* See lvmetad_handle_reply for handling other cases. */
}
}
out:
return reply;
}
+/*
+ * token_update happens when starting or ending an lvmetad update.
+ * When starting we set the token to "update in progress".
+ * When ending we set the token to our filter:<hash>.
+ *
+ * From the perspective of a command, the lvmetad state is one of:
+ * "none" - the lvmetad cache is not populated and an update is required.
+ * "filter:<matching_hash>" - the command with can use the lvmetad cache.
+ * "filter:<unmatching_hash>" - the lvmetad cache must be updated to be used.
+ * "update in progress" - a command is updating the lvmetad cache.
+ *
+ * . If none, the command will update (scan and populate lvmetad),
+ * then use the cache.
+ *
+ * . If filter is matching, the command will use the cache.
+ *
+ * . If filter is unmatching, the command will update (scan and
+ * populate lvmetad), then use the cache.
+ *
+ * . If update in progress, the command will wait for a while for the state
+ * to become non-updating. If it changes, see above, if it doesn't change,
+ * then the command either reverts to not using lvmetad, or does an update
+ * (scan and populate lvmetad) and then uses the cache.
+ *
+ * A command that is explicitly intended to update the cache will always do
+ * that (it may wait for a while first to allow a current update to complete).
+ * A command that is not explicitly intended to update the cache may choose
+ * to revert to scanning and not use lvmetad.
+ *
+ * Because two different updates from two commands can potentially overlap,
+ * lvmetad saves the pid of the latest update to start, so it can reject messages
+ * from preempted updates. This prevents an invalid mix of two different updates.
+ * (The command makes use of the update_pid to print more informative messages.)
+ *
+ * If lvmetad detects that a command doing an update is taking too long, it will
+ * change the token from "update in progress" to "none", which means a new update
+ * is required, causing the next command to do an update. This effectively
+ * cancels/preempts a slow/stuck update, and helps to automatically resolve
+ * some failure cases.
+ */
+
static int _token_update(int *replaced_update)
{
daemon_reply reply;
+ const char *token_expected;
const char *prev_token;
+ int update_pid;
+ int ending_our_update;
- log_debug_lvmetad("Sending updated token to lvmetad: %s", _lvmetad_token ? : "<NONE>");
+ log_debug_lvmetad("Sending lvmetad token_update %s", _lvmetad_token);
reply = _lvmetad_send(NULL, "token_update", NULL);
if (replaced_update)
*replaced_update = 0;
- if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+ if (reply.error) {
+ log_warn("WARNING: lvmetad token update error: %s", strerror(reply.error));
+ daemon_reply_destroy(reply);
+ return 0;
+ }
+
+ update_pid = (int)daemon_reply_int(reply, "update_pid", 0);
+
+ /*
+ * A mismatch can only happen when this command attempts to set the
+ * token to filter:<hash> at the end of its update, but the update has
+ * been preempted in lvmetad by a new one (from update_pid).
+ */
+ if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
+ token_expected = daemon_reply_str(reply, "expected", "");
+
+ ending_our_update = strcmp(_lvmetad_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+
+ log_debug_lvmetad("Received token update mismatch expected \"%s\" our token \"%s\" update_pid %d our pid %d",
+ token_expected, _lvmetad_token, update_pid, getpid());
+
+ if (ending_our_update && (update_pid != getpid())) {
+ log_warn("WARNING: lvmetad was updated by another command (pid %d).", update_pid);
+ } else {
+ /*
+ * Shouldn't happen.
+ * If we're ending our update and our pid matches the update_pid,
+ * then there would not be a mismatch.
+ * If we're starting a new update, lvmetad never returns a
+ * token mismatch.
+ * In any case, it doesn't hurt to just return an error here.
+ */
+ log_error(INTERNAL_ERROR "lvmetad token update mismatch pid %d matches our own pid %d", update_pid, getpid());
+ }
+
+ daemon_reply_destroy(reply);
+ return 0;
+ }
+
+ if (strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
+ log_error("Failed response from lvmetad for token update.");
daemon_reply_destroy(reply);
return 0;
}
if ((prev_token = daemon_reply_str(reply, "prev_token", NULL))) {
if (!strcmp(prev_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS))
- if (replaced_update)
+ if (replaced_update && (update_pid != getpid()))
*replaced_update = 1;
}
daemon_reply_destroy(reply);
-
return 1;
}
@@ -539,8 +623,12 @@ static int _token_update(int *replaced_update)
*/
static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char *object, int *found)
{
- int action_modifies = 0;
+ const char *token_expected;
const char *action;
+ int action_modifies = 0;
+ int daemon_in_update;
+ int we_are_in_update;
+ int update_pid;
if (!id)
action = "<none>";
@@ -574,33 +662,111 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
}
if (reply.error) {
- log_error("Request to %s %s%sin lvmetad gave response %s.",
- action, object, *object ? " " : "", strerror(reply.error));
+ log_warn("WARNING: lvmetad cannot be used due to error: %s", strerror(reply.error));
goto fail;
}
/*
- * See the description of the token mismatch errors in lvmetad_send.
+ * Errors related to token mismatch.
*/
+
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
- if (!strcmp(daemon_reply_str(reply, "expected", ""), LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
+
+ token_expected = daemon_reply_str(reply, "expected", "");
+ update_pid = (int)daemon_reply_int(reply, "update_pid", 0);
+
+ log_debug("lvmetad token mismatch, expected \"%s\" our token \"%s\"",
+ token_expected, _lvmetad_token);
+
+ daemon_in_update = !strcmp(token_expected, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+ we_are_in_update = !strcmp(_lvmetad_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS);
+
+ if (daemon_in_update && we_are_in_update) {
+
/*
- * lvmetad_send retried up to the limit and eventually
- * printed a warning and gave up.
+ * When we do not match the update_pid, it means our
+ * update was cancelled and another process is now
+ * updating the cache.
*/
- log_error("Request to %s %s%sin lvmetad failed after lvmetad_update_wait_time expired.",
- action, object, *object ? " " : "");
- } else {
+
+ if (update_pid != getpid()) {
+ log_warn("WARNING: lvmetad is being updated by another command (pid %d).", update_pid);
+ } else {
+ /* Shouldn't happen */
+ log_error(INTERNAL_ERROR "lvmetad update by pid %d matches our own pid %d", update_pid, getpid());
+ }
+ /* We don't care if the action was modifying during a token update. */
+ action_modifies = 0;
+ goto fail;
+
+ } else if (daemon_in_update && !we_are_in_update) {
+
+ /*
+ * Another command is updating lvmetad, and we cannot
+ * use lvmetad until the update is finished.
+ * lvmetad_send resent this message up to the limit and
+ * eventually gave up. The caller may choose to not
+ * use lvmetad at this point and revert to scanning.
+ */
+
+ log_warn("WARNING: lvmetad is being updated and cannot be used.");
+ goto fail;
+
+ } else if (!daemon_in_update && we_are_in_update) {
+
+ /*
+ * We are updating lvmetad after setting the token to
+ * "update in progress", but lvmetad has a non-update
+ * token and is rejecting our update messages. This
+ * must mean that lvmetad cancelled our update (we were
+ * probably too slow, taking longer than the timeout),
+ * so another command completed an update and set the
+ * token based on its filter. Here we've attempt to
+ * continue our cache update, and find we've been
+ * preempted, so we should just abort our failed
+ * update.
+ */
+
+ log_warn("WARNING: lvmetad was updated by another command.");
+ /* We don't care if the action was modifying during a token update. */
+ action_modifies = 0;
+ goto fail;
+
+ } else if (!daemon_in_update && !we_are_in_update) {
+
/*
- * lvmetad is caching different devices based on a different
- * device filter which causes a token mismatch.
+ * Another command has updated the lvmetad cache, and
+ * has done so using a different device filter from our
+ * own, which has made the lvmetad token and our token
+ * not match. This should not usually happen because
+ * this command has already checked for a matching token
+ * in lvmetad_token_matches(), but it's possible for
+ * another command's rescan to slip in between the time
+ * we call lvmetad_token_matches() and the time we get
+ * here to lvmetad_send(). With a mismatched token
+ * (different set of devices), we cannot use the lvmetad
+ * cache.
+ *
+ * FIXME: it would be nice to have this command ignore
+ * lvmetad at this point and revert to disk scanning,
+ * but the layers above lvmetad_send are not yet able
+ * to switch modes in the middle of processing.
+ *
+ * (The advantage of lvmetad_check_token is that it
+ * can rescan to get the token in sync, or if that
+ * fails it can make the command revert to scanning
+ * from the start.)
*/
- log_error("Request to %s %s%sin lvmetad failed after device filter mismatch.",
- action, object, *object ? " " : "");
+
+ log_warn("WARNING: Cannot use lvmetad while it caches different devices.");
+ goto fail;
}
- goto fail;
}
+ /*
+ * Non-token-mismatch related error checking.
+ */
+
/* All OK? */
if (!strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
if (found)
@@ -634,14 +800,20 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
daemon_reply_str(reply, "reason", "<missing>"));
fail:
/*
- * If the failed lvmetad message was updating lvmetad, it is important
- * to restart lvmetad (or at least rescan.)
- *
- * FIXME: attempt to set the disabled state in lvmetad here so that
- * commands will not use it until it's been properly repopulated.
+ * If the failed lvmetad message was updating lvmetad with new metadata
+ * that has been changed by this command, it is important to restart
+ * lvmetad (or at least rescan.) (An lvmetad update that is just
+ * scanning disks to populate the cache is not a problem, so we try to
+ * avoid printing a "corruption" warning in that case.)
*/
- if (action_modifies)
+
+ if (action_modifies) {
+ /*
+ * FIXME: experiment with killing the lvmetad process here, e.g.
+ * kill(_lvmetad_daemon_pid, SIGKILL);
+ */
log_warn("WARNING: To avoid corruption, restart lvmetad (or disable with use_lvmetad=0).");
+ }
return 0;
}
@@ -1617,7 +1789,6 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
struct _lvmetad_pvscan_baton baton;
/* Create a dummy instance. */
struct format_instance_ctx fic = { .type = 0 };
- struct metadata_area *mda;
if (!lvmetad_used()) {
log_error("Cannot proceed since lvmetad is not active.");
@@ -1644,24 +1815,15 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
log_warn("WARNING: Disabling lvmetad cache which does not support obsolete (lvm1) metadata.");
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_LVM1);
_found_lvm1_metadata = 1;
+ /*
+ * return 1 (success) so that we'll continue to populate lvmetad
+ * instead of leaving the update incomplete.
+ */
return 1;
}
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
- /*
- * LVM1 VGs have no MDAs and lvmcache_foreach_mda isn't worth fixing
- * to use pseudo-mdas for PVs.
- * Note that the single_device parameter also gets ignored and this code
- * can scan further devices.
- */
- if (!baton.vg && !(baton.fid->fmt->features & FMT_MDAS)) {
- /* This code seems to be unreachable */
- if ((mda = (struct metadata_area *)dm_list_first(&baton.fid->metadata_areas_in_use)))
- baton.vg = mda->ops->vg_read(baton.fid, lvmcache_vgname_from_info(info),
- mda, NULL, NULL, 1);
- }
-
if (!baton.vg)
lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
@@ -1758,12 +1920,12 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
if (!replacing_other_update && replaced_update) {
if (do_wait && !retries) {
retries = 1;
- log_warn("WARNING: lvmetad update in progress, retry update.");
+ log_warn("WARNING: lvmetad update in progress, retrying update.");
dev_iter_destroy(iter);
_lvmetad_token = future_token;
goto retry;
}
- log_error("Concurrent lvmetad updates failed.");
+ log_warn("WARNING: lvmetad update in progress, skipping update.");
dev_iter_destroy(iter);
_lvmetad_token = future_token;
return 0;
@@ -1784,8 +1946,12 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
stack;
break;
}
- if (!lvmetad_pvscan_single(cmd, dev, NULL, NULL))
+
+ if (!lvmetad_pvscan_single(cmd, dev, NULL, NULL)) {
ret = 0;
+ stack;
+ break;
+ }
}
init_silent(was_silent);
@@ -1793,6 +1959,17 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
dev_iter_destroy(iter);
_lvmetad_token = future_token;
+
+ /*
+ * If we failed to fully and successfully populate lvmetad just leave
+ * the existing "update in progress" token in place so lvmetad will
+ * time out our update and force another command to do it.
+ * (We could try to set the token to empty here, but that doesn't
+ * help much.)
+ */
+ if (!ret)
+ return 0;
+
if (!_token_update(NULL)) {
log_error("Failed to update lvmetad token after device scan.");
return 0;
@@ -1802,7 +1979,7 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
* If lvmetad is disabled, and no lvm1 metadata was seen and no
* duplicate PVs were seen, then re-enable lvmetad.
*/
- if (ret && lvmetad_is_disabled(cmd, &reason) &&
+ if (lvmetad_is_disabled(cmd, &reason) &&
!lvmcache_found_duplicate_pvs() && !_found_lvm1_metadata) {
log_debug_lvmetad("Enabling lvmetad which was previously disabled.");
lvmetad_clear_disabled(cmd);
@@ -1820,6 +1997,7 @@ int lvmetad_vg_clear_outdated_pvs(struct volume_group *vg)
if (!id_write_format(&vg->id, uuid, sizeof(uuid)))
return_0;
+ log_debug_lvmetad("Sending lvmetad vg_clear_outdated_pvs");
reply = _lvmetad_send(vg->cmd, "vg_clear_outdated_pvs", "vgid = %s", uuid, NULL);
result = _lvmetad_handle_reply(reply, "vg_clear_outdated_pvs", vg->name, NULL);
daemon_reply_destroy(reply);
@@ -2057,6 +2235,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error) {
@@ -2115,6 +2295,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
reply = daemon_send_simple(_lvmetad, "set_global_info",
"token = %s", "skip",
"global_invalid = " FMTd64, INT64_C(0),
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error)
log_error("lvmetad_validate_global_cache set_global_info error %d", reply.error);
@@ -2161,6 +2343,7 @@ int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const cha
if (!id_write_format((const struct id*)vgid, uuid, sizeof(uuid)))
return_0;
+ log_debug_lvmetad("Sending lvmetad vg_clear_outdated_pvs");
reply = _lvmetad_send(cmd, "vg_lookup",
"uuid = %s", uuid,
"name = %s", vgname,
@@ -2321,12 +2504,14 @@ void lvmetad_set_disabled(struct cmd_context *cmd, const char *reason)
if (!_lvmetad_use)
return;
- log_debug_lvmetad("lvmetad send disabled %s", reason);
+ log_debug_lvmetad("Sending lvmetad disabled %s", reason);
reply = daemon_send_simple(_lvmetad, "set_global_info",
"token = %s", "skip",
"global_disable = " FMTd64, (int64_t)1,
"disable_reason = %s", reason,
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error)
log_error("Failed to send message to lvmetad %d", reply.error);
@@ -2344,11 +2529,13 @@ void lvmetad_clear_disabled(struct cmd_context *cmd)
if (!_lvmetad_use)
return;
- log_debug_lvmetad("lvmetad send disabled 0");
+ log_debug_lvmetad("Sending lvmetad disabled 0");
reply = daemon_send_simple(_lvmetad, "set_global_info",
"token = %s", "skip",
"global_disable = " FMTd64, (int64_t)0,
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error)
log_error("Failed to send message to lvmetad %d", reply.error);
@@ -2367,6 +2554,8 @@ int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason)
reply = daemon_send_simple(_lvmetad, "get_global_info",
"token = %s", "skip",
+ "pid = " FMTd64, (int64_t)getpid(),
+ "cmd = %s", get_cmd_name(),
NULL);
if (reply.error) {
7 years, 11 months
master - lvmetad: remove disabled case for "scan error"
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=851ccfccaf3dae...
Commit: 851ccfccaf3dae184e0bd5f222bdcfcef33fa3b8
Parent: 0e7f352c70decb779508b038a22e87c8e3f58b61
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed May 25 16:10:46 2016 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 7 10:17:00 2016 -0500
lvmetad: remove disabled case for "scan error"
Failures while populating lvmetad will be handling
differently in a subsequent commit.
---
daemons/lvmetad/lvmetad-client.h | 1 -
daemons/lvmetad/lvmetad-core.c | 10 +++-------
lib/cache/lvmetad.c | 6 ------
3 files changed, 3 insertions(+), 14 deletions(-)
diff --git a/daemons/lvmetad/lvmetad-client.h b/daemons/lvmetad/lvmetad-client.h
index 47eb6b4..b352c04 100644
--- a/daemons/lvmetad/lvmetad-client.h
+++ b/daemons/lvmetad/lvmetad-client.h
@@ -24,7 +24,6 @@
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
-#define LVMETAD_DISABLE_REASON_SCANERROR "SCANERROR"
struct volume_group;
diff --git a/daemons/lvmetad/lvmetad-core.c b/daemons/lvmetad/lvmetad-core.c
index f9d0d4c..51db92f 100644
--- a/daemons/lvmetad/lvmetad-core.c
+++ b/daemons/lvmetad/lvmetad-core.c
@@ -202,9 +202,8 @@ struct vg_info {
#define GLFL_DISABLE_REASON_DIRECT 0x00000004
#define GLFL_DISABLE_REASON_LVM1 0x00000008
#define GLFL_DISABLE_REASON_DUPLICATES 0x00000010
-#define GLFL_DISABLE_REASON_SCANERROR 0x00000020
-#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES | GLFL_DISABLE_REASON_SCANERROR)
+#define GLFL_DISABLE_REASON_ALL (GLFL_DISABLE_REASON_DIRECT | GLFL_DISABLE_REASON_LVM1 | GLFL_DISABLE_REASON_DUPLICATES)
#define VGFL_INVALID 0x00000001
@@ -2333,8 +2332,6 @@ static response set_global_info(lvmetad_state *s, request r)
reason_flags |= GLFL_DISABLE_REASON_LVM1;
if (strstr(reason, LVMETAD_DISABLE_REASON_DUPLICATES))
reason_flags |= GLFL_DISABLE_REASON_DUPLICATES;
- if (strstr(reason, LVMETAD_DISABLE_REASON_SCANERROR))
- reason_flags |= GLFL_DISABLE_REASON_SCANERROR;
}
if (global_invalid != -1) {
@@ -2388,11 +2385,10 @@ static response get_global_info(lvmetad_state *s, request r)
memset(reason, 0, sizeof(reason));
if (s->flags & GLFL_DISABLE) {
- snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s%s",
+ snprintf(reason, REASON_BUF_SIZE - 1, "%s%s%s",
(s->flags & GLFL_DISABLE_REASON_DIRECT) ? LVMETAD_DISABLE_REASON_DIRECT "," : "",
(s->flags & GLFL_DISABLE_REASON_LVM1) ? LVMETAD_DISABLE_REASON_LVM1 "," : "",
- (s->flags & GLFL_DISABLE_REASON_DUPLICATES) ? LVMETAD_DISABLE_REASON_DUPLICATES "," : "",
- (s->flags & GLFL_DISABLE_REASON_SCANERROR) ? LVMETAD_DISABLE_REASON_SCANERROR "," : "");
+ (s->flags & GLFL_DISABLE_REASON_DUPLICATES) ? LVMETAD_DISABLE_REASON_DUPLICATES "," : "");
}
if (!reason[0])
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index a87c952..bb86e88 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -1792,9 +1792,6 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
dev_iter_destroy(iter);
- if (!ret)
- lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_SCANERROR);
-
_lvmetad_token = future_token;
if (!_token_update(NULL)) {
log_error("Failed to update lvmetad token after device scan.");
@@ -2401,9 +2398,6 @@ int lvmetad_is_disabled(struct cmd_context *cmd, const char **reason)
} else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_DUPLICATES)) {
*reason = "duplicate PVs were found";
- } else if (strstr(reply_reason, LVMETAD_DISABLE_REASON_SCANERROR)) {
- *reason = "scanning devices failed";
-
} else {
*reason = "<unknown>";
}
7 years, 11 months
master - lvmetad: define special update in progress string
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0e7f352c70decb...
Commit: 0e7f352c70decb779508b038a22e87c8e3f58b61
Parent: 7ae05adf462b8de4428f32600fb43583dce5009a
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu May 19 16:19:38 2016 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jun 7 10:17:00 2016 -0500
lvmetad: define special update in progress string
---
daemons/lvmetad/lvmetad-client.h | 2 ++
lib/cache/lvmetad.c | 12 ++++++------
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/daemons/lvmetad/lvmetad-client.h b/daemons/lvmetad/lvmetad-client.h
index 1376e6b..47eb6b4 100644
--- a/daemons/lvmetad/lvmetad-client.h
+++ b/daemons/lvmetad/lvmetad-client.h
@@ -19,6 +19,8 @@
#define LVMETAD_SOCKET DEFAULT_RUN_DIR "/lvmetad.socket"
+#define LVMETAD_TOKEN_UPDATE_IN_PROGRESS "update in progress"
+
#define LVMETAD_DISABLE_REASON_DIRECT "DIRECT"
#define LVMETAD_DISABLE_REASON_LVM1 "LVM1"
#define LVMETAD_DISABLE_REASON_DUPLICATES "DUPLICATES"
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 6f914b2..a87c952 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -286,7 +286,7 @@ retry:
* the update message so that callers could detect when a rescan has
* stalled while updating lvmetad.
*/
- if (!strcmp(daemon_token, "update in progress")) {
+ if (!strcmp(daemon_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
if (!(now = _monotonic_seconds()))
goto fail;
@@ -370,7 +370,7 @@ retry:
if (!(daemon_token = daemon_reply_str(reply, "token", NULL)))
goto out;
- if (!strcmp(daemon_token, "update in progress")) {
+ if (!strcmp(daemon_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
ret = 1;
if (!do_wait)
@@ -441,7 +441,7 @@ retry:
goto out;
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
- if (!strcmp(daemon_reply_str(reply, "expected", ""), "update in progress")) {
+ if (!strcmp(daemon_reply_str(reply, "expected", ""), LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
/*
* Another command is updating the lvmetad cache, and
* we cannot use lvmetad until the update is finished.
@@ -520,7 +520,7 @@ static int _token_update(int *replaced_update)
}
if ((prev_token = daemon_reply_str(reply, "prev_token", NULL))) {
- if (!strcmp(prev_token, "update in progress"))
+ if (!strcmp(prev_token, LVMETAD_TOKEN_UPDATE_IN_PROGRESS))
if (replaced_update)
*replaced_update = 1;
}
@@ -583,7 +583,7 @@ static int _lvmetad_handle_reply(daemon_reply reply, const char *id, const char
* See the description of the token mismatch errors in lvmetad_send.
*/
if (!strcmp(daemon_reply_str(reply, "response", ""), "token_mismatch")) {
- if (!strcmp(daemon_reply_str(reply, "expected", ""), "update in progress")) {
+ if (!strcmp(daemon_reply_str(reply, "expected", ""), LVMETAD_TOKEN_UPDATE_IN_PROGRESS)) {
/*
* lvmetad_send retried up to the limit and eventually
* printed a warning and gave up.
@@ -1739,7 +1739,7 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
}
future_token = _lvmetad_token;
- _lvmetad_token = (char *) "update in progress";
+ _lvmetad_token = (char *) LVMETAD_TOKEN_UPDATE_IN_PROGRESS;
if (!_token_update(&replaced_update)) {
log_error("Failed to update lvmetad which had an update in progress.");
7 years, 11 months
master - blkdeactivate: fix regression in blkdeactivate causing dm and md devices to be skipped.
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=7ae05adf462b8d...
Commit: 7ae05adf462b8de4428f32600fb43583dce5009a
Parent: 7c894911aee47662e8f85f4458d65baea97eb058
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Mon Jun 6 14:57:41 2016 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Mon Jun 6 14:57:46 2016 +0200
blkdeactivate: fix regression in blkdeactivate causing dm and md devices to be skipped.
Commit #5b3a4a9 caused the "name" variable to be cleared if
declaration and assignment is on two lines so put it back
so it's on one line for it to work again.
---
WHATS_NEW | 1 +
scripts/blkdeactivate.sh.in | 6 ++----
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/WHATS_NEW b/WHATS_NEW
index c1b90af..2e7e138 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
Version 2.02.156 -
================================
+ Fix regression in blkdeactivate causing dm and md devices to be skipped. (2.02.155)
Version 2.02.155 - 3rd June 2016
================================
diff --git a/scripts/blkdeactivate.sh.in b/scripts/blkdeactivate.sh.in
index 2a48b3e..b4c3237 100644
--- a/scripts/blkdeactivate.sh.in
+++ b/scripts/blkdeactivate.sh.in
@@ -193,8 +193,7 @@ deactivate_holders () {
}
deactivate_dm () {
- local name
- name=$(printf "%s" "$name")
+ local name=$(printf "%s" "$name")
test -b "$DEV_DIR/mapper/$name" || return 0
test -z ${SKIP_DEVICE_LIST["$kname"]} || return 1
@@ -263,8 +262,7 @@ deactivate_lvm () {
}
deactivate_md () {
- local name
- name=$(printf "%s" "$name")
+ local name=$(printf "%s" "$name")
test -b "$DEV_DIR/$name" || return 0
test -z ${SKIP_DEVICE_LIST["$kname"]} || return 1
7 years, 11 months
v2_02_155 annotated tag has been created
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d0af97e64d143d...
Commit: d0af97e64d143d466013d7480ec3abd4e34b82ef
Parent: 0000000000000000000000000000000000000000
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: 2016-06-03 22:17 +0000
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: 2016-06-03 22:17 +0000
annotated tag: v2_02_155 has been created
at d0af97e64d143d466013d7480ec3abd4e34b82ef (tag)
tagging 767c9d653eb9c6deec576c23823781c6f184dea0 (commit)
replaces v2_02_154
Release 2.02.155.
A development release with an assortment of small enhancements and fixes
including limited support for striping using the dm-raid raid0 target.
97 files changed, 1964 insertions(+), 1288 deletions(-)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.14 (GNU/Linux)
iEYEABECAAYFAldSApEACgkQIoGRwVZ+LBfzhwCfbtZNyjFQjV2vjlLQxCEcPD24
pZQAoIWjo4ahEadsLS2lri2dfSGNoxiE
=QAhm
-----END PGP SIGNATURE-----
Alasdair G Kergon (8):
post-release
raid0: Add raid0 segment type.
raid0: Standardise meta_areas checks before access.
raid10: Fix new use of area multiple calc.
metadata: Tidy merge.c
raid: Revert _lv_extend_layered_lv non-raid0 area_multiple.
Revert "libdm: trace missing settings"
pre-release
David Teigland (16):
python: move lvm_init
lvmetad: add request level thread locking
lvmetad: remove old thread locking
pvremove: allow clearing a duplicate PV
liblvm: allow config settings to be read without full lvm cmd
lvm2_activation_generator: don't create full context for liblvm2app
WHATS_NEW: include recent changes
tools: improve error message about VG name and select
toollib: add vg name list arg to process_each_vg
pvscan: use process_each_vg for autoactivate
test: lvmetad-pvscan-filter
test: lvmetad-disabled
lvconvert: use process_each_lv
vgreduce: use process_each_vg
WHATS_NEW: include recent changes
pvmove: disallow tag args
Peter Rajnoha (12):
refactor: split _report fn further into init and config part
toollib: simplify internal selection calls for non-reporting tools
report: fix lvm devtypes internal error if -S is used with field name from pvs/vgs/lvs
toollib: properly reset selection handle on selection failure in select_match_{pv,vg,lv}
tests: add dmstats to CLEAN_TARGETS for make clean
coverity: fix possible resource leak of descendants_buffer in _print_historical_lv fn
coverity: blkdeactivate: separate format and args for printf and declare and assign separately to avoid masking return values
coverity: missing check for id_write_format return value
coverity: fix warnings about missing return value check for sscanf
make: add generated parts of lvmdbusd to DISTCLEAN_TARGETS for make distclean
lvmconfig: fix lvmconfig --type diff to display complete diff if config cascade used
man: lvmconfig: add note about --type diff and --mergedconfig
Tobias Stoeckmann (1):
man: fixed typo in lvcreate.8
Zdenek Kabelac (28):
libdm: cache status reports passthrough cache mode
libdm: trace missing settings
lvchange: allow change of cache mode
debug: use display_lvname
tests: test change of cache mode
report: fix report copy_percent value
snapshot: check merging_cow is cow
setup_task: add with_flush
cache: call status only on cache pool in use
cache: enhance lv_cache_wait_for_clean
cleanup: substract integers
cleanup: drop cmd and constify lv for lv_refresh_suspend_resume()
refresh: call resume after failing suspend
lvstatus: enhance seg_status to handle snapshot
lv: introduce lvseg_percent_with_info_and_seg_status
snapshot: use seg_status for attrs
report: convert more options to use single status
cache: add log_error on error path
debug: use display_lvname
tests: check cache_mode change on cachepool
tests: stacked snapshot merge
snapshot: for invalid snapshot show 100%
tests: check thin is not flushed for status
devices: handle partscan loop devices
tests: extend prepare_loop
tests: check losetup -P is correctly handled
cleanup: use display_name
cleanup: compile fixes for --disable-devmapper
7 years, 11 months
master - post-release
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=7c894911aee476...
Commit: 7c894911aee47662e8f85f4458d65baea97eb058
Parent: 767c9d653eb9c6deec576c23823781c6f184dea0
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Fri Jun 3 23:20:43 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Jun 3 23:20:43 2016 +0100
post-release
---
VERSION | 2 +-
VERSION_DM | 2 +-
WHATS_NEW | 3 +++
WHATS_NEW_DM | 3 +++
4 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/VERSION b/VERSION
index c233b09..e2b1146 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.02.155(2)-git (2016-06-03)
+2.02.156(2)-git (2016-06-03)
diff --git a/VERSION_DM b/VERSION_DM
index d4bffcd..fddb2ee 100644
--- a/VERSION_DM
+++ b/VERSION_DM
@@ -1 +1 @@
-1.02.126-git (2016-06-03)
+1.02.127-git (2016-06-03)
diff --git a/WHATS_NEW b/WHATS_NEW
index 2484ab2..c1b90af 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,3 +1,6 @@
+Version 2.02.156 -
+================================
+
Version 2.02.155 - 3rd June 2016
================================
Reject PV tags on pvmove cmdline because only 1 PV is supported. (2.02.141)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index a86940b..9c84854 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,3 +1,6 @@
+Version 1.02.127 -
+================================
+
Version 1.02.126 - 3rd June 2016
================================
Report passthrough caching mode when parsing cache mode.
7 years, 11 months
master - pre-release
by Alasdair Kergon
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=767c9d653eb9c6...
Commit: 767c9d653eb9c6deec576c23823781c6f184dea0
Parent: b321d2b1b9a3b6a1f8d67888a04c7318aa3148c2
Author: Alasdair G Kergon <agk(a)redhat.com>
AuthorDate: Fri Jun 3 23:16:50 2016 +0100
Committer: Alasdair G Kergon <agk(a)redhat.com>
CommitterDate: Fri Jun 3 23:16:50 2016 +0100
pre-release
---
VERSION | 2 +-
VERSION_DM | 2 +-
WHATS_NEW | 3 ++-
WHATS_NEW_DM | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/VERSION b/VERSION
index fc39fdb..c233b09 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.02.155(2)-git (2016-05-14)
+2.02.155(2)-git (2016-06-03)
diff --git a/VERSION_DM b/VERSION_DM
index fbe453d..d4bffcd 100644
--- a/VERSION_DM
+++ b/VERSION_DM
@@ -1 +1 @@
-1.02.126-git (2016-05-14)
+1.02.126-git (2016-06-03)
diff --git a/WHATS_NEW b/WHATS_NEW
index 92b95c0..2484ab2 100644
--- a/WHATS_NEW
+++ b/WHATS_NEW
@@ -1,5 +1,6 @@
-Version 2.02.155 -
+Version 2.02.155 - 3rd June 2016
================================
+ Reject PV tags on pvmove cmdline because only 1 PV is supported. (2.02.141)
Fix compilation error when building with configure --disable-devmapper.
Fix lvmconfig --type diff to display complete diff if config cascade used.
Automatically filter out partitioned loop devices with partscan (losetup -P).
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index d446997..a86940b 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,4 +1,4 @@
-Version 1.02.126 -
+Version 1.02.126 - 3rd June 2016
================================
Report passthrough caching mode when parsing cache mode.
7 years, 11 months
master - pvmove: disallow tag args
by David Teigland
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=b321d2b1b9a3b6...
Commit: b321d2b1b9a3b6a1f8d67888a04c7318aa3148c2
Parent: 68e097972462e3c7c208ac34c62e737b161dd3c4
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Fri Jun 3 09:56:48 2016 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Jun 3 09:56:48 2016 -0500
pvmove: disallow tag args
pvmove began processing tags unintentionally from commit,
6d7dc87cb pvmove: use toollib
pvmove works on a single PV, but tags can match multiple PVs.
If we allowed tags, but processed only the first matching PV,
then the resulting PV would be unpredictable.
Also, the current processing code does not allow us to simply
report an error and do nothing if more than one PV matches the tag,
because the command starts processing PVs as they are found,
so it's too late to do nothing if a second PV matches.
---
tools/commands.h | 4 +++-
tools/toollib.c | 5 +++++
tools/tools.h | 2 ++
3 files changed, 10 insertions(+), 1 deletions(-)
diff --git a/tools/commands.h b/tools/commands.h
index da432a7..888f3a2 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -874,9 +874,11 @@ xx(pvdisplay,
select_ARG, separator_ARG, shared_ARG, short_ARG, sort_ARG, unbuffered_ARG,
units_ARG)
+/* ALL_VGS_IS_DEFAULT is for polldaemon to find pvmoves in-progress using process_each_vg. */
+
xx(pvmove,
"Move extents from one physical volume to another",
- ALL_VGS_IS_DEFAULT, /* For polldaemon to find pvmoves in-progress using process_each_vg. */
+ ALL_VGS_IS_DEFAULT | DISALLOW_TAG_ARGS,
"pvmove\n"
"\t[--abort]\n"
"\t[--alloc AllocationPolicy]\n"
diff --git a/tools/toollib.c b/tools/toollib.c
index 0de6ee8..0563fea 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -3375,6 +3375,11 @@ int process_each_pv(struct cmd_context *cmd,
return ret;
}
+ if ((cmd->command->flags & DISALLOW_TAG_ARGS) && !dm_list_empty(&arg_tags)) {
+ log_error("Tags cannot be used with this command.");
+ return ECMD_FAILED;
+ }
+
orphans_locked = lvmcache_vgname_is_locked(VG_ORPHANS);
process_all_pvs = dm_list_empty(&arg_pvnames) && dm_list_empty(&arg_tags);
diff --git a/tools/tools.h b/tools/tools.h
index 2abc750..8704749 100644
--- a/tools/tools.h
+++ b/tools/tools.h
@@ -114,6 +114,8 @@ struct arg_value_group_list {
#define NO_LVMETAD_AUTOSCAN 0x00000200
/* Command should process unused duplicate devices. */
#define ENABLE_DUPLICATE_DEVS 0x00000400
+/* Command does not accept tags as args. */
+#define DISALLOW_TAG_ARGS 0x00000800
/* a register of the lvm commands */
struct command {
7 years, 11 months
master - man: fixed typo in lvcreate.8
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=68e097972462e3...
Commit: 68e097972462e3c7c208ac34c62e737b161dd3c4
Parent: 8e4db009b8f215cb7f593f4b76a6f4bd4293e2ca
Author: Tobias Stoeckmann <tobias(a)stoeckmann.org>
AuthorDate: Mon May 30 23:13:40 2016 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jun 3 12:46:47 2016 +0200
man: fixed typo in lvcreate.8
It's supposed to be "smaller than" instead of "smaller then".
---
man/lvcreate.8.in | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/man/lvcreate.8.in b/man/lvcreate.8.in
index 8614cb1..c28bc41 100644
--- a/man/lvcreate.8.in
+++ b/man/lvcreate.8.in
@@ -261,7 +261,7 @@ and the default value is 4KiB.
For cache pools the value must a multiple of 32KiB
between 32KiB and 1GiB. The default is 64KiB.
When the size is specified with volume caching, it may not be smaller
-then cache pool creation chunk size was.
+than cache pool creation chunk size was.
.br
For thin pools the value must be a multiple of 64KiB
between 64KiB and 1GiB.
7 years, 11 months