master - label_scan: remove extra label scan and read for orphan PVs
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=79c4971210a6337563f...
Commit: 79c4971210a6337563ffa2fca08fb636423d93d4
Parent: 5f138f36040297d092977a3b547cdefffb5ac4e8
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Nov 6 12:09:52 2017 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:45 2018 -0500
label_scan: remove extra label scan and read for orphan PVs
When process_each_pv() calls vg_read() on the orphan VG, the
internal implementation was doing an unnecessary
lvmcache_label_scan() and two unnecessary label_read() calls
on each orphan. Some of those unnecessary label scans/reads
would sometimes be skipped due to caching, but the code was
always doing at least one unnecessary read on each orphan.
The common format_text case was also unecessarily calling into
the format-specific pv_read() function which actually did nothing.
By analyzing each case in which vg_read() was being called on
the orphan VG, we can say that all of the label scans/reads
in vg_read_orphans are unnecessary:
1. reporting commands: the information saved in lvmcache by
the original label scan can be reported. There is no advantage
to repeating the label scan on the orphans a second time before
reporting it.
2. pvcreate/vgcreate/vgextend: these all share a common
implementation in pvcreate_each_device(). That function
already rescans labels after acquiring the orphan VG lock,
which ensures that the command is using valid lvmcache
information.
---
lib/cache/lvmcache.c | 51 +++-----------
lib/cache/lvmcache.h | 4 +-
lib/format_text/format-text.c | 31 ---------
lib/metadata/metadata.c | 150 +++++++++++------------------------------
lib/metadata/metadata.h | 6 --
5 files changed, 54 insertions(+), 188 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index 47058cc..8e119b5 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -2454,56 +2454,29 @@ int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_insta
return 1;
}
-static int _get_pv_if_in_vg(struct lvmcache_info *info,
- struct physical_volume *pv)
-{
- char vgname[NAME_LEN + 1];
- char vgid[ID_LEN + 1];
-
- if (info->vginfo && info->vginfo->vgname &&
- !is_orphan_vg(info->vginfo->vgname)) {
- /*
- * get_pv_from_vg_by_id() may call
- * lvmcache_label_scan() and drop cached
- * vginfo so make a local copy of string.
- */
- (void) dm_strncpy(vgname, info->vginfo->vgname, sizeof(vgname));
- memcpy(vgid, info->vginfo->vgid, sizeof(vgid));
-
- if (get_pv_from_vg_by_id(info->fmt, vgname, vgid,
- info->dev->pvid, pv))
- return 1;
- }
-
- return 0;
-}
-
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
- struct physical_volume *pv,
- int scan_label_only)
+ struct volume_group *vg,
+ struct physical_volume *pv)
{
struct data_area_list *da;
-
- /* Have we already cached vgname? */
- if (!scan_label_only && _get_pv_if_in_vg(info, pv))
- return 1;
-
- /* Perform full scan (just the first time) and try again */
- if (!scan_label_only && !critical_section() && !full_scan_done()) {
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(info->fmt->cmd);
-
- if (_get_pv_if_in_vg(info, pv))
- return 1;
+
+ if (!info->label) {
+ log_error("No cached label for orphan PV %s", pv_dev_name(pv));
+ return 0;
}
- /* Orphan */
+ pv->label_sector = info->label->sector;
pv->dev = info->dev;
pv->fmt = info->fmt;
pv->size = info->device_size >> SECTOR_SHIFT;
pv->vg_name = FMT_TEXT_ORPHAN_VG_NAME;
memcpy(&pv->id, &info->dev->pvid, sizeof(pv->id));
+ if (!pv->size) {
+ log_error("PV %s size is zero.", dev_name(info->dev));
+ return 0;
+ }
+
/* Currently only support exactly one data area */
if (dm_list_size(&info->das) != 1) {
log_error("Must be exactly one data area (found %d) on PV %s",
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 826e91e..1b5379c 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -145,8 +145,8 @@ int lvmcache_fid_add_mdas(struct lvmcache_info *info, struct format_instance *fi
int lvmcache_fid_add_mdas_pv(struct lvmcache_info *info, struct format_instance *fid);
int lvmcache_fid_add_mdas_vg(struct lvmcache_vginfo *vginfo, struct format_instance *fid);
int lvmcache_populate_pv_fields(struct lvmcache_info *info,
- struct physical_volume *pv,
- int scan_label_only);
+ struct volume_group *vg,
+ struct physical_volume *pv);
int lvmcache_check_format(struct lvmcache_info *info, const struct format_type *fmt);
void lvmcache_del_mdas(struct lvmcache_info *info);
void lvmcache_del_das(struct lvmcache_info *info);
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 9538080..ee1f11d 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1593,36 +1593,6 @@ static uint64_t _metadata_locn_offset_raw(void *metadata_locn)
return mdac->area.start;
}
-static int _text_pv_read(const struct format_type *fmt, const char *pv_name,
- struct physical_volume *pv, int scan_label_only)
-{
- struct lvmcache_info *info;
- struct device *dev;
-
- if (!(dev = dev_cache_get(pv_name, fmt->cmd->filter)))
- return_0;
-
- if (lvmetad_used()) {
- 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, dev, 0);
- } else {
- struct label *label;
- if (!(label_read(dev, &label, UINT64_C(0))))
- return_0;
- info = label->info;
- }
-
- if (!info)
- return_0;
-
- if (!lvmcache_populate_pv_fields(info, pv, scan_label_only))
- return 0;
-
- return 1;
-}
-
static int _text_pv_initialise(const struct format_type *fmt,
struct pv_create_args *pva,
struct physical_volume *pv)
@@ -2471,7 +2441,6 @@ static struct format_instance *_text_create_text_instance(const struct format_ty
static struct format_handler _text_handler = {
.scan = _text_scan,
- .pv_read = _text_pv_read,
.pv_initialise = _text_pv_initialise,
.pv_setup = _text_pv_setup,
.pv_add_metadata_area = _text_pv_add_metadata_area,
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index b4ee204..570cbe6 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -38,10 +38,9 @@
#include <sys/param.h>
static struct physical_volume *_pv_read(struct cmd_context *cmd,
- struct dm_pool *pvmem,
- const char *pv_name,
- struct format_instance *fid,
- uint32_t warn_flags, int scan_label_only);
+ const struct format_type *fmt,
+ struct volume_group *vg,
+ struct lvmcache_info *info);
static int _alignment_overrides_default(unsigned long data_alignment,
unsigned long default_pe_align)
@@ -330,37 +329,6 @@ bad:
return NULL;
}
-int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
- const char *vgid, const char *pvid,
- struct physical_volume *pv)
-{
- struct volume_group *vg;
- struct pv_list *pvl;
- uint32_t warn_flags = WARN_PV_READ | WARN_INCONSISTENT;
- int r = 0, consistent = 0;
-
- if (!(vg = vg_read_internal(fmt->cmd, vg_name, vgid, warn_flags, &consistent))) {
- log_error("get_pv_from_vg_by_id: vg_read_internal failed to read VG %s",
- vg_name);
- return 0;
- }
-
- dm_list_iterate_items(pvl, &vg->pvs) {
- if (id_equal(&pvl->pv->id, (const struct id *) pvid)) {
- if (!_copy_pv(fmt->cmd->mem, pv, pvl->pv)) {
- log_error("internal PV duplication failed");
- r = 0;
- goto out;
- }
- r = 1;
- goto out;
- }
- }
-out:
- release_vg(vg);
- return r;
-}
-
static int _move_pv(struct volume_group *vg_from, struct volume_group *vg_to,
const char *pv_name, int enforce_pv_from_source)
{
@@ -3246,9 +3214,7 @@ static int _check_mda_in_use(struct metadata_area *mda, void *_in_use)
struct _vg_read_orphan_baton {
struct cmd_context *cmd;
struct volume_group *vg;
- uint32_t warn_flags;
- int consistent;
- int repair;
+ const struct format_type *fmt;
};
/*
@@ -3345,8 +3311,7 @@ static int _vg_read_orphan_pv(struct lvmcache_info *info, void *baton)
uint32_t ext_version;
uint32_t ext_flags;
- if (!(pv = _pv_read(b->vg->cmd, b->vg->vgmem, dev_name(lvmcache_device(info)),
- b->vg->fid, b->warn_flags, 0))) {
+ if (!(pv = _pv_read(b->cmd, b->fmt, b->vg, info))) {
stack;
return 1;
}
@@ -3453,10 +3418,22 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
vg->free_count = 0;
baton.cmd = cmd;
- baton.warn_flags = warn_flags;
+ baton.fmt = fmt;
baton.vg = vg;
- baton.consistent = 1;
- baton.repair = *consistent;
+
+ /*
+ * vg_read for a normal VG will rescan labels for all the devices
+ * in the VG, in case something changed on disk between the initial
+ * label scan and acquiring the VG lock. We don't rescan labels
+ * here because this is only called in two ways:
+ *
+ * 1. for reporting, in which case it doesn't matter if something
+ * changed between the label scan and printing the PVs here
+ *
+ * 2. pvcreate_each_device() for pvcreate//vgcreate/vgextend,
+ * which already does the label rescan after taking the
+ * orphan lock.
+ */
while ((pvl = (struct pv_list *) dm_list_first(&head.list))) {
dm_list_del(&pvl->list);
@@ -3468,7 +3445,6 @@ static struct volume_group *_vg_read_orphans(struct cmd_context *cmd,
if (!lvmcache_foreach_pv(vginfo, _vg_read_orphan_pv, &baton))
return_NULL;
- *consistent = baton.consistent;
return vg;
}
@@ -4686,86 +4662,40 @@ const char *find_vgname_from_pvname(struct cmd_context *cmd,
return find_vgname_from_pvid(cmd, pvid);
}
-/* FIXME Use label functions instead of PV functions */
static struct physical_volume *_pv_read(struct cmd_context *cmd,
- struct dm_pool *pvmem,
- const char *pv_name,
- struct format_instance *fid,
- uint32_t warn_flags, int scan_label_only)
+ const struct format_type *fmt,
+ struct volume_group *vg,
+ struct lvmcache_info *info)
{
struct physical_volume *pv;
- struct label *label;
- struct lvmcache_info *info;
- struct device *dev;
- const struct format_type *fmt;
- int found;
-
- if (!(dev = dev_cache_get(pv_name, cmd->filter)))
- return_NULL;
-
- if (lvmetad_used()) {
- info = lvmcache_info_from_pvid(dev->pvid, dev, 0);
- if (!info) {
- if (!lvmetad_pv_lookup_by_dev(cmd, dev, &found))
- return_NULL;
- if (!found) {
- if (warn_flags & WARN_PV_READ)
- log_error("No physical volume found in lvmetad cache for %s",
- pv_name);
- return NULL;
- }
- 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);
- return NULL;
- }
- }
- label = lvmcache_get_label(info);
- } else {
- if (!(label_read(dev, &label, UINT64_C(0)))) {
- if (warn_flags & WARN_PV_READ)
- log_error("No physical volume label read from %s",
- pv_name);
- return NULL;
- }
- info = (struct lvmcache_info *) label->info;
- }
+ struct device *dev = lvmcache_device(info);
- fmt = lvmcache_fmt(info);
-
- pv = _alloc_pv(pvmem, dev);
- if (!pv) {
- log_error("pv allocation for '%s' failed", pv_name);
+ if (!(pv = _alloc_pv(vg->vgmem, NULL))) {
+ log_error("pv allocation failed");
return NULL;
}
- pv->label_sector = label->sector;
-
- /* FIXME Move more common code up here */
- if (!(lvmcache_fmt(info)->ops->pv_read(lvmcache_fmt(info), pv_name, pv, scan_label_only))) {
- log_error("Failed to read existing physical volume '%s'",
- pv_name);
- goto bad;
+ if (fmt->ops->pv_read) {
+ /* format1 and pool */
+ if (!(fmt->ops->pv_read(fmt, dev_name(dev), pv, 0))) {
+ log_error("Failed to read existing physical volume '%s'", dev_name(dev));
+ goto bad;
+ }
+ } else {
+ /* format text */
+ if (!lvmcache_populate_pv_fields(info, vg, pv))
+ goto_bad;
}
- if (!pv->size)
- goto bad;
-
- if (!alloc_pv_segment_whole_pv(pvmem, pv))
+ if (!alloc_pv_segment_whole_pv(vg->vgmem, pv))
goto_bad;
- if (fid)
- lvmcache_fid_add_mdas(info, fid, (const char *) &pv->id, ID_LEN);
- else {
- lvmcache_fid_add_mdas(info, fmt->orphan_vg->fid, (const char *) &pv->id, ID_LEN);
- pv_set_fid(pv, fmt->orphan_vg->fid);
- }
-
+ lvmcache_fid_add_mdas(info, vg->fid, (const char *) &pv->id, ID_LEN);
+ pv_set_fid(pv, vg->fid);
return pv;
bad:
free_pv_fid(pv);
- dm_pool_free(pvmem, pv);
+ dm_pool_free(vg->vgmem, pv);
return NULL;
}
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 5b8d690..83983b4 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -371,12 +371,6 @@ uint32_t vg_bad_status_bits(const struct volume_group *vg, uint64_t status);
int add_pv_to_vg(struct volume_group *vg, const char *pv_name,
struct physical_volume *pv, int new_pv);
-
-/* Find a PV within a given VG */
-int get_pv_from_vg_by_id(const struct format_type *fmt, const char *vg_name,
- const char *vgid, const char *pvid,
- struct physical_volume *pv);
-
struct logical_volume *find_lv_in_vg_by_lvid(struct volume_group *vg,
const union lvid *lvid);
6 years
master - vgcreate: improve the use of label_scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=5f138f36040297d0929...
Commit: 5f138f36040297d092977a3b547cdefffb5ac4e8
Parent: e3e5beec74ac0037917f5e9a2693c6ccb16debac
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Oct 26 14:32:30 2017 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:45 2018 -0500
vgcreate: improve the use of label_scan
The old code was doing unnecessary label scans when
checking to see if the new VG name exists. A single
label_scan is sufficient if it is done after the
new VG lock is held.
---
tools/vgcreate.c | 28 ++++++++++++++++++++--------
1 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/tools/vgcreate.c b/tools/vgcreate.c
index af0c363..87a296f 100644
--- a/tools/vgcreate.c
+++ b/tools/vgcreate.c
@@ -26,7 +26,6 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
const char *clustered_message = "";
char *vg_name;
struct arg_value_group_list *current_group;
- uint32_t rc;
if (!argc) {
log_error("Please provide volume group name and "
@@ -66,17 +65,30 @@ int vgcreate(struct cmd_context *cmd, int argc, char **argv)
return_ECMD_FAILED;
cmd->lockd_gl_disable = 1;
- lvmcache_seed_infos_from_lvmetad(cmd);
-
/*
* Check if the VG name already exists. This should be done before
* creating PVs on any of the devices.
+ *
+ * When searching if a VG name exists, acquire the VG lock,
+ * then do the initial label scan which reads all devices and
+ * populates lvmcache with any VG name it finds. If the VG name
+ * we want to use exists, then the label scan will find it,
+ * and the fmt_from_vgname call (used to check if the name exists)
+ * will return non-NULL.
*/
- if ((rc = vg_lock_newname(cmd, vp_new.vg_name)) != SUCCESS) {
- if (rc == FAILED_EXIST)
- log_error("A volume group called %s already exists.", vp_new.vg_name);
- else
- log_error("Can't get lock for %s.", vp_new.vg_name);
+
+ if (!lock_vol(cmd, vp_new.vg_name, LCK_VG_WRITE, NULL)) {
+ log_error("Can't get lock for %s.", vp_new.vg_name);
+ return ECMD_FAILED;
+ }
+
+ lvmcache_force_next_label_scan();
+ lvmcache_label_scan(cmd); /* Does nothing when using lvmetad. */
+ lvmcache_seed_infos_from_lvmetad(cmd); /* Does nothing unless using lvmetad. */
+
+ if (lvmcache_fmt_from_vgname(cmd, vp_new.vg_name, NULL, 0)) {
+ unlock_vg(cmd, NULL, vp_new.vg_name);
+ log_error("A volume group called %s already exists.", vp_new.vg_name);
return ECMD_FAILED;
}
6 years
master - lvmetad: use new label_scan for update from pvscan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e3e5beec74ac0037917...
Commit: e3e5beec74ac0037917f5e9a2693c6ccb16debac
Parent: 9c71fa02144619a67993920cee2146fed820f49c
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 7 13:58:40 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:22:43 2018 -0500
lvmetad: use new label_scan for update from pvscan
Take advantage of the common implementation with aio
and reduced disk reads.
---
lib/cache/lvmetad.c | 38 ++++++++++++++++++++++++-------
lib/commands/toolcontext.h | 2 +-
lib/format_text/import_vsn1.c | 6 ++++-
tools/pvscan.c | 49 +++++++++++++++++++++++++++++++++++------
4 files changed, 77 insertions(+), 18 deletions(-)
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 552dbf0..81ba1b7 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -2240,9 +2240,12 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
struct label *label;
struct lvmcache_info *info;
struct _lvmetad_pvscan_baton baton;
+ const struct format_type *fmt;
/* Create a dummy instance. */
struct format_instance_ctx fic = { .type = 0 };
+ log_debug_lvmetad("Scan metadata from dev %s", dev_name(dev));
+
if (!lvmetad_used()) {
log_error("Cannot proceed since lvmetad is not active.");
return 0;
@@ -2253,23 +2256,31 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
return 1;
}
- if (!label_read(dev, &label, 0)) {
- log_print_unless_silent("No PV label found on %s.", dev_name(dev));
+ if (!(info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
+ log_print_unless_silent("No PV info found on %s for PVID %s.", dev_name(dev), dev->pvid);
+ if (!lvmetad_pv_gone_by_dev(dev))
+ goto_bad;
+ return 1;
+ }
+
+ if (!(label = lvmcache_get_label(info))) {
+ log_print_unless_silent("No PV label found for %s.", dev_name(dev));
if (!lvmetad_pv_gone_by_dev(dev))
goto_bad;
return 1;
}
- info = (struct lvmcache_info *) label->info;
+ fmt = lvmcache_fmt(info);
+ baton.cmd = cmd;
baton.vg = NULL;
- baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
+ baton.fid = fmt->ops->create_instance(fmt, &fic);
if (!baton.fid)
goto_bad;
- if (baton.fid->fmt->features & FMT_OBSOLETE) {
- lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+ if (fmt->features & FMT_OBSOLETE) {
+ fmt->ops->destroy_instance(baton.fid);
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;
@@ -2283,9 +2294,9 @@ int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
if (!baton.vg)
- lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+ fmt->ops->destroy_instance(baton.fid);
- if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, lvmcache_fmt(info),
+ if (!lvmetad_pv_found(cmd, (const struct id *) &dev->pvid, dev, fmt,
label->sector, baton.vg, found_vgnames, changed_vgnames)) {
release_vg(baton.vg);
goto_bad;
@@ -2351,6 +2362,13 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
replacing_other_update = 1;
}
+ label_scan(cmd);
+
+ if (lvmcache_found_duplicate_pvs()) {
+ log_warn("WARNING: Scan found duplicate PVs.");
+ return 0;
+ }
+
log_verbose("Scanning all devices to update lvmetad.");
if (!(iter = dev_iter_create(cmd->lvmetad_filter, 1))) {
@@ -2721,6 +2739,8 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
*/
_lvmetad_get_pv_cache_list(cmd, &pvc_before);
+ log_debug_lvmetad("Rescan all devices to validate global cache.");
+
/*
* Update the local lvmetad cache so it correctly reflects any
* changes made on remote hosts. (It's possible that this command
@@ -2789,7 +2809,7 @@ void lvmetad_validate_global_cache(struct cmd_context *cmd, int force)
_update_changed_pvs_in_udev(cmd, &pvc_before, &pvc_after);
}
- log_debug_lvmetad("Validating global lvmetad cache finished");
+ log_debug_lvmetad("Rescanned all devices");
}
int lvmetad_vg_is_foreign(struct cmd_context *cmd, const char *vgname, const char *vgid)
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index f04afec..d20cef1 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -167,8 +167,8 @@ struct cmd_context {
unsigned pv_notify:1;
unsigned activate_component:1; /* command activates component LV */
unsigned process_component_lvs:1; /* command processes also component LVs */
-
unsigned mirror_warn_printed:1; /* command already printed warning about non-monitored mirrors */
+ unsigned pvscan_cache_single:1;
/*
* Filtering.
*/
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index b41d83c..dee5379 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -221,7 +221,11 @@ static int _read_pv(struct format_instance *fid,
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
buffer[0] = '\0';
- log_error_once("Couldn't find device with uuid %s.", buffer);
+
+ if (fid->fmt->cmd && !fid->fmt->cmd->pvscan_cache_single)
+ log_error_once("Couldn't find device with uuid %s.", buffer);
+ else
+ log_debug_metadata("Couldn't find device with uuid %s.", buffer);
}
if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
diff --git a/tools/pvscan.c b/tools/pvscan.c
index 6581990..ab6ea0b 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -300,8 +300,10 @@ static int _pvscan_autoactivate(struct cmd_context *cmd, struct pvscan_aa_params
static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
{
struct pvscan_aa_params pp = { 0 };
+ struct dm_list single_devs;
struct dm_list found_vgnames;
struct device *dev;
+ struct device_list *devl;
const char *pv_name;
const char *reason = NULL;
int32_t major = -1;
@@ -434,8 +436,12 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
* to drop any devices that have left.)
*/
- if (argc || devno_args)
+ if (argc || devno_args) {
log_verbose("Scanning devices on command line.");
+ cmd->pvscan_cache_single = 1;
+ }
+
+ dm_list_init(&single_devs);
while (argc--) {
pv_name = *argv++;
@@ -453,8 +459,11 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
} else {
/* Add device path to lvmetad. */
log_debug("Scanning dev %s for lvmetad cache.", pv_name);
- if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
- add_errors++;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&single_devs, &devl->list);
}
} else {
if (sscanf(pv_name, "%d:%d", &major, &minor) != 2) {
@@ -471,8 +480,11 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
} else {
/* Add major:minor to lvmetad. */
log_debug("Scanning dev %d:%d for lvmetad cache.", major, minor);
- if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
- add_errors++;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&single_devs, &devl->list);
}
}
@@ -482,9 +494,20 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
}
}
+ if (!dm_list_empty(&single_devs)) {
+ label_scan_devs(cmd, &single_devs);
+
+ dm_list_iterate_items(devl, &single_devs) {
+ if (!lvmetad_pvscan_single(cmd, devl->dev, &found_vgnames, &pp.changed_vgnames))
+ add_errors++;
+ }
+ }
+
if (!devno_args)
goto activate;
+ dm_list_init(&single_devs);
+
/* Process any grouped --major --minor args */
dm_list_iterate_items(current_group, &cmd->arg_value_groups) {
major = grouped_arg_int_value(current_group->arg_values, major_ARG, major);
@@ -503,8 +526,11 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
} else {
/* Add major:minor to lvmetad. */
log_debug("Scanning dev %d:%d for lvmetad cache.", major, minor);
- if (!lvmetad_pvscan_single(cmd, dev, &found_vgnames, &pp.changed_vgnames))
- add_errors++;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+ devl->dev = dev;
+ dm_list_add(&single_devs, &devl->list);
}
if (sigint_caught()) {
@@ -513,6 +539,15 @@ static int _pvscan_cache(struct cmd_context *cmd, int argc, char **argv)
}
}
+ if (!dm_list_empty(&single_devs)) {
+ label_scan_devs(cmd, &single_devs);
+
+ dm_list_iterate_items(devl, &single_devs) {
+ if (!lvmetad_pvscan_single(cmd, devl->dev, &found_vgnames, &pp.changed_vgnames))
+ add_errors++;
+ }
+ }
+
/*
* In the process of scanning devices, lvmetad may have become
* disabled. If so, revert to scanning for the autoactivation step.
6 years
master - lvmetad: use new label_scan for update from lvmlockd
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=9c71fa02144619a6799...
Commit: 9c71fa02144619a67993920cee2146fed820f49c
Parent: 098c843c50cdcc2e4f4162037e1ff5975624f3e2
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Oct 26 10:58:23 2017 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:21:41 2018 -0500
lvmetad: use new label_scan for update from lvmlockd
When lvmlockd indicates that the lvmetad cache is out of
date because of changes by another node, lvmetad_pvscan_vg()
rescans the devices in the VG to update lvmetad. Use the
new label_scan in this function to use the common code and
take advantage of the new aio and reduced reads.
---
lib/cache/lvmetad.c | 435 +++++++++++++++++++++++++++++++++++----------------
1 files changed, 298 insertions(+), 137 deletions(-)
diff --git a/lib/cache/lvmetad.c b/lib/cache/lvmetad.c
index 4b7410c..552dbf0 100644
--- a/lib/cache/lvmetad.c
+++ b/lib/cache/lvmetad.c
@@ -39,7 +39,7 @@ static int64_t _lvmetad_update_timeout;
static int _found_lvm1_metadata = 0;
-static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg);
+static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg, const char *vgid, struct format_type *fmt);
static uint64_t _monotonic_seconds(void)
{
@@ -1093,14 +1093,17 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
* invalidated the cached vg.
*/
if (rescan) {
- if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg))) {
+ if (!(vg2 = _lvmetad_pvscan_vg(cmd, vg, vgid, fmt))) {
log_debug_lvmetad("VG %s from lvmetad not found during rescan.", vgname);
fid = NULL;
release_vg(vg);
vg = NULL;
goto out;
}
+ fid->ref_count++;
release_vg(vg);
+ fid->ref_count--;
+ fmt->ops->destroy_instance(fid);
vg = vg2;
fid = vg2->fid;
}
@@ -1108,14 +1111,14 @@ struct volume_group *lvmetad_vg_lookup(struct cmd_context *cmd, const char *vgna
dm_list_iterate_items(pvl, &vg->pvs) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
- goto_out; /* FIXME error path */
+ goto_out; /* FIXME: use an error path that disables lvmetad */
}
}
dm_list_iterate_items(pvl, &vg->pvs_outdated) {
if (!_pv_update_struct_pv(pvl->pv, fid)) {
vg = NULL;
- goto_out; /* FIXME error path */
+ goto_out; /* FIXME: use an error path that disables lvmetad */
}
}
@@ -1761,6 +1764,7 @@ int lvmetad_pv_gone_by_dev(struct device *dev)
*/
struct _lvmetad_pvscan_baton {
+ struct cmd_context *cmd;
struct volume_group *vg;
struct format_instance *fid;
};
@@ -1771,7 +1775,7 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
struct volume_group *vg;
if (mda_is_ignored(mda) ||
- !(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL, 1)))
+ !(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
return 1;
/* FIXME Also ensure contents match etc. */
@@ -1784,6 +1788,33 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
}
/*
+ * FIXME: handle errors and do proper comparison of metadata from each area
+ * like vg_read and fall back to real vg_read from disk if there's any problem.
+ */
+
+static int _lvmetad_pvscan_vg_single(struct metadata_area *mda, void *baton)
+{
+ struct _lvmetad_pvscan_baton *b = baton;
+ struct volume_group *vg = NULL;
+
+ if (mda_is_ignored(mda))
+ return 1;
+
+ if (!(vg = mda->ops->vg_read(b->fid, "", mda, NULL, NULL)))
+ return 1;
+
+ if (!b->vg)
+ b->vg = vg;
+ else if (vg->seqno > b->vg->seqno) {
+ release_vg(b->vg);
+ b->vg = vg;
+ } else
+ release_vg(vg);
+
+ return 1;
+}
+
+/*
* The lock manager may detect that the vg cached in lvmetad is out of date,
* due to something like an lvcreate from another host.
* This is limited to changes that only affect the vg (not global state like
@@ -1792,41 +1823,41 @@ static int _lvmetad_pvscan_single(struct metadata_area *mda, void *baton)
* the VG, and that PV may have been reused for another VG.
*/
-static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg)
+static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct volume_group *vg,
+ const char *vgid, struct format_type *fmt)
{
char pvid_s[ID_LEN + 1] __attribute__((aligned(8)));
char uuid[64] __attribute__((aligned(8)));
- struct label *label;
- struct volume_group *vg_ret = NULL;
- struct dm_config_tree *vgmeta_ret = NULL;
struct dm_config_tree *vgmeta;
struct pv_list *pvl, *pvl_new;
- struct device_list *devl, *devl_new, *devlsafe;
+ struct device_list *devl, *devlsafe;
struct dm_list pvs_scan;
struct dm_list pvs_drop;
- struct dm_list pvs_new;
+ struct lvmcache_vginfo *vginfo = NULL;
struct lvmcache_info *info = NULL;
struct format_instance *fid;
struct format_instance_ctx fic = { .type = 0 };
struct _lvmetad_pvscan_baton baton;
+ struct volume_group *save_vg;
+ struct dm_config_tree *save_meta;
struct device *save_dev = NULL;
uint32_t save_seqno = 0;
- int missing_devs = 0;
- int check_new_pvs = 0;
+ int found_new_pvs = 0;
+ int retried_reads = 0;
int found;
+ save_vg = NULL;
+ save_meta = NULL;
+ save_dev = NULL;
+ save_seqno = 0;
+
dm_list_init(&pvs_scan);
dm_list_init(&pvs_drop);
- dm_list_init(&pvs_new);
- log_debug_lvmetad("Rescanning VG %s (seqno %u).", vg->name, vg->seqno);
+ log_debug_lvmetad("Rescan VG %s to update lvmetad (seqno %u).", vg->name, vg->seqno);
/*
- * Another host may have added a PV to the VG, and some
- * commands do not always populate their lvmcache with
- * all devs from lvmetad, so they would fail to find
- * the new PV when scanning the VG. So make sure this
- * command knows about all PVs from lvmetad.
+ * Make sure this command knows about all PVs from lvmetad.
*/
lvmcache_seed_infos_from_lvmetad(cmd);
@@ -1841,54 +1872,111 @@ static struct volume_group *_lvmetad_pvscan_vg(struct cmd_context *cmd, struct v
dm_list_add(&pvs_scan, &devl->list);
}
-scan_more:
+ /*
+ * Rescan labels/metadata only from devs that we previously
+ * saw in the VG. If we find below that there are new PVs
+ * in the VG, we'll have to rescan all devices to find which
+ * device(s) are now being used.
+ */
+ log_debug_lvmetad("Rescan VG %s scanning data from devs in previous metadata.", vg->name);
+
+ label_scan_devs(cmd, &pvs_scan);
/*
- * Run the equivalent of lvmetad_pvscan_single on each dev in the VG.
+ * Check if any pvs_scan entries are no longer PVs.
+ * In that case, label_read/_find_label_header will have
+ * found no label_header, and would have dropped the
+ * info struct for the device from lvmcache. So, if
+ * we look up the info struct here and don't find it,
+ * we can infer it's no longer a PV.
+ *
+ * FIXME: we should record specific results from the
+ * label_read and then check specifically for whatever
+ * result means "no label was found", rather than going
+ * about this indirectly via the lvmcache side effects.
*/
dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
- if (!devl->dev)
- continue;
+ if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
+ /* Another host removed this PV from the VG. */
+ log_debug_lvmetad("Rescan VG %s from %s dropping dev (no label).",
+ vg->name, dev_name(devl->dev));
+ dm_list_move(&pvs_drop, &devl->list);
+ }
+ }
- log_debug_lvmetad("Rescan VG %s scanning %s.", vg->name, dev_name(devl->dev));
+ fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
+ fic.context.vg_ref.vg_name = vg->name;
+ fic.context.vg_ref.vg_id = vgid;
- if (!label_read(devl->dev, &label, 0)) {
- /* Another host removed this PV from the VG. */
- log_debug_lvmetad("Rescan VG %s found %s was removed.", vg->name, dev_name(devl->dev));
+ retry_reads:
- if ((info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0)))
- lvmcache_del(info);
+ if (!(fid = fmt->ops->create_instance(fmt, &fic))) {
+ /* FIXME: are there only internal reasons for failures here? */
+ log_error("Reading VG %s failed to create format instance.", vg->name);
+ return NULL;
+ }
- dm_list_move(&pvs_drop, &devl->list);
- continue;
- }
+ /* FIXME: not sure if this is necessary */
+ fid->ref_count++;
- info = (struct lvmcache_info *) label->info;
+ baton.fid = fid;
+ baton.cmd = cmd;
- baton.vg = NULL;
- baton.fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
- if (!baton.fid)
- return_NULL;
+ /*
+ * FIXME: this vg_read path does not have the ability to repair
+ * any problems with the VG, e.g. VG on one dev has an older
+ * seqno. When vg_read() is reworked, we need to fall back
+ * to using that from here (and vg_read's from lvmetad) when
+ * there is a problem. Perhaps by disabling lvmetad when a
+ * VG problem is detected, causing commands to fully fall
+ * back to disk, which will repair the VG. Then lvmetad can
+ * be repopulated and re-enabled (possibly automatically.)
+ */
- if (baton.fid->fmt->features & FMT_OBSOLETE) {
- log_debug_lvmetad("Ignoring obsolete format on PV %s in VG %s.", dev_name(devl->dev), vg->name);
- lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+ /*
+ * Do a low level vg_read on each dev, verify the vg returned
+ * from metadata on each device is for the VG being read
+ * (the PV may have been removed from the VG being read and
+ * added to a different one), and return this vg to the caller
+ * as the current vg to use.
+ *
+ * The label scan above will have saved in lvmcache which
+ * vg each device is used in, so we could figure that part
+ * out without doing the vg_read.
+ */
+ dm_list_iterate_items_safe(devl, devlsafe, &pvs_scan) {
+ if (!devl->dev)
+ continue;
+
+ log_debug_lvmetad("Rescan VG %s getting metadata from %s.",
+ vg->name, dev_name(devl->dev));
+
+ /*
+ * The info struct for this dev knows what and where
+ * the mdas are for this dev (the label scan saved
+ * the mda locations for this dev on the lvmcache info struct).
+ */
+ if (!(info = lvmcache_info_from_pvid(devl->dev->pvid, devl->dev, 0))) {
+ log_debug_lvmetad("Rescan VG %s from %s dropping dev (no info).",
+ vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
continue;
}
+ baton.vg = NULL;
+
/*
* Read VG metadata from this dev's mdas.
*/
- lvmcache_foreach_mda(info, _lvmetad_pvscan_single, &baton);
+ lvmcache_foreach_mda(info, _lvmetad_pvscan_vg_single, &baton);
/*
* The PV may have been removed from the VG by another host
* since we last read the VG.
*/
if (!baton.vg) {
- log_debug_lvmetad("Rescan VG %s did not find %s.", vg->name, dev_name(devl->dev));
- lvmcache_fmt(info)->ops->destroy_instance(baton.fid);
+ log_debug_lvmetad("Rescan VG %s from %s dropping dev (no metadata).",
+ vg->name, dev_name(devl->dev));
dm_list_move(&pvs_drop, &devl->list);
continue;
}
@@ -1898,10 +1986,15 @@ scan_more:
* different VG since we last read the VG.
*/
if (strcmp(baton.vg->name, vg->name)) {
- log_debug_lvmetad("Rescan VG %s found different VG %s on PV %s.",
- vg->name, baton.vg->name, dev_name(devl->dev));
+ log_debug_lvmetad("Rescan VG %s from %s dropping dev (other VG %s).",
+ vg->name, dev_name(devl->dev), baton.vg->name);
+ release_vg(baton.vg);
+ continue;
+ }
+
+ if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
+ log_error("VG export to config tree failed");
release_vg(baton.vg);
- dm_list_move(&pvs_drop, &devl->list);
continue;
}
@@ -1911,20 +2004,35 @@ scan_more:
* read from each other dev.
*/
- if (!save_seqno)
- save_seqno = baton.vg->seqno;
-
- if (!(vgmeta = export_vg_to_config_tree(baton.vg))) {
- log_error("VG export to config tree failed");
- release_vg(baton.vg);
- return NULL;
+ if (save_vg && (save_seqno != baton.vg->seqno)) {
+ /* FIXME: fall back to vg_read to correct this. */
+ log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
+ vg->name, dev_name(save_dev), save_seqno,
+ dev_name(devl->dev), baton.vg->seqno);
+ log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
+
+ /* Use the most recent */
+ if (save_seqno < baton.vg->seqno) {
+ release_vg(save_vg);
+ dm_config_destroy(save_meta);
+ save_vg = baton.vg;
+ save_meta = vgmeta;
+ save_seqno = baton.vg->seqno;
+ save_dev = devl->dev;
+ } else {
+ release_vg(baton.vg);
+ dm_config_destroy(vgmeta);
+ }
+ continue;
}
- if (!vgmeta_ret) {
- vgmeta_ret = vgmeta;
+ if (!save_vg) {
+ save_vg = baton.vg;
+ save_meta = vgmeta;
+ save_seqno = baton.vg->seqno;
save_dev = devl->dev;
} else {
- struct dm_config_node *meta1 = vgmeta_ret->root;
+ struct dm_config_node *meta1 = save_meta->root;
struct dm_config_node *meta2 = vgmeta->root;
struct dm_config_node *sib1 = meta1->sib;
struct dm_config_node *sib2 = meta2->sib;
@@ -1949,73 +2057,128 @@ scan_more:
meta2->sib = NULL;
if (compare_config(meta1, meta2)) {
+ /* FIXME: fall back to vg_read to correct this. */
+ log_warn("WARNING: inconsistent metadata for VG %s on devices %s seqno %u and %s seqno %u.",
+ vg->name, dev_name(save_dev), save_seqno,
+ dev_name(devl->dev), baton.vg->seqno);
+ log_warn("WARNING: temporarily disable lvmetad to repair metadata.");
log_error("VG %s metadata comparison failed for device %s vs %s",
vg->name, dev_name(devl->dev), save_dev ? dev_name(save_dev) : "none");
- _log_debug_inequality(vg->name, vgmeta_ret->root, vgmeta->root);
+ _log_debug_inequality(vg->name, save_meta->root, vgmeta->root);
meta1->sib = sib1;
meta2->sib = sib2;
- dm_config_destroy(vgmeta);
- dm_config_destroy(vgmeta_ret);
+
+ /* no right choice, just use the previous copy */
release_vg(baton.vg);
- return NULL;
+ dm_config_destroy(vgmeta);
}
meta1->sib = sib1;
meta2->sib = sib2;
+ release_vg(baton.vg);
dm_config_destroy(vgmeta);
}
+ }
- /*
- * Look for any new PVs in the VG metadata that were not in our
- * previous version of the VG. Add them to pvs_new to be
- * scanned in this loop just like the old PVs.
- */
- if (!check_new_pvs) {
- check_new_pvs = 1;
- dm_list_iterate_items(pvl_new, &baton.vg->pvs) {
- found = 0;
- dm_list_iterate_items(pvl, &vg->pvs) {
- if (pvl_new->pv->dev != pvl->pv->dev)
- continue;
- found = 1;
- break;
- }
- if (found)
- continue;
- if (!pvl_new->pv->dev) {
- strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
- if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
- stack;
- log_error("Device not found for PV %s in VG %s", uuid, vg->name);
- missing_devs++;
+ /* FIXME: see above */
+ fid->ref_count--;
+
+ /*
+ * Look for any new PVs in the VG metadata that were not in our
+ * previous version of the VG.
+ *
+ * (Don't look for new PVs after a rescan and retry.)
+ */
+ found_new_pvs = 0;
+
+ if (save_vg && !retried_reads) {
+ dm_list_iterate_items(pvl_new, &save_vg->pvs) {
+ found = 0;
+ dm_list_iterate_items(pvl, &vg->pvs) {
+ if (pvl_new->pv->dev != pvl->pv->dev)
continue;
- }
- if (!(devl_new = dm_pool_zalloc(cmd->mem, sizeof(*devl_new))))
- return_NULL;
- devl_new->dev = pvl_new->pv->dev;
- dm_list_add(&pvs_new, &devl_new->list);
- log_debug_lvmetad("Rescan VG %s found %s was added.", vg->name, dev_name(devl_new->dev));
+ found = 1;
+ break;
+ }
+
+ /*
+ * PV in new VG metadata not found in old VG metadata.
+ * There's a good chance we don't know about this new
+ * PV or what device it's on; a label scan is needed
+ * of all devices so we know which device the VG is
+ * now using.
+ */
+ if (!found) {
+ found_new_pvs++;
+ strncpy(pvid_s, (char *) &pvl_new->pv->id, sizeof(pvid_s) - 1);
+ if (!id_write_format((const struct id *)&pvid_s, uuid, sizeof(uuid)))
+ stack;
+ log_debug_lvmetad("Rescan VG %s found new PV %s.", vg->name, uuid);
}
}
+ }
- release_vg(baton.vg);
+ if (!save_vg && retried_reads) {
+ log_error("VG %s not found after rescanning devices.", vg->name);
+ goto out;
}
/*
- * Do the same scanning above for any new PVs.
+ * Do a full rescan of devices, then look up which devices the
+ * scan found for this VG name, and select those devices to
+ * read metadata from in the loop above (rather than the list
+ * of devices we created from our last copy of the vg metadata.)
+ *
+ * Case 1: VG we knew is no longer on any of the devices we knew it
+ * to be on (save_vg is NULL, which means the metadata wasn't found
+ * when reading mdas on each of the initial pvs_scan devices).
+ * Rescan all devs and then retry reading metadata from the devs that
+ * the scan finds associated with this VG.
+ *
+ * Case 2: VG has new PVs but we don't know what devices they are
+ * so rescan all devs and then retry reading metadata from the devs
+ * that the scan finds associated with this VG.
+ *
+ * (N.B. after a retry, we don't check for found_new_pvs.)
*/
- if (!dm_list_empty(&pvs_new)) {
+ if (!save_vg || found_new_pvs) {
+ if (!save_vg)
+ log_debug_lvmetad("Rescan VG %s did not find VG on previous devs.", vg->name);
+ if (found_new_pvs)
+ log_debug_lvmetad("Rescan VG %s scanning all devs to find new PVs.", vg->name);
+
+ label_scan(cmd);
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vg->name, NULL))) {
+ log_error("VG %s vg info not found after rescanning devices.", vg->name);
+ goto out;
+ }
+
+ /*
+ * Set pvs_scan to devs that the label scan found
+ * in the VG and retry the metadata reading loop.
+ */
dm_list_init(&pvs_scan);
- dm_list_splice(&pvs_scan, &pvs_new);
- dm_list_init(&pvs_new);
- log_debug_lvmetad("Rescan VG %s found new PVs to scan.", vg->name);
- goto scan_more;
- }
- if (missing_devs) {
- if (vgmeta_ret)
- dm_config_destroy(vgmeta_ret);
- return_NULL;
+ if (!lvmcache_get_vg_devs(cmd, vginfo, &pvs_scan)) {
+ log_error("VG %s info devs not found after rescanning devices.", vg->name);
+ goto out;
+ }
+
+ log_debug_lvmetad("Rescan VG %s has %d PVs after label scan.",
+ vg->name, dm_list_size(&pvs_scan));
+
+ if (save_vg)
+ release_vg(save_vg);
+ if (save_meta)
+ dm_config_destroy(save_meta);
+ save_vg = NULL;
+ save_meta = NULL;
+ save_dev = NULL;
+ save_seqno = 0;
+ found_new_pvs = 0;
+ retried_reads = 1;
+ goto retry_reads;
}
/*
@@ -2024,52 +2187,50 @@ scan_more:
dm_list_iterate_items(devl, &pvs_drop) {
if (!devl->dev)
continue;
- log_debug_lvmetad("Rescan VG %s dropping %s.", vg->name, dev_name(devl->dev));
- if (!lvmetad_pv_gone_by_dev(devl->dev))
- return_NULL;
+ log_debug_lvmetad("Rescan VG %s removing %s from lvmetad.", vg->name, dev_name(devl->dev));
+ if (!lvmetad_pv_gone_by_dev(devl->dev)) {
+ /* FIXME: use an error path that disables lvmetad */
+ log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
+ }
}
/*
- * Update the VG in lvmetad.
+ * Update lvmetad with the newly read version of the VG.
+ * When the seqno is unchanged the cached VG can be left.
*/
- if (vgmeta_ret) {
- fid = lvmcache_fmt(info)->ops->create_instance(lvmcache_fmt(info), &fic);
- if (!(vg_ret = import_vg_from_config_tree(vgmeta_ret, fid))) {
- log_error("VG import from config tree failed");
- lvmcache_fmt(info)->ops->destroy_instance(fid);
- goto out;
+ if (save_vg && (save_seqno != vg->seqno)) {
+ dm_list_iterate_items(devl, &pvs_scan) {
+ if (!devl->dev)
+ continue;
+ log_debug_lvmetad("Rescan VG %s removing %s from lvmetad to replace.",
+ vg->name, dev_name(devl->dev));
+ if (!lvmetad_pv_gone_by_dev(devl->dev)) {
+ /* FIXME: use an error path that disables lvmetad */
+ log_error("Failed to remove %s from lvmetad.", dev_name(devl->dev));
+ }
}
+ log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
+ vg->name, vg->seqno, save_seqno);
+
/*
- * Update lvmetad with the newly read version of the VG.
- * When the seqno is unchanged the cached VG can be left.
+ * If this vg_update fails the cached metadata in
+ * lvmetad will remain invalid.
*/
- if (save_seqno != vg->seqno) {
- dm_list_iterate_items(devl, &pvs_scan) {
- if (!devl->dev)
- continue;
- log_debug_lvmetad("Rescan VG %s dropping to replace %s.", vg->name, dev_name(devl->dev));
- if (!lvmetad_pv_gone_by_dev(devl->dev))
- return_NULL;
- }
-
- log_debug_lvmetad("Rescan VG %s updating lvmetad from seqno %u to seqno %u.",
- vg->name, vg->seqno, save_seqno);
-
- /*
- * If this vg_update fails the cached metadata in
- * lvmetad will remain invalid.
- */
- vg_ret->lvmetad_update_pending = 1;
- if (!lvmetad_vg_update_finish(vg_ret))
- log_error("Failed to update lvmetad with new VG meta");
+ save_vg->lvmetad_update_pending = 1;
+ if (!lvmetad_vg_update_finish(save_vg)) {
+ /* FIXME: use an error path that disables lvmetad */
+ log_error("Failed to update lvmetad with new VG meta");
}
- dm_config_destroy(vgmeta_ret);
}
out:
- if (vg_ret)
- log_debug_lvmetad("Rescan VG %s done (seqno %u).", vg_ret->name, vg_ret->seqno);
- return vg_ret;
+ if (!save_vg && fid)
+ fmt->ops->destroy_instance(fid);
+ if (save_meta)
+ dm_config_destroy(save_meta);
+ if (save_vg)
+ log_debug_lvmetad("Rescan VG %s done (new seqno %u).", save_vg->name, save_vg->seqno);
+ return save_vg;
}
int lvmetad_pvscan_single(struct cmd_context *cmd, struct device *dev,
6 years
master - independent metadata areas: fix bogus code
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=098c843c50cdcc2e4f4...
Commit: 098c843c50cdcc2e4f4162037e1ff5975624f3e2
Parent: d9ef9eb330bdc66dd6d9b45713d5c0b25d645ac0
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Oct 25 13:55:22 2017 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:21:41 2018 -0500
independent metadata areas: fix bogus code
Fix mixing bitwise & and logical && which was
always 1 in any case.
---
lib/format_text/format-text.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 8c12c82..9538080 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1362,7 +1362,9 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
static int _text_scan(const struct format_type *fmt, const char *vgname)
{
- return (_scan_file(fmt, vgname) & _scan_raw(fmt, vgname));
+ _scan_file(fmt, vgname);
+ _scan_raw(fmt, vgname);
+ return 1;
}
struct _write_single_mda_baton {
6 years
master - label_scan: fix independent metadata areas
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d9ef9eb330bdc66dd6d...
Commit: d9ef9eb330bdc66dd6d9b45713d5c0b25d645ac0
Parent: 748f29b42a61e05fb696a86e04b4b589d70d6d79
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Oct 25 13:39:46 2017 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:21:41 2018 -0500
label_scan: fix independent metadata areas
This fixes the use of lvmcache_label_rescan_vg() in the previous
commit for the special case of independent metadata areas.
label scan is about discovering VG name to device associations
using information from disks, but devices in VGs with
independent metadata areas have no information on disk, so
the label scan does nothing for these VGs/devices.
With independent metadata areas, only the VG metadata found
in files is used. This metadata is found and read in
vg_read in the processing phase.
lvmcache_label_rescan_vg() drops lvmcache info for the VG devices
before repeating the label scan on them. In the case of
independent metadata areas, there is no metadata on devices, so the
label scan of the devices will find nothing, so will not recreate
the necessary vginfo/info data in lvmcache for the VG. Fix this
by setting a flag in the lvmcache vginfo struct indicating that
the VG uses independent metadata areas, and label rescanning should
be skipped.
In the case of independent metadata areas, it is the metadata
processing in the vg_read phase that sets up the lvmcache
vginfo/info information, and label scan has no role.
---
lib/format_text/format-text.c | 24 +++++++++++++++++++++++-
1 files changed, 23 insertions(+), 1 deletions(-)
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 6c13346..8c12c82 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1141,6 +1141,9 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
dir_list = &((struct mda_lists *) fmt->private)->dirs;
+ if (!dm_list_empty(dir_list))
+ log_debug_metadata("Scanning independent files for %s", vgname ? vgname : "VGs");
+
dm_list_iterate_items(dl, dir_list) {
if (!(d = opendir(dl->dir))) {
log_sys_error("opendir", dl->dir);
@@ -1173,10 +1176,14 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
stack;
break;
}
+
+ log_debug_metadata("Scanning independent file %s for VG %s", path, scanned_vgname);
+
if ((vg = _vg_read_file_name(fid, scanned_vgname,
path))) {
/* FIXME Store creation host in vg */
lvmcache_update_vg(vg, 0);
+ lvmcache_set_independent_location(vg->name);
release_vg(vg);
}
}
@@ -1302,6 +1309,8 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 1;
}
+/* used for independent_metadata_areas */
+
static int _scan_raw(const struct format_type *fmt, const char *vgname __attribute__((unused)))
{
struct raw_list *rl;
@@ -1313,11 +1322,16 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
raw_list = &((struct mda_lists *) fmt->private)->raws;
+ if (!dm_list_empty(raw_list))
+ log_debug_metadata("Scanning independent raw locations for %s", vgname ? vgname : "VGs");
+
fid.fmt = fmt;
dm_list_init(&fid.metadata_areas_in_use);
dm_list_init(&fid.metadata_areas_ignored);
dm_list_iterate_items(rl, raw_list) {
+ log_debug_metadata("Scanning independent dev %s", dev_name(rl->dev_area.dev));
+
/* FIXME We're reading mdah twice here... */
if (!dev_open_readonly(rl->dev_area.dev)) {
stack;
@@ -1331,8 +1345,10 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
if (read_metadata_location_summary(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0, 0);
- if (vg)
+ if (vg) {
lvmcache_update_vg(vg, 0);
+ lvmcache_set_independent_location(vg->name);
+ }
}
close_dev:
if (!dev_close(rl->dev_area.dev))
@@ -1342,6 +1358,8 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
return 1;
}
+/* used for independent_metadata_areas */
+
static int _text_scan(const struct format_type *fmt, const char *vgname)
{
return (_scan_file(fmt, vgname) & _scan_raw(fmt, vgname));
@@ -1796,6 +1814,8 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
.mda_import_text = _mda_import_text_raw
};
+/* used only for sending info to lvmetad */
+
static int _mda_export_text_raw(struct metadata_area *mda,
struct dm_config_tree *cft,
struct dm_config_node *parent)
@@ -1820,6 +1840,8 @@ static int _mda_export_text_raw(struct metadata_area *mda,
NULL) ? 1 : 0;
}
+/* used only for receiving info from lvmetad */
+
static int _mda_import_text_raw(struct lvmcache_info *info, const struct dm_config_node *cn)
{
struct device *device;
6 years
master - scan: do scanning at the start of a command
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=748f29b42a61e05fb69...
Commit: 748f29b42a61e05fb696a86e04b4b589d70d6d79
Parent: 4507ba3596a549697733e1b839f25af454ccf878
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 7 13:26:37 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:21:38 2018 -0500
scan: do scanning at the start of a command
Move the location of scans to make it clearer and avoid
unnecessary repeated scanning. There should be one scan
at the start of a command which is then used through the
rest of command processing.
Previously, the initial label scan was called as a side effect
from various utility functions. This would lead to it being called
unnecessarily. It is an expensive operation, and should only be
called when necessary. Also, this is a primary step in the
function of the command, and as such it should be called prominently
at the top level of command processing, not as a hidden side effect
of a utility function. lvm knows exactly where and when the
label scan needs to be done. Because of this, move the label scan
calls from the internal functions to the top level of processing.
Other specific instances of lvmcache_label_scan() are still called
unnecessarily or unclearly by specific commands that do not use
the common process_each functions. These will be improved in
future commits.
During the processing phase, rescanning labels for devices in a VG
needs to be done after the VG lock is acquired in case things have
changed since the initial label scan. This was being done by way
of rescanning devices that had the INVALID flag set in lvmcache.
This usually approximated the right set of devices, but it was not
exact, and obfuscated the real requirement. Correct this by using
a new function that rescans the devices in the VG:
lvmcache_label_rescan_vg().
Apart from being inexact, the rescanning was extremely well hidden.
_vg_read() would call ->create_instance(), _text_create_text_instance(),
_create_vg_text_instance() which would call lvmcache_label_scan()
which would call _scan_invalid() which repeats the label scan on
devices flagged INVALID. lvmcache_label_rescan_vg() is now called
prominently by _vg_read() directly.
---
lib/cache/lvmcache.c | 2 -
lib/format_text/format-text.c | 16 ----------
lib/metadata/metadata.c | 62 +++++++++++++++++++++++++++++++++--------
tools/toollib.c | 27 ++++++++++++-----
tools/vgcfgrestore.c | 2 +
5 files changed, 71 insertions(+), 38 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index c0b2202..47058cc 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -1436,8 +1436,6 @@ int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct vgnameid_list *vgnl;
struct lvmcache_vginfo *vginfo;
- lvmcache_label_scan(cmd);
-
dm_list_iterate_items(vginfo, &_vginfos) {
if (!include_internal && is_orphan_vg(vginfo->vgname))
continue;
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index c438b2d..6c13346 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -2049,22 +2049,6 @@ static int _create_vg_text_instance(struct format_instance *fid,
}
if (type & FMT_INSTANCE_MDAS) {
- /*
- * TODO in theory, this function should be never reached
- * while in critical_section(), because lvmcache's
- * cached_vg should be valid. However, this assumption
- * sometimes fails (possibly due to inconsistent
- * (precommit) metadata and/or missing devices), and
- * calling lvmcache_label_scan inside the critical
- * section may be fatal (i.e. deadlock).
- */
- if (!critical_section())
- /* Scan PVs in VG for any further MDAs */
- /*
- * FIXME Only scan PVs believed to be in the VG.
- */
- lvmcache_label_scan(fid->fmt->cmd);
-
if (!(vginfo = lvmcache_vginfo_from_vgname(vg_name, vg_id)))
goto_out;
if (!lvmcache_fid_add_mdas_vg(vginfo, fid))
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 00b7737..b4ee204 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -3859,20 +3859,28 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
correct_vg = NULL;
}
+ /*
+ * Rescan the devices that are associated with this vg in lvmcache.
+ * This repeats what was done by the command's initial label scan,
+ * but only the devices associated with this VG.
+ *
+ * The lvmcache info about these devs is from the initial label scan
+ * performed by the command before the vg lock was held. Now the VG
+ * lock is held, so we rescan all the info from the devs in case
+ * something changed between the initial scan and now that the lock
+ * is held.
+ */
+ log_debug_metadata("Reading VG rereading labels for %s", vgname);
- /* Find the vgname in the cache */
- /* If it's not there we must do full scan to be completely sure */
- if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
+ if (!lvmcache_label_rescan_vg(cmd, vgname, vgid)) {
+ /* The VG wasn't found, so force a full label scan. */
+ lvmcache_force_next_label_scan();
lvmcache_label_scan(cmd);
- if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 1))) {
- /* Independent MDAs aren't supported under low memory */
- if (!cmd->independent_metadata_areas && prioritized_section())
- return_NULL;
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(cmd);
- if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0)))
- return_NULL;
- }
+ }
+
+ if (!(fmt = lvmcache_fmt_from_vgname(cmd, vgname, vgid, 0))) {
+ log_debug_metadata("Cache did not find fmt for vgname %s", vgname);
+ return_NULL;
}
/* Now determine the correct vgname if none was supplied */
@@ -3890,6 +3898,36 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if (use_precommitted && !(fmt->features & FMT_PRECOMMIT))
use_precommitted = 0;
+ /*
+ * A "format instance" is an abstraction for a VG location,
+ * i.e. where a VG's metadata exists on disk.
+ *
+ * An fic (format_instance_ctx) is a temporary struct used
+ * to create an fid (format_instance). The fid hangs around
+ * and is used to create a 'vg' to which it connected (vg->fid).
+ *
+ * The 'fic' describes a VG in terms of fmt/name/id.
+ *
+ * The 'fid' describes a VG in more detail than the fic,
+ * holding information about where to find the VG metadata.
+ *
+ * The 'vg' describes the VG in the most detail representing
+ * all the VG metadata.
+ *
+ * The fic and fid are set up by create_instance() to describe
+ * the VG location. This happens before the VG metadata is
+ * assembled into the more familiar struct volume_group "vg".
+ *
+ * The fid has one main purpose: to keep track of the metadata
+ * locations for a given VG. It does this by putting 'mda'
+ * structs on fid->metadata_areas_in_use, which specify where
+ * metadata is located on disk. It gets this information
+ * (metadata locations for a specific VG) from the command's
+ * initial label scan. The info is passed indirectly via
+ * lvmcache info/vginfo structs, which are created by the
+ * label scan and then copied into fid by create_instance().
+ */
+
/* create format instance with appropriate metadata area */
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vgname;
diff --git a/tools/toollib.c b/tools/toollib.c
index 451f24d..1c216d8 100644
--- a/tools/toollib.c
+++ b/tools/toollib.c
@@ -2228,14 +2228,10 @@ int process_each_vg(struct cmd_context *cmd,
}
/*
- * First rescan for available devices, then force the next
- * label scan to be done. get_vgnameids() will scan labels
- * (when not using lvmetad).
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
*/
- if (cmd->cname->flags & REQUIRES_FULL_LABEL_SCAN) {
- dev_cache_full_scan(cmd->full_filter);
- lvmcache_force_next_label_scan();
- }
+ lvmcache_label_scan(cmd);
/*
* A list of all VGs on the system is needed when:
@@ -3745,6 +3741,12 @@ int process_each_lv(struct cmd_context *cmd,
}
/*
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
+ */
+ lvmcache_label_scan(cmd);
+
+ /*
* A list of all VGs on the system is needed when:
* . processing all VGs on the system
* . A VG name is specified which may refer to one
@@ -4453,7 +4455,12 @@ int process_each_pv(struct cmd_context *cmd,
if (!trust_cache() && !orphans_locked) {
log_debug("Scanning for available devices");
lvmcache_destroy(cmd, 1, 0);
- dev_cache_full_scan(cmd->full_filter);
+
+ /*
+ * Scan all devices to populate lvmcache with initial
+ * list of PVs and VGs.
+ */
+ lvmcache_label_scan(cmd);
}
if (!get_vgnameids(cmd, &all_vgnameids, only_this_vgname, 1)) {
@@ -5467,6 +5474,8 @@ int pvcreate_each_device(struct cmd_context *cmd,
dev_cache_full_scan(cmd->full_filter);
+ lvmcache_label_scan(cmd);
+
/*
* Translate arg names into struct device's.
*/
@@ -5621,6 +5630,8 @@ int pvcreate_each_device(struct cmd_context *cmd,
goto out;
}
+ lvmcache_label_scan(cmd);
+
/*
* The device args began on the arg_devices list, then the first check
* loop moved those entries to arg_process as they were found. Devices
diff --git a/tools/vgcfgrestore.c b/tools/vgcfgrestore.c
index b5a2add..e9f1a4c 100644
--- a/tools/vgcfgrestore.c
+++ b/tools/vgcfgrestore.c
@@ -74,6 +74,8 @@ int vgcfgrestore(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED;
}
+ lvmcache_label_scan(cmd);
+
cmd->handles_unknown_segments = 1;
if (!(arg_is_set(cmd, file_ARG) ?
6 years
master - scan: use new label_scan for lvmcache_label_scan
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=4507ba3596a54969773...
Commit: 4507ba3596a549697733e1b839f25af454ccf878
Parent: a7cb76ae94a90c89b86a810ceb4b6a91bab3441e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Wed Feb 7 13:14:08 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:19:32 2018 -0500
scan: use new label_scan for lvmcache_label_scan
To do label scanning, lvm code calls lvmcache_label_scan().
Change lvmcache_label_scan() to use the new label_scan()
based on bcache.
Also add lvmcache_label_rescan_vg() which calls the new
label_scan_devs() which does label scanning on only the
specified devices. This is for a subsequent commit and
is not yet used.
---
lib/cache/lvmcache.c | 234 ++++++++++++++++++++++++++++------------
lib/cache/lvmcache.h | 12 ++-
lib/format_text/format-text.c | 2 +-
lib/format_text/import_vsn1.c | 3 +-
lib/metadata/metadata-liblvm.c | 2 +-
5 files changed, 174 insertions(+), 79 deletions(-)
diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c
index fb81002..c0b2202 100644
--- a/lib/cache/lvmcache.c
+++ b/lib/cache/lvmcache.c
@@ -72,6 +72,7 @@ struct lvmcache_vginfo {
unsigned vg_use_count; /* Counter of vg reusage */
unsigned precommitted; /* Is vgmetadata live or precommitted? */
unsigned cached_vg_invalidated; /* Signal to regenerate cached_vg */
+ int independent_metadata_location; /* metadata read from independent areas */
};
static struct dm_hash_table *_pvid_hash = NULL;
@@ -542,7 +543,6 @@ const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
{
struct lvmcache_vginfo *vginfo;
struct lvmcache_info *info;
- struct label *label;
struct dm_list *devh, *tmp;
struct dm_list devs;
struct device_list *devl;
@@ -587,7 +587,7 @@ const struct format_type *lvmcache_fmt_from_vgname(struct cmd_context *cmd,
dm_list_iterate_safe(devh, tmp, &devs) {
devl = dm_list_item(devh, struct device_list);
- (void) label_read(devl->dev, &label, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
dm_list_del(&devl->list);
dm_free(devl);
}
@@ -750,7 +750,7 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
struct lvmcache_info *info;
char *vgname;
- if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL, NULL)) {
+ if (!lvmcache_device_from_pvid(cmd, (const struct id *)pvid, NULL)) {
log_error("Couldn't find device with uuid %s.", pvid);
return NULL;
}
@@ -766,19 +766,42 @@ char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid)
return vgname;
}
-static void _rescan_entry(struct lvmcache_info *info)
+/*
+ * FIXME: get rid of the CACHE_INVALID state and rescanning
+ * infos with that flag. The code should just know which devices
+ * need scanning and when.
+ */
+static int _label_scan_invalid(struct cmd_context *cmd)
{
- struct label *label;
+ struct dm_list devs;
+ struct dm_hash_node *n;
+ struct device_list *devl;
+ struct lvmcache_info *info;
+ int dev_count = 0;
+ int ret;
- if (info->status & CACHE_INVALID)
- (void) label_read(info->dev, &label, UINT64_C(0));
-}
+ dm_list_init(&devs);
-static int _scan_invalid(void)
-{
- dm_hash_iter(_pvid_hash, (dm_hash_iterate_fn) _rescan_entry);
+ dm_hash_iterate(n, _pvid_hash) {
+ if (!(info = dm_hash_get_data(_pvid_hash, n)))
+ continue;
- return 1;
+ if (!(info->status & CACHE_INVALID))
+ continue;
+
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
+
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
+ dev_count++;
+ }
+
+ log_debug_cache("Scanning %d devs with invalid info.", dev_count);
+
+ ret = label_scan_devs(cmd, &devs);
+
+ return ret;
}
/*
@@ -1093,17 +1116,89 @@ next:
goto next;
}
+/*
+ * The initial label_scan at the start of the command is done without
+ * holding VG locks. Then for each VG identified during the label_scan,
+ * vg_read(vgname) is called while holding the VG lock. The labels
+ * and metadata on this VG's devices could have changed between the
+ * initial unlocked label_scan and the current vg_read(). So, we reread
+ * the labels/metadata for each device in the VG now that we hold the
+ * lock, and use this for processing the VG.
+ *
+ * FIXME: In some cases, the data read by label_scan may be fine, and not
+ * need to be reread here. e.g. a reporting command, possibly with a
+ * special option, could skip this second reread. Or, we could look
+ * at the VG seqno in each copy of the metadata read in the first label
+ * scan, and if they all match, consider it good enough to use for
+ * reporting without rereading it. (A command modifying the VG would
+ * always want to reread while the lock is held before modifying.)
+ *
+ * A label scan is ultimately creating associations between devices
+ * and VGs so that when vg_read wants to get VG metadata, it knows
+ * which devices to read. In the special case where VG metadata is
+ * stored in files on the file system (configured in lvm.conf), the
+ * vginfo->independent_metadata_location flag is set during label scan.
+ * When we get here to rescan, we are revalidating the device to VG
+ * mapping from label scan by repeating the label scan on a subset of
+ * devices. If we see independent_metadata_location is set from the
+ * initial label scan, we know that there is nothing to do because
+ * there is no device to VG mapping to revalidate, since the VG metadata
+ * comes directly from files.
+ */
+
+int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid)
+{
+ struct dm_list devs;
+ struct device_list *devl;
+ struct lvmcache_vginfo *vginfo;
+ struct lvmcache_info *info;
+
+ if (lvmetad_used())
+ return 1;
+
+ dm_list_init(&devs);
+
+ if (!(vginfo = lvmcache_vginfo_from_vgname(vgname, vgid)))
+ return_0;
+
+ /*
+ * When the VG metadata is from an independent location,
+ * then rescanning the devices in the VG won't find the
+ * metadata, and will destroy the vginfo/info associations
+ * that were created during label scan when the
+ * independent locations were read.
+ */
+ if (vginfo->independent_metadata_location)
+ return 1;
+
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_malloc(sizeof(*devl)))) {
+ log_error("device_list element allocation failed");
+ return 0;
+ }
+ devl->dev = info->dev;
+ dm_list_add(&devs, &devl->list);
+ }
+
+ label_scan_devs(cmd, &devs);
+
+ /*
+ * TODO: grab vginfo again, and compare vginfo->infos
+ * to what was found above before rereading labels.
+ * If there are any info->devs now that were not in the
+ * first devs list, then do label_read on those also.
+ */
+
+ return 1;
+}
+
int lvmcache_label_scan(struct cmd_context *cmd)
{
struct dm_list del_cache_devs;
struct dm_list add_cache_devs;
struct lvmcache_info *info;
struct device_list *devl;
- struct label *label;
- struct dev_iter *iter;
- struct device *dev;
struct format_type *fmt;
- int dev_count = 0;
int r = 0;
@@ -1121,34 +1216,40 @@ int lvmcache_label_scan(struct cmd_context *cmd)
goto out;
}
+ /*
+ * Scan devices whose info struct has the INVALID flag set.
+ * When scanning has read the pv_header, mda_header and
+ * mda locations, it will clear the INVALID flag (via
+ * lvmcache_make_valid).
+ */
if (_has_scanned && !_force_label_scan) {
- r = _scan_invalid();
+ r = _label_scan_invalid(cmd);
goto out;
}
if (_force_label_scan && (cmd->full_filter && !cmd->full_filter->use_count) && !refresh_filters(cmd))
goto_out;
- if (!cmd->full_filter || !(iter = dev_iter_create(cmd->full_filter, _force_label_scan))) {
- log_error("dev_iter creation failed");
+ if (!cmd->full_filter) {
+ log_error("label scan is missing full filter");
goto out;
}
- log_very_verbose("Scanning device labels");
-
/*
* Duplicates found during this label scan are added to _found_duplicate_devs().
*/
_destroy_duplicate_device_list(&_found_duplicate_devs);
- while ((dev = dev_iter_get(iter))) {
- (void) label_read(dev, &label, UINT64_C(0));
- dev_count++;
- }
-
- dev_iter_destroy(iter);
-
- log_very_verbose("Scanned %d device labels", dev_count);
+ /*
+ * Do the actual scanning. This populates lvmcache
+ * with infos/vginfos based on reading headers from
+ * each device, and a vg summary from each mda.
+ *
+ * Note that this will *skip* scanning a device if
+ * an info struct already exists in lvmcache for
+ * the device.
+ */
+ label_scan(cmd);
/*
* _choose_preferred_devs() returns:
@@ -1182,7 +1283,7 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_iterate_items(devl, &add_cache_devs) {
log_debug_cache("Rescan preferred device %s for lvmcache", dev_name(devl->dev));
- (void) label_read(devl->dev, &label, UINT64_C(0));
+ label_read(devl->dev, NULL, UINT64_C(0));
}
dm_list_splice(&_unused_duplicate_devs, &del_cache_devs);
@@ -1441,61 +1542,45 @@ struct dm_list *lvmcache_get_pvids(struct cmd_context *cmd, const char *vgname,
return pvids;
}
-static struct device *_device_from_pvid(const struct id *pvid,
- uint64_t *label_sector)
+int lvmcache_get_vg_devs(struct cmd_context *cmd,
+ struct lvmcache_vginfo *vginfo,
+ struct dm_list *devs)
{
struct lvmcache_info *info;
- struct label *label;
+ struct device_list *devl;
- if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
- if (lvmetad_used()) {
- if (info->label && label_sector)
- *label_sector = info->label->sector;
- return info->dev;
- }
+ dm_list_iterate_items(info, &vginfo->infos) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return_0;
- if (label_read(info->dev, &label, UINT64_C(0))) {
- info = (struct lvmcache_info *) label->info;
- if (id_equal(pvid, (struct id *) &info->dev->pvid)) {
- if (label_sector)
- *label_sector = label->sector;
- return info->dev;
- }
- }
+ devl->dev = info->dev;
+ dm_list_add(devs, &devl->list);
}
- return NULL;
+ return 1;
}
-struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid,
- unsigned *scan_done_once, uint64_t *label_sector)
+static struct device *_device_from_pvid(const struct id *pvid, uint64_t *label_sector)
{
- struct device *dev;
-
- /* Already cached ? */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
-
- lvmcache_label_scan(cmd);
+ struct lvmcache_info *info;
- /* Try again */
- dev = _device_from_pvid(pvid, label_sector);
- if (dev)
- return dev;
+ if ((info = lvmcache_info_from_pvid((const char *) pvid, NULL, 0))) {
+ if (info->label && label_sector)
+ *label_sector = info->label->sector;
+ return info->dev;
+ }
- if (critical_section() || (scan_done_once && *scan_done_once))
- return NULL;
+ return NULL;
+}
- lvmcache_force_next_label_scan();
- lvmcache_label_scan(cmd);
- if (scan_done_once)
- *scan_done_once = 1;
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector)
+{
+ struct device *dev;
- /* Try again */
dev = _device_from_pvid(pvid, label_sector);
if (dev)
return dev;
+ log_debug_devs("No device with uuid %s.", (const char *)pvid);
return NULL;
}
@@ -1503,7 +1588,6 @@ const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
const char *devname)
{
struct device *dev;
- struct label *label;
if (!(dev = dev_cache_get(devname, cmd->filter))) {
log_error("%s: Couldn't find device. Check your filters?",
@@ -1511,7 +1595,7 @@ const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
return NULL;
}
- if (!(label_read(dev, &label, UINT64_C(0))))
+ if (!(label_read(dev, NULL, UINT64_C(0))))
return NULL;
return dev->pvid;
@@ -2657,6 +2741,14 @@ int lvmcache_vgid_is_cached(const char *vgid) {
return 1;
}
+void lvmcache_set_independent_location(const char *vgname)
+{
+ struct lvmcache_vginfo *vginfo;
+
+ if ((vginfo = lvmcache_vginfo_from_vgname(vgname, NULL)))
+ vginfo->independent_metadata_location = 1;
+}
+
/*
* Return true iff it is impossible to find out from this info alone whether the
* PV in question is or is not an orphan.
diff --git a/lib/cache/lvmcache.h b/lib/cache/lvmcache.h
index 847c208..826e91e 100644
--- a/lib/cache/lvmcache.h
+++ b/lib/cache/lvmcache.h
@@ -74,6 +74,7 @@ void lvmcache_destroy(struct cmd_context *cmd, int retain_orphans, int reset);
*/
void lvmcache_force_next_label_scan(void);
int lvmcache_label_scan(struct cmd_context *cmd);
+int lvmcache_label_rescan_vg(struct cmd_context *cmd, const char *vgname, const char *vgid);
/* Add/delete a device */
struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid,
@@ -105,10 +106,8 @@ struct lvmcache_vginfo *lvmcache_vginfo_from_vgid(const char *vgid);
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,
- unsigned *scan_done_once, uint64_t *label_sector);
-const char *lvmcache_pvid_from_devname(struct cmd_context *cmd,
- const char *devname);
+struct device *lvmcache_device_from_pvid(struct cmd_context *cmd, const struct id *pvid, uint64_t *label_sector);
+const char *lvmcache_pvid_from_devname(struct cmd_context *cmd, const char *devname);
char *lvmcache_vgname_from_pvid(struct cmd_context *cmd, const char *pvid);
const char *lvmcache_vgname_from_info(struct lvmcache_info *info);
const struct format_type *lvmcache_fmt_from_info(struct lvmcache_info *info);
@@ -215,4 +214,9 @@ void lvmcache_remove_unchosen_duplicate(struct device *dev);
int lvmcache_pvid_in_unchosen_duplicates(const char *pvid);
+int lvmcache_get_vg_devs(struct cmd_context *cmd,
+ struct lvmcache_vginfo *vginfo,
+ struct dm_list *devs);
+void lvmcache_set_independent_location(const char *vgname);
+
#endif
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index e9a34e6..c438b2d 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -2534,7 +2534,7 @@ static int _get_config_disk_area(struct cmd_context *cmd,
return 0;
}
- if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL, NULL))) {
+ if (!(dev_area.dev = lvmcache_device_from_pvid(cmd, &id, NULL))) {
char buffer[64] __attribute__((aligned(8)));
if (!id_write_format(&id, buffer, sizeof(buffer)))
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index d51397a..b41d83c 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -216,8 +216,7 @@ static int _read_pv(struct format_instance *fid,
/*
* Convert the uuid into a device.
*/
- if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, scan_done_once,
- &pv->label_sector))) {
+ if (!(pv->dev = lvmcache_device_from_pvid(fid->fmt->cmd, &pv->id, &pv->label_sector))) {
char buffer[64] __attribute__((aligned(8)));
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
diff --git a/lib/metadata/metadata-liblvm.c b/lib/metadata/metadata-liblvm.c
index a4284bc..388e8d9 100644
--- a/lib/metadata/metadata-liblvm.c
+++ b/lib/metadata/metadata-liblvm.c
@@ -314,7 +314,7 @@ struct physical_volume *pvcreate_vol(struct cmd_context *cmd, const char *pv_nam
}
if (pp->pva.idp) {
- if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL, NULL)) &&
+ if ((dev = lvmcache_device_from_pvid(cmd, pp->pva.idp, NULL)) &&
(dev != dev_cache_get(pv_name, cmd->full_filter))) {
if (!id_write_format((const struct id*)&pp->pva.idp->uuid,
buffer, sizeof(buffer)))
6 years
master - scan: use bcache for label scan and vg read
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=a7cb76ae94a90c89b86...
Commit: a7cb76ae94a90c89b86a810ceb4b6a91bab3441e
Parent: 697fa7aa1dbcc2ed8e141d9d13118cb38d609161
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Feb 6 15:18:11 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:19:24 2018 -0500
scan: use bcache for label scan and vg read
New label_scan function populates bcache for each device
on the system.
The two read paths are updated to get data from bcache.
The bcache is not yet used for writing. bcache blocks
for a device are invalidated when the device is written.
---
lib/commands/toolcontext.c | 2 +
lib/config/config.c | 10 +-
lib/device/bcache.c | 6 +-
lib/device/device.h | 1 +
lib/format_text/archive.c | 2 +-
lib/format_text/archiver.c | 2 +-
lib/format_text/format-text.c | 217 ++++++++------
lib/format_text/import-export.h | 8 +-
lib/format_text/import.c | 70 ++++--
lib/format_text/import_vsn1.c | 51 +---
lib/format_text/layout.h | 2 +-
lib/format_text/text_label.c | 15 +-
lib/label/label.c | 583 +++++++++++++++++++++++++++++---------
lib/label/label.h | 15 +-
lib/metadata/metadata-exported.h | 13 +
lib/metadata/metadata.c | 12 +-
lib/metadata/metadata.h | 8 +-
17 files changed, 713 insertions(+), 304 deletions(-)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index c998495..fe6b8a3 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -2124,6 +2124,7 @@ int refresh_toolcontext(struct cmd_context *cmd)
activation_release();
lvmcache_destroy(cmd, 0, 0);
+ label_scan_destroy(cmd);
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
@@ -2243,6 +2244,7 @@ void destroy_toolcontext(struct cmd_context *cmd)
archive_exit(cmd);
backup_exit(cmd);
lvmcache_destroy(cmd, 0, 0);
+ label_scan_destroy(cmd);
label_exit();
_destroy_segtypes(&cmd->segtypes);
_destroy_formats(cmd, &cmd->formats);
diff --git a/lib/config/config.c b/lib/config/config.c
index 8fca372..2d7db69 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -23,6 +23,7 @@
#include "toolcontext.h"
#include "lvm-file.h"
#include "memlock.h"
+#include "label.h"
#include <sys/stat.h>
#include <sys/mman.h>
@@ -532,10 +533,15 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
log_error("Failed to allocate circular buffer.");
return 0;
}
- if (!dev_read_circular(dev, (uint64_t) offset, size,
- (uint64_t) offset2, size2, reason, buf)) {
+
+ if (!bcache_read_bytes(scan_bcache, dev->fd, offset, size, buf))
goto out;
+
+ if (size2) {
+ if (!bcache_read_bytes(scan_bcache, dev->fd, offset2, size2, buf + size))
+ goto out;
}
+
fb = buf;
}
diff --git a/lib/device/bcache.c b/lib/device/bcache.c
index 5141083..38c909c 100644
--- a/lib/device/bcache.c
+++ b/lib/device/bcache.c
@@ -223,7 +223,11 @@ static bool _async_wait(struct io_engine *ioe, io_complete_fn fn)
else if ((int) ev->res < 0)
fn(cb->context, (int) ev->res);
- else {
+ else if (ev->res >= (1 << SECTOR_SHIFT)) {
+ /* minimum acceptable read is 1 sector */
+ fn((void *) cb->context, 0);
+
+ } else {
log_warn("short io");
fn(cb->context, -ENODATA);
}
diff --git a/lib/device/device.h b/lib/device/device.h
index 503373f..d5eb00f 100644
--- a/lib/device/device.h
+++ b/lib/device/device.h
@@ -31,6 +31,7 @@
#define DEV_USED_FOR_LV 0x00000100 /* Is device used for an LV */
#define DEV_ASSUMED_FOR_LV 0x00000200 /* Is device assumed for an LV */
#define DEV_NOT_O_NOATIME 0x00000400 /* Don't use O_NOATIME */
+#define DEV_IN_BCACHE 0x00000800 /* dev fd is open and used in bcache */
/*
* Support for external device info.
diff --git a/lib/format_text/archive.c b/lib/format_text/archive.c
index 72ec40b..690bc74 100644
--- a/lib/format_text/archive.c
+++ b/lib/format_text/archive.c
@@ -320,7 +320,7 @@ static void _display_archive(struct cmd_context *cmd, struct archive_file *af)
* retrieve the archive time and description.
*/
/* FIXME Use variation on _vg_read */
- if (!(vg = text_vg_import_file(tf, af->path, &when, &desc))) {
+ if (!(vg = text_read_metadata_file(tf, af->path, &when, &desc))) {
log_error("Unable to read archive file.");
tf->fmt->ops->destroy_instance(tf);
return;
diff --git a/lib/format_text/archiver.c b/lib/format_text/archiver.c
index 1eb6654..81b5da9 100644
--- a/lib/format_text/archiver.c
+++ b/lib/format_text/archiver.c
@@ -320,7 +320,7 @@ struct volume_group *backup_read_vg(struct cmd_context *cmd,
}
dm_list_iterate_items(mda, &tf->metadata_areas_in_use) {
- if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL, 0)))
+ if (!(vg = mda->ops->vg_read(tf, vg_name, mda, NULL, NULL)))
stack;
break;
}
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index be9a8b9..e9a34e6 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -317,47 +317,42 @@ static void _xlate_mdah(struct mda_header *mdah)
static int _raw_read_mda_header(struct mda_header *mdah, struct device_area *dev_area, int primary_mda)
{
- if (!dev_open_readonly(dev_area->dev))
- return_0;
+ log_debug_metadata("Reading mda header sector from %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
- if (!dev_read(dev_area->dev, dev_area->start, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah)) {
- if (!dev_close(dev_area->dev))
- stack;
- return_0;
+ if (!bcache_read_bytes(scan_bcache, dev_area->dev->fd, dev_area->start, MDA_HEADER_SIZE, mdah)) {
+ log_error("Failed to read metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
+ return 0;
}
- if (!dev_close(dev_area->dev))
- return_0;
-
if (mdah->checksum_xl != xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)))) {
- log_error("Incorrect metadata area header checksum on %s"
- " at offset " FMTu64, dev_name(dev_area->dev),
- dev_area->start);
+ log_error("Incorrect checksum in metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
_xlate_mdah(mdah);
if (strncmp((char *)mdah->magic, FMTT_MAGIC, sizeof(mdah->magic))) {
- log_error("Wrong magic number in metadata area header on %s"
- " at offset " FMTu64, dev_name(dev_area->dev),
- dev_area->start);
+ log_error("Wrong magic number in metadata area header on %s at %llu",
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
if (mdah->version != FMTT_VERSION) {
- log_error("Incompatible metadata area header version: %d on %s"
- " at offset " FMTu64, mdah->version,
- dev_name(dev_area->dev), dev_area->start);
+ log_error("Incompatible version %u metadata area header on %s at %llu",
+ mdah->version,
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
if (mdah->start != dev_area->start) {
- log_error("Incorrect start sector in metadata area header: "
- FMTu64 " on %s at offset " FMTu64, mdah->start,
- dev_name(dev_area->dev), dev_area->start);
+ log_error("Incorrect start sector %llu in metadata area header on %s at %llu",
+ (unsigned long long)mdah->start,
+ dev_name(dev_area->dev), (unsigned long long)dev_area->start);
return 0;
}
@@ -390,18 +385,33 @@ static int _raw_write_mda_header(const struct format_type *fmt,
mdah->version = FMTT_VERSION;
mdah->start = start_byte;
+ label_scan_invalidate(dev);
+
+ if (!dev_open(dev))
+ return_0;
+
_xlate_mdah(mdah);
mdah->checksum_xl = xlate32(calc_crc(INITIAL_CRC, (uint8_t *)mdah->magic,
MDA_HEADER_SIZE -
sizeof(mdah->checksum_xl)));
- if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah))
+ if (!dev_write(dev, start_byte, MDA_HEADER_SIZE, MDA_HEADER_REASON(primary_mda), mdah)) {
+ dev_close(dev);
return_0;
+ }
+
+ if (dev_close(dev))
+ stack;
return 1;
}
-static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
+/*
+ * FIXME: unify this with read_metadata_location() which is used
+ * in the label scanning path.
+ */
+
+static struct raw_locn *_read_metadata_location_vg(struct device_area *dev_area,
struct mda_header *mdah, int primary_mda,
const char *vgname,
int *precommitted)
@@ -446,11 +456,13 @@ static struct raw_locn *_find_vg_rlocn(struct device_area *dev_area,
if (rlocn_was_ignored)
return rlocn;
- /* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
- /* FIXME Ignore if checksum incorrect!!! */
- if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
- sizeof(vgnamebuf), MDA_CONTENT_REASON(primary_mda), vgnamebuf))
- goto_bad;
+ /*
+ * Verify that the VG metadata pointed to by the rlocn
+ * begins with a valid vgname.
+ */
+ memset(vgnamebuf, 0, sizeof(vgnamebuf));
+
+ bcache_read_bytes(scan_bcache, dev_area->dev->fd, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf);
if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
(isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
@@ -505,7 +517,7 @@ static int _raw_holds_vgname(struct format_instance *fid,
if (!(mdah = raw_read_mda_header(fid->fmt, dev_area, 0)))
return_0;
- if (_find_vg_rlocn(dev_area, mdah, 0, vgname, &noprecommit))
+ if (_read_metadata_location_vg(dev_area, mdah, 0, vgname, &noprecommit))
r = 1;
if (!dev_close(dev_area->dev))
@@ -520,7 +532,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
int precommitted,
- int single_device, int primary_mda)
+ int primary_mda)
{
struct volume_group *vg = NULL;
struct raw_locn *rlocn;
@@ -532,7 +544,7 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
if (!(mdah = raw_read_mda_header(fid->fmt, area, primary_mda)))
goto_out;
- if (!(rlocn = _find_vg_rlocn(area, mdah, primary_mda, vgname, &precommitted))) {
+ if (!(rlocn = _read_metadata_location_vg(area, mdah, primary_mda, vgname, &precommitted))) {
log_debug_metadata("VG %s not found on %s", vgname, dev_name(area->dev));
goto out;
}
@@ -546,26 +558,25 @@ static struct volume_group *_vg_read_raw_area(struct format_instance *fid,
goto out;
}
- /* FIXME 64-bit */
- if (!(vg = text_vg_import_fd(fid, NULL, vg_fmtdata, use_previous_vg, single_device, area->dev,
- primary_mda,
- (off_t) (area->start + rlocn->offset),
- (uint32_t) (rlocn->size - wrap),
- (off_t) (area->start + MDA_HEADER_SIZE),
- wrap, calc_crc, rlocn->checksum, &when,
- &desc)) && (!use_previous_vg || !*use_previous_vg))
- goto_out;
+ vg = text_read_metadata(fid, NULL, vg_fmtdata, use_previous_vg, area->dev, primary_mda,
+ (off_t) (area->start + rlocn->offset),
+ (uint32_t) (rlocn->size - wrap),
+ (off_t) (area->start + MDA_HEADER_SIZE),
+ wrap,
+ calc_crc,
+ rlocn->checksum,
+ &when, &desc);
- if (vg)
- log_debug_metadata("Read %s %smetadata (%u) from %s at " FMTu64 " size "
- FMTu64, vg->name, precommitted ? "pre-commit " : "",
- vg->seqno, dev_name(area->dev),
- area->start + rlocn->offset, rlocn->size);
- else
- log_debug_metadata("Skipped reading %smetadata from %s at " FMTu64 " size "
- FMTu64 " with matching checksum.", precommitted ? "pre-commit " : "",
- dev_name(area->dev),
- area->start + rlocn->offset, rlocn->size);
+ if (!vg) {
+ /* FIXME: detect and handle errors, and distinguish from the optimization
+ that skips parsing the metadata which also returns NULL. */
+ }
+
+ log_debug_metadata("Found metadata on %s at %"FMTu64" size %"FMTu64" for VG %s",
+ dev_name(area->dev),
+ area->start + rlocn->offset,
+ rlocn->size,
+ vgname);
if (vg && precommitted)
vg->status |= PRECOMMITTED;
@@ -578,8 +589,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg,
- int single_device)
+ unsigned *use_previous_vg)
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct volume_group *vg;
@@ -587,7 +597,7 @@ static struct volume_group *_vg_read_raw(struct format_instance *fid,
if (!dev_open_readonly(mdac->area.dev))
return_NULL;
- vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, single_device, mda_is_primary(mda));
+ vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 0, mda_is_primary(mda));
if (!dev_close(mdac->area.dev))
stack;
@@ -607,7 +617,7 @@ static struct volume_group *_vg_read_precommit_raw(struct format_instance *fid,
if (!dev_open_readonly(mdac->area.dev))
return_NULL;
- vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, 0, mda_is_primary(mda));
+ vg = _vg_read_raw_area(fid, vgname, &mdac->area, vg_fmtdata, use_previous_vg, 1, mda_is_primary(mda));
if (!dev_close(mdac->area.dev))
stack;
@@ -655,7 +665,7 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
goto out;
}
- rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
+ rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit);
mdac->rlocn.offset = _next_rlocn_offset(rlocn, mdah, mdac->area.start, MDA_ORIGINAL_ALIGNMENT);
mdac->rlocn.size = fidtc->raw_metadata_buf_size;
@@ -681,6 +691,8 @@ static int _vg_write_raw(struct format_instance *fid, struct volume_group *vg,
vg->name, dev_name(mdac->area.dev), mdac->area.start +
mdac->rlocn.offset, mdac->rlocn.size - new_wrap, mdac->rlocn.size);
+ label_scan_invalidate(mdac->area.dev);
+
/* Write text out, circularly */
if (!dev_write(mdac->area.dev, mdac->area.start + mdac->rlocn.offset,
(size_t) (mdac->rlocn.size - new_wrap), MDA_CONTENT_REASON(mda_is_primary(mda)),
@@ -752,7 +764,7 @@ static int _vg_commit_raw_rlocn(struct format_instance *fid,
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area, mda_is_primary(mda))))
goto_out;
- if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit))) {
+ if (!(rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), old_vg_name ? : vg->name, &noprecommit))) {
mdah->raw_locns[0].offset = 0;
mdah->raw_locns[0].size = 0;
mdah->raw_locns[0].checksum = 0;
@@ -872,7 +884,7 @@ static int _vg_remove_raw(struct format_instance *fid, struct volume_group *vg,
if (!(mdah = raw_read_mda_header(fid->fmt, &mdac->area, mda_is_primary(mda))))
goto_out;
- if (!(rlocn = _find_vg_rlocn(&mdac->area, mdah, mda_is_primary(mda), vg->name, &noprecommit))) {
+ if (!(rlocn = _read_metadata_location_vg(&mdac->area, mdah, mda_is_primary(mda), vg->name, &noprecommit))) {
rlocn = &mdah->raw_locns[0];
mdah->raw_locns[1].offset = 0;
}
@@ -906,8 +918,10 @@ static struct volume_group *_vg_read_file_name(struct format_instance *fid,
time_t when;
char *desc;
- if (!(vg = text_vg_import_file(fid, read_path, &when, &desc)))
- return_NULL;
+ if (!(vg = text_read_metadata_file(fid, read_path, &when, &desc))) {
+ log_error("Failed to read VG %s from %s", vgname, read_path);
+ return NULL;
+ }
/*
* Currently you can only have a single volume group per
@@ -931,8 +945,7 @@ static struct volume_group *_vg_read_file(struct format_instance *fid,
const char *vgname,
struct metadata_area *mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg __attribute__((unused)),
- int single_device __attribute__((unused)))
+ unsigned *use_previous_vg __attribute__((unused)))
{
struct text_context *tc = (struct text_context *) mda->metadata_locn;
@@ -1175,7 +1188,7 @@ static int _scan_file(const struct format_type *fmt, const char *vgname)
return 1;
}
-int vgname_from_mda(const struct format_type *fmt,
+int read_metadata_location_summary(const struct format_type *fmt,
struct mda_header *mdah, int primary_mda, struct device_area *dev_area,
struct lvmcache_vgsummary *vgsummary, uint64_t *mda_free_sectors)
{
@@ -1184,13 +1197,12 @@ int vgname_from_mda(const struct format_type *fmt,
unsigned int len = 0;
char buf[NAME_LEN + 1] __attribute__((aligned(8)));
uint64_t buffer_size, current_usage;
- unsigned used_cached_metadata = 0;
if (mda_free_sectors)
*mda_free_sectors = ((dev_area->size - MDA_HEADER_SIZE) / 2) >> SECTOR_SHIFT;
if (!mdah) {
- log_error(INTERNAL_ERROR "vgname_from_mda called with NULL pointer for mda_header");
+ log_error(INTERNAL_ERROR "read_metadata_location_summary called with NULL pointer for mda_header");
return 0;
}
@@ -1201,15 +1213,12 @@ int vgname_from_mda(const struct format_type *fmt,
* If no valid offset, do not try to search for vgname
*/
if (!rlocn->offset) {
- log_debug("%s: found metadata with offset 0.",
- dev_name(dev_area->dev));
+ log_debug_metadata("Metadata location on %s at %"FMTu64" has offset 0.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
return 0;
}
- /* Do quick check for a vgname */
- if (!dev_read(dev_area->dev, dev_area->start + rlocn->offset,
- NAME_LEN, MDA_CONTENT_REASON(primary_mda), buf))
- return_0;
+ bcache_read_bytes(scan_bcache, dev_area->dev->fd, dev_area->start + rlocn->offset, NAME_LEN, buf);
while (buf[len] && !isspace(buf[len]) && buf[len] != '{' &&
len < (NAME_LEN - 1))
@@ -1218,47 +1227,66 @@ int vgname_from_mda(const struct format_type *fmt,
buf[len] = '\0';
/* Ignore this entry if the characters aren't permissible */
- if (!validate_name(buf))
+ if (!validate_name(buf)) {
+ log_error("Metadata location on %s at %"FMTu64" begins with invalid VG name.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
return_0;
+ }
/* We found a VG - now check the metadata */
if (rlocn->offset + rlocn->size > mdah->size)
wrap = (uint32_t) ((rlocn->offset + rlocn->size) - mdah->size);
if (wrap > rlocn->offset) {
- log_error("%s: metadata (" FMTu64 " bytes) too large for circular buffer (" FMTu64 " bytes)",
- dev_name(dev_area->dev), rlocn->size, mdah->size - MDA_HEADER_SIZE);
+ log_error("Metadata location on %s at %"FMTu64" is too large for circular buffer.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
return 0;
}
- /* Did we see this metadata before? */
+ /*
+ * Did we see this metadata before?
+ * Look in lvmcache to see if there is vg info matching
+ * the checksum/size that we see in the mda_header (rlocn)
+ * on this device. If so, then vgsummary->name is is set
+ * and controls if the "checksum_only" flag passed to
+ * text_read_metadata_summary() is 1 or 0.
+ *
+ * If checksum_only = 1, then text_read_metadata_summary()
+ * will read the metadata from this device, and run the
+ * checksum function on it. If the calculated checksum
+ * of the metadata matches the checksum in the mda_header,
+ * which also matches the checksum saved in vginfo from
+ * another device, then it skips parsing the metadata into
+ * a config tree, which saves considerable cpu time.
+ */
+
vgsummary->mda_checksum = rlocn->checksum;
vgsummary->mda_size = rlocn->size;
+ lvmcache_lookup_mda(vgsummary);
- if (lvmcache_lookup_mda(vgsummary))
- used_cached_metadata = 1;
-
- /* FIXME 64-bit */
- if (!text_vgsummary_import(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
+ if (!text_read_metadata_summary(fmt, dev_area->dev, MDA_CONTENT_REASON(primary_mda),
(off_t) (dev_area->start + rlocn->offset),
(uint32_t) (rlocn->size - wrap),
(off_t) (dev_area->start + MDA_HEADER_SIZE),
wrap, calc_crc, vgsummary->vgname ? 1 : 0,
- vgsummary))
- return_0;
+ vgsummary)) {
+ log_error("Metadata location on %s at %"FMTu64" has invalid summary for VG.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
+ return 0;
+ }
/* Ignore this entry if the characters aren't permissible */
- if (!validate_name(vgsummary->vgname))
- return_0;
+ if (!validate_name(vgsummary->vgname)) {
+ log_error("Metadata location on %s at %"FMTu64" has invalid VG name.",
+ dev_name(dev_area->dev), dev_area->start + rlocn->offset);
+ return 0;
+ }
- log_debug_metadata("%s: %s metadata at " FMTu64 " size " FMTu64
- " (in area at " FMTu64 " size " FMTu64
- ") for %s (" FMTVGID ")",
+ log_debug_metadata("Found metadata summary on %s at %"FMTu64" size %"FMTu64" for VG %s",
dev_name(dev_area->dev),
- used_cached_metadata ? "Using cached" : "Found",
dev_area->start + rlocn->offset,
- rlocn->size, dev_area->start, dev_area->size, vgsummary->vgname,
- (char *)&vgsummary->vgid);
+ rlocn->size,
+ vgsummary->vgname);
if (mda_free_sectors) {
current_usage = (rlocn->size + SECTOR_SIZE - UINT64_C(1)) -
@@ -1301,8 +1329,7 @@ static int _scan_raw(const struct format_type *fmt, const char *vgname __attribu
goto close_dev;
}
- /* TODO: caching as in vgname_from_mda() (trigger this code?) */
- if (vgname_from_mda(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
+ if (read_metadata_location_summary(fmt, mdah, 0, &rl->dev_area, &vgsummary, NULL)) {
vg = _vg_read_raw_area(&fid, vgsummary.vgname, &rl->dev_area, NULL, NULL, 0, 0, 0);
if (vg)
lvmcache_update_vg(vg, 0);
@@ -1776,7 +1803,13 @@ static int _mda_export_text_raw(struct metadata_area *mda,
struct mda_context *mdc = (struct mda_context *) mda->metadata_locn;
char mdah[MDA_HEADER_SIZE]; /* temporary */
- if (!mdc || !_raw_read_mda_header((struct mda_header *)mdah, &mdc->area, mda_is_primary(mda)))
+ if (!mdc) {
+ log_error(INTERNAL_ERROR "mda_export_text_raw no mdc");
+ return 1; /* pretend the MDA does not exist */
+ }
+
+ /* FIXME: why aren't ignore,start,size,free_sectors available? */
+ if (!_raw_read_mda_header((struct mda_header *)mdah, &mdc->area, mda_is_primary(mda)))
return 1; /* pretend the MDA does not exist */
return config_make_nodes(cft, parent, NULL,
diff --git a/lib/format_text/import-export.h b/lib/format_text/import-export.h
index 894d881..920eb3e 100644
--- a/lib/format_text/import-export.h
+++ b/lib/format_text/import-export.h
@@ -49,7 +49,6 @@ struct text_vg_version_ops {
int (*check_version) (const struct dm_config_tree * cf);
struct volume_group *(*read_vg) (struct format_instance * fid,
const struct dm_config_tree *cf,
- unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions);
void (*read_desc) (struct dm_pool * mem, const struct dm_config_tree *cf,
time_t *when, char **desc);
@@ -68,14 +67,13 @@ int read_segtype_lvflags(uint64_t *status, char *segtype_str);
int text_vg_export_file(struct volume_group *vg, const char *desc, FILE *fp);
size_t text_vg_export_raw(struct volume_group *vg, const char *desc, char **buf);
-struct volume_group *text_vg_import_file(struct format_instance *fid,
+struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc);
-struct volume_group *text_vg_import_fd(struct format_instance *fid,
+struct volume_group *text_read_metadata(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
- int single_device,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
@@ -83,7 +81,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
uint32_t checksum,
time_t *when, char **desc);
-int text_vgsummary_import(const struct format_type *fmt,
+int text_read_metadata_summary(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
diff --git a/lib/format_text/import.c b/lib/format_text/import.c
index da4cefd..4b34485 100644
--- a/lib/format_text/import.c
+++ b/lib/format_text/import.c
@@ -35,7 +35,7 @@ static void _init_text_import(void)
/*
* Find out vgname on a given device.
*/
-int text_vgsummary_import(const struct format_type *fmt,
+int text_read_metadata_summary(const struct format_type *fmt,
struct device *dev, dev_io_reason_t reason,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
@@ -52,17 +52,29 @@ int text_vgsummary_import(const struct format_type *fmt,
if (!(cft = config_open(CONFIG_FILE_SPECIAL, NULL, 0)))
return_0;
- if ((!dev && !config_file_read(cft)) ||
- (dev && !config_file_read_fd(cft, dev, reason, offset, size,
+ if (dev) {
+ log_debug_metadata("Reading metadata summary from %s at %llu size %d (+%d)",
+ dev_name(dev), (unsigned long long)offset,
+ size, size2);
+
+ if (!config_file_read_fd(cft, dev, reason, offset, size,
offset2, size2, checksum_fn,
vgsummary->mda_checksum,
- checksum_only, 1))) {
- log_error("Couldn't read volume group metadata.");
- goto out;
+ checksum_only, 1)) {
+ /* FIXME: handle errors */
+ log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
+ goto out;
+ }
+ } else {
+ if (!config_file_read(cft)) {
+ log_error("Couldn't read volume group metadata from file.");
+ goto out;
+ }
}
if (checksum_only) {
/* Checksum matches already-cached content - no need to reparse. */
+ log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
r = 1;
goto out;
}
@@ -91,11 +103,10 @@ struct cached_vg_fmtdata {
size_t cached_mda_size;
};
-struct volume_group *text_vg_import_fd(struct format_instance *fid,
+struct volume_group *text_read_metadata(struct format_instance *fid,
const char *file,
struct cached_vg_fmtdata **vg_fmtdata,
unsigned *use_previous_vg,
- int single_device,
struct device *dev, int primary_mda,
off_t offset, uint32_t size,
off_t offset2, uint32_t size2,
@@ -108,6 +119,15 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
struct text_vg_version_ops **vsn;
int skip_parse;
+ /*
+ * This struct holds the checksum and size of the VG metadata
+ * that was read from a previous device. When we read the VG
+ * metadata from this device, we can skip parsing it into a
+ * cft (saving time) if the checksum of the metadata buffer
+ * we read from this device matches the size/checksum saved in
+ * the mda_header/rlocn struct on this device, and matches the
+ * size/checksum from the previous device.
+ */
if (vg_fmtdata && !*vg_fmtdata &&
!(*vg_fmtdata = dm_pool_zalloc(fid->mem, sizeof(**vg_fmtdata)))) {
log_error("Failed to allocate VG fmtdata for text format.");
@@ -127,15 +147,30 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
((*vg_fmtdata)->cached_mda_checksum == checksum) &&
((*vg_fmtdata)->cached_mda_size == (size + size2));
- if ((!dev && !config_file_read(cft)) ||
- (dev && !config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
+
+ if (dev) {
+ log_debug_metadata("Reading metadata from %s at %llu size %d (+%d)",
+ dev_name(dev), (unsigned long long)offset,
+ size, size2);
+
+ if (!config_file_read_fd(cft, dev, MDA_CONTENT_REASON(primary_mda), offset, size,
offset2, size2, checksum_fn, checksum,
- skip_parse, 1)))
- goto_out;
+ skip_parse, 1)) {
+ /* FIXME: handle errors */
+ log_error("Couldn't read volume group metadata from %s.", dev_name(dev));
+ goto out;
+ }
+ } else {
+ if (!config_file_read(cft)) {
+ log_error("Couldn't read volume group metadata from file.");
+ goto out;
+ }
+ }
if (skip_parse) {
if (use_previous_vg)
*use_previous_vg = 1;
+ log_debug_metadata("Skipped parsing metadata on %s", dev_name(dev));
goto out;
}
@@ -146,7 +181,7 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
if (!(*vsn)->check_version(cft))
continue;
- if (!(vg = (*vsn)->read_vg(fid, cft, single_device, 0)))
+ if (!(vg = (*vsn)->read_vg(fid, cft, 0)))
goto_out;
(*vsn)->read_desc(vg->vgmem, cft, when, desc);
@@ -166,12 +201,13 @@ struct volume_group *text_vg_import_fd(struct format_instance *fid,
return vg;
}
-struct volume_group *text_vg_import_file(struct format_instance *fid,
+struct volume_group *text_read_metadata_file(struct format_instance *fid,
const char *file,
time_t *when, char **desc)
{
- return text_vg_import_fd(fid, file, NULL, NULL, 0, NULL, 0, (off_t)0, 0, (off_t)0, 0, NULL, 0,
- when, desc);
+ return text_read_metadata(fid, file, NULL, NULL, NULL, 0,
+ (off_t)0, 0, (off_t)0, 0, NULL, 0,
+ when, desc);
}
static struct volume_group *_import_vg_from_config_tree(const struct dm_config_tree *cft,
@@ -191,7 +227,7 @@ static struct volume_group *_import_vg_from_config_tree(const struct dm_config_t
* The only path to this point uses cached vgmetadata,
* so it can use cached PV state too.
*/
- if (!(vg = (*vsn)->read_vg(fid, cft, 1, allow_lvmetad_extensions)))
+ if (!(vg = (*vsn)->read_vg(fid, cft, allow_lvmetad_extensions)))
stack;
else if ((vg_missing = vg_missing_pv_count(vg))) {
log_verbose("There are %d physical volumes missing.",
diff --git a/lib/format_text/import_vsn1.c b/lib/format_text/import_vsn1.c
index 9267d45..d51397a 100644
--- a/lib/format_text/import_vsn1.c
+++ b/lib/format_text/import_vsn1.c
@@ -32,9 +32,7 @@ typedef int (*section_fn) (struct format_instance * fid,
struct volume_group * vg, const struct dm_config_node * pvn,
const struct dm_config_node * vgn,
struct dm_hash_table * pv_hash,
- struct dm_hash_table * lv_hash,
- unsigned *scan_done_once,
- unsigned report_missing_devices);
+ struct dm_hash_table * lv_hash);
#define _read_int32(root, path, result) \
dm_config_get_uint32(root, path, (uint32_t *) (result))
@@ -180,9 +178,7 @@ static int _read_pv(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *pvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
- struct dm_hash_table *lv_hash __attribute__((unused)),
- unsigned *scan_done_once,
- unsigned report_missing_devices)
+ struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
struct physical_volume *pv;
@@ -226,10 +222,7 @@ static int _read_pv(struct format_instance *fid,
if (!id_write_format(&pv->id, buffer, sizeof(buffer)))
buffer[0] = '\0';
- if (report_missing_devices)
- log_error_once("Couldn't find device with uuid %s.", buffer);
- else
- log_very_verbose("Couldn't find device with uuid %s.", buffer);
+ log_error_once("Couldn't find device with uuid %s.", buffer);
}
if (!(pv->vg_name = dm_pool_strdup(mem, vg->name)))
@@ -574,9 +567,7 @@ static int _read_lvnames(struct format_instance *fid __attribute__((unused)),
struct volume_group *vg, const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
- struct dm_hash_table *lv_hash,
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash)
{
struct dm_pool *mem = vg->vgmem;
struct logical_volume *lv;
@@ -731,9 +722,7 @@ static int _read_historical_lvnames(struct format_instance *fid __attribute__((u
struct volume_group *vg, const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
- struct dm_hash_table *lv_hash __attribute__((unused)),
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
struct generic_logical_volume *glv;
@@ -802,9 +791,7 @@ static int _read_historical_lvnames_interconnections(struct format_instance *fid
struct volume_group *vg, const struct dm_config_node *hlvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash __attribute__((unused)),
- struct dm_hash_table *lv_hash __attribute__((unused)),
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash __attribute__((unused)))
{
struct dm_pool *mem = vg->vgmem;
const char *historical_lv_name, *origin_name = NULL;
@@ -914,9 +901,7 @@ static int _read_lvsegs(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *lvn,
const struct dm_config_node *vgn __attribute__((unused)),
struct dm_hash_table *pv_hash,
- struct dm_hash_table *lv_hash,
- unsigned *scan_done_once __attribute__((unused)),
- unsigned report_missing_devices __attribute__((unused)))
+ struct dm_hash_table *lv_hash)
{
struct logical_volume *lv;
@@ -977,12 +962,9 @@ static int _read_sections(struct format_instance *fid,
struct volume_group *vg, const struct dm_config_node *vgn,
struct dm_hash_table *pv_hash,
struct dm_hash_table *lv_hash,
- int optional,
- unsigned *scan_done_once)
+ int optional)
{
const struct dm_config_node *n;
- /* Only report missing devices when doing a scan */
- unsigned report_missing_devices = scan_done_once ? !*scan_done_once : 1;
if (!dm_config_get_section(vgn, section, &n)) {
if (!optional) {
@@ -994,8 +976,7 @@ static int _read_sections(struct format_instance *fid,
}
for (n = n->child; n; n = n->sib) {
- if (!fn(fid, vg, n, vgn, pv_hash, lv_hash,
- scan_done_once, report_missing_devices))
+ if (!fn(fid, vg, n, vgn, pv_hash, lv_hash))
return_0;
}
@@ -1004,7 +985,6 @@ static int _read_sections(struct format_instance *fid,
static struct volume_group *_read_vg(struct format_instance *fid,
const struct dm_config_tree *cft,
- unsigned use_cached_pvs,
unsigned allow_lvmetad_extensions)
{
const struct dm_config_node *vgn;
@@ -1012,7 +992,6 @@ static struct volume_group *_read_vg(struct format_instance *fid,
const char *str, *format_str, *system_id;
struct volume_group *vg;
struct dm_hash_table *pv_hash = NULL, *lv_hash = NULL;
- unsigned scan_done_once = use_cached_pvs;
uint64_t vgstatus;
/* skip any top-level values */
@@ -1167,7 +1146,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
if (!_read_sections(fid, "physical_volumes", _read_pv, vg,
- vgn, pv_hash, lv_hash, 0, &scan_done_once)) {
+ vgn, pv_hash, lv_hash, 0)) {
log_error("Couldn't find all physical volumes for volume "
"group %s.", vg->name);
goto bad;
@@ -1175,7 +1154,7 @@ static struct volume_group *_read_vg(struct format_instance *fid,
if (allow_lvmetad_extensions)
_read_sections(fid, "outdated_pvs", _read_pv, vg,
- vgn, pv_hash, lv_hash, 1, &scan_done_once);
+ vgn, pv_hash, lv_hash, 1);
else if (dm_config_has_node(vgn, "outdated_pvs"))
log_error(INTERNAL_ERROR "Unexpected outdated_pvs section in metadata of VG %s.", vg->name);
@@ -1187,28 +1166,28 @@ static struct volume_group *_read_vg(struct format_instance *fid,
}
if (!_read_sections(fid, "logical_volumes", _read_lvnames, vg,
- vgn, pv_hash, lv_hash, 1, NULL)) {
+ vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all logical volume names for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "historical_logical_volumes", _read_historical_lvnames, vg,
- vgn, pv_hash, lv_hash, 1, NULL)) {
+ vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all historical logical volumes for volume "
"group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "logical_volumes", _read_lvsegs, vg,
- vgn, pv_hash, lv_hash, 1, NULL)) {
+ vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all logical volumes for "
"volume group %s.", vg->name);
goto bad;
}
if (!_read_sections(fid, "historical_logical_volumes", _read_historical_lvnames_interconnections,
- vg, vgn, pv_hash, lv_hash, 1, NULL)) {
+ vg, vgn, pv_hash, lv_hash, 1)) {
log_error("Couldn't read all removed logical volume interconnections "
"for volume group %s.", vg->name);
goto bad;
diff --git a/lib/format_text/layout.h b/lib/format_text/layout.h
index 1746b9c..2671bbf 100644
--- a/lib/format_text/layout.h
+++ b/lib/format_text/layout.h
@@ -104,7 +104,7 @@ struct mda_context {
#define MDA_SIZE_MIN (8 * (unsigned) lvm_getpagesize())
#define MDA_ORIGINAL_ALIGNMENT 512 /* Original alignment used for start of VG metadata content */
-int vgname_from_mda(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
+int read_metadata_location_summary(const struct format_type *fmt, struct mda_header *mdah, int primary_mda,
struct device_area *dev_area, struct lvmcache_vgsummary *vgsummary,
uint64_t *mda_free_sectors);
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index 7058f70..1c322dd 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -323,7 +323,7 @@ struct _update_mda_baton {
struct label *label;
};
-static int _update_mda(struct metadata_area *mda, void *baton)
+static int _read_mda_header_and_metadata(struct metadata_area *mda, void *baton)
{
struct _update_mda_baton *p = baton;
const struct format_type *fmt = p->label->labeller->fmt;
@@ -360,7 +360,7 @@ static int _update_mda(struct metadata_area *mda, void *baton)
return 1;
}
- if (vgname_from_mda(fmt, mdah, mda_is_primary(mda), &mdac->area, &vgsummary,
+ if (read_metadata_location_summary(fmt, mdah, mda_is_primary(mda), &mdac->area, &vgsummary,
&mdac->free_sectors) &&
!lvmcache_update_vgname_and_id(p->info, &vgsummary)) {
if (!dev_close(mdac->area.dev))
@@ -375,10 +375,10 @@ close_dev:
return 1;
}
-static int _text_read(struct labeller *l, struct device *dev, void *buf,
- struct label **label)
+static int _text_read(struct labeller *l, struct device *dev, void *label_buf,
+ struct label **label)
{
- struct label_header *lh = (struct label_header *) buf;
+ struct label_header *lh = (struct label_header *) label_buf;
struct pv_header *pvhdr;
struct pv_header_extension *pvhdr_ext;
struct lvmcache_info *info;
@@ -390,7 +390,7 @@ static int _text_read(struct labeller *l, struct device *dev, void *buf,
/*
* PV header base
*/
- pvhdr = (struct pv_header *) ((char *) buf + xlate32(lh->offset_xl));
+ pvhdr = (struct pv_header *) ((char *) label_buf + xlate32(lh->offset_xl));
if (!(info = lvmcache_add(l, (char *)pvhdr->pv_uuid, dev,
FMT_TEXT_ORPHAN_VG_NAME,
@@ -447,8 +447,7 @@ out:
baton.info = info;
baton.label = *label;
- if (!lvmcache_foreach_mda(info, _update_mda, &baton))
- return_0;
+ lvmcache_foreach_mda(info, _read_mda_header_and_metadata, &baton);
lvmcache_make_valid(info);
diff --git a/lib/label/label.c b/lib/label/label.c
index 46dd667..57d5248 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -18,10 +18,14 @@
#include "crc.h"
#include "xlate.h"
#include "lvmcache.h"
+#include "bcache.h"
+#include "toolcontext.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/time.h>
+
/* FIXME Allow for larger labels? Restricted to single sector currently */
@@ -96,101 +100,6 @@ struct labeller *label_get_handler(const char *name)
return NULL;
}
-static void _update_lvmcache_orphan(struct lvmcache_info *info)
-{
- struct lvmcache_vgsummary vgsummary_orphan = {
- .vgname = lvmcache_fmt(info)->orphan_vg_name,
- };
-
- memcpy(&vgsummary_orphan.vgid, lvmcache_fmt(info)->orphan_vg_name, strlen(lvmcache_fmt(info)->orphan_vg_name));
-
- if (!lvmcache_update_vgname_and_id(info, &vgsummary_orphan))
- stack;
-}
-
-static struct labeller *_find_labeller(struct device *dev, char *buf,
- uint64_t *label_sector,
- uint64_t scan_sector)
-{
- struct labeller_i *li;
- struct labeller *r = NULL;
- struct label_header *lh;
- struct lvmcache_info *info;
- uint64_t sector;
- int found = 0;
- char readbuf[LABEL_SCAN_SIZE] __attribute__((aligned(8)));
-
- if (!dev_read(dev, scan_sector << SECTOR_SHIFT,
- LABEL_SCAN_SIZE, DEV_IO_LABEL, readbuf)) {
- log_debug_devs("%s: Failed to read label area", dev_name(dev));
- goto out;
- }
-
- /* Scan a few sectors for a valid label */
- for (sector = 0; sector < LABEL_SCAN_SECTORS;
- sector += LABEL_SIZE >> SECTOR_SHIFT) {
- lh = (struct label_header *) (readbuf +
- (sector << SECTOR_SHIFT));
-
- if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
- if (found) {
- log_error("Ignoring additional label on %s at "
- "sector %" PRIu64, dev_name(dev),
- sector + scan_sector);
- }
- if (xlate64(lh->sector_xl) != sector + scan_sector) {
- log_very_verbose("%s: Label for sector %" PRIu64
- " found at sector %" PRIu64
- " - ignoring", dev_name(dev),
- (uint64_t)xlate64(lh->sector_xl),
- sector + scan_sector);
- continue;
- }
- if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
- ((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
- xlate32(lh->crc_xl)) {
- log_very_verbose("Label checksum incorrect on %s - "
- "ignoring", dev_name(dev));
- continue;
- }
- if (found)
- continue;
- }
-
- dm_list_iterate_items(li, &_labellers) {
- if (li->l->ops->can_handle(li->l, (char *) lh,
- sector + scan_sector)) {
- log_very_verbose("%s: %s label detected at "
- "sector %" PRIu64,
- dev_name(dev), li->name,
- sector + scan_sector);
- if (found) {
- log_error("Ignoring additional label "
- "on %s at sector %" PRIu64,
- dev_name(dev),
- sector + scan_sector);
- continue;
- }
- r = li->l;
- memcpy(buf, lh, LABEL_SIZE);
- if (label_sector)
- *label_sector = sector + scan_sector;
- found = 1;
- break;
- }
- }
- }
-
- out:
- if (!found) {
- if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0)))
- _update_lvmcache_orphan(info);
- log_very_verbose("%s: No label detected", dev_name(dev));
- }
-
- return r;
-}
-
/* FIXME Also wipe associated metadata area headers? */
int label_remove(struct device *dev)
{
@@ -216,6 +125,8 @@ int label_remove(struct device *dev)
*/
dev_flush(dev);
+ label_scan_invalidate(dev);
+
if (!dev_read(dev, UINT64_C(0), LABEL_SCAN_SIZE, DEV_IO_LABEL, readbuf)) {
log_debug_devs("%s: Failed to read label area", dev_name(dev));
goto out;
@@ -267,44 +178,6 @@ int label_remove(struct device *dev)
return r;
}
-int label_read(struct device *dev, struct label **result,
- uint64_t scan_sector)
-{
- char buf[LABEL_SIZE] __attribute__((aligned(8)));
- struct labeller *l;
- uint64_t sector;
- struct lvmcache_info *info;
- int r = 0;
-
- 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, dev, 0)))
- _update_lvmcache_orphan(info);
-
- return r;
- }
-
- if ((l = _find_labeller(dev, buf, §or, scan_sector)))
- if ((r = (l->ops->read)(l, dev, buf, result)) && result && *result) {
- (*result)->dev = dev;
- (*result)->sector = sector;
- }
-
- if (!dev_close(dev))
- stack;
-
- return r;
-}
-
/* Caller may need to use label_get_handler to create label struct! */
int label_write(struct device *dev, struct label *label)
{
@@ -323,6 +196,8 @@ int label_write(struct device *dev, struct label *label)
return 0;
}
+ label_scan_invalidate(dev);
+
memset(buf, 0, LABEL_SIZE);
strncpy((char *)lh->id, LABEL_ID, sizeof(lh->id));
@@ -373,3 +248,445 @@ struct label *label_create(struct labeller *labeller)
return label;
}
+
+
+/* global variable for accessing the bcache populated by label scan */
+struct bcache *scan_bcache;
+
+#define BCACHE_BLOCK_SIZE_IN_SECTORS 2048 /* 1MB */
+
+static bool _in_bcache(struct device *dev)
+{
+ return (dev->flags & DEV_IN_BCACHE) ? true : false;
+}
+
+static struct labeller *_find_lvm_header(struct device *dev,
+ char *scan_buf,
+ char *label_buf,
+ uint64_t *label_sector,
+ uint64_t scan_sector)
+{
+ struct labeller_i *li;
+ struct labeller *labeller_ret = NULL;
+ struct label_header *lh;
+ uint64_t sector;
+ int found = 0;
+
+ /*
+ * Find which sector in scan_buf starts with a valid label,
+ * and copy it into label_buf.
+ */
+
+ for (sector = 0; sector < LABEL_SCAN_SECTORS;
+ sector += LABEL_SIZE >> SECTOR_SHIFT) {
+ lh = (struct label_header *) (scan_buf + (sector << SECTOR_SHIFT));
+
+ if (!strncmp((char *)lh->id, LABEL_ID, sizeof(lh->id))) {
+ if (found) {
+ log_error("Ignoring additional label on %s at sector %llu",
+ dev_name(dev), (unsigned long long)(sector + scan_sector));
+ }
+ if (xlate64(lh->sector_xl) != sector + scan_sector) {
+ log_very_verbose("%s: Label for sector %llu found at sector %llu - ignoring.",
+ dev_name(dev),
+ (unsigned long long)xlate64(lh->sector_xl),
+ (unsigned long long)(sector + scan_sector));
+ continue;
+ }
+ if (calc_crc(INITIAL_CRC, (uint8_t *)&lh->offset_xl, LABEL_SIZE -
+ ((uint8_t *) &lh->offset_xl - (uint8_t *) lh)) !=
+ xlate32(lh->crc_xl)) {
+ log_very_verbose("Label checksum incorrect on %s - ignoring", dev_name(dev));
+ continue;
+ }
+ if (found)
+ continue;
+ }
+
+ dm_list_iterate_items(li, &_labellers) {
+ if (li->l->ops->can_handle(li->l, (char *) lh, sector + scan_sector)) {
+ log_very_verbose("%s: %s label detected at sector %llu",
+ dev_name(dev), li->name,
+ (unsigned long long)(sector + scan_sector));
+ if (found) {
+ log_error("Ignoring additional label on %s at sector %llu",
+ dev_name(dev),
+ (unsigned long long)(sector + scan_sector));
+ continue;
+ }
+
+ labeller_ret = li->l;
+ found = 1;
+
+ memcpy(label_buf, lh, LABEL_SIZE);
+ if (label_sector)
+ *label_sector = sector + scan_sector;
+ break;
+ }
+ }
+ }
+
+ return labeller_ret;
+}
+
+/*
+ * Process/parse the headers from the data read from a device.
+ * Populates lvmcache with device / mda locations / vgname
+ * so that vg_read(vgname) will know which devices/locations
+ * to read metadata from.
+ *
+ * If during processing, headers/metadata are found to be needed
+ * beyond the range of the scanned block, then additional reads
+ * are performed in the processing functions to get that data.
+ */
+static int _process_block(struct device *dev, struct block *bb, int *is_lvm_device)
+{
+ char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
+ struct label *label = NULL;
+ struct labeller *labeller;
+ struct lvmcache_info *info;
+ uint64_t sector;
+ int ret = 0;
+
+ /*
+ * Finds the data sector containing the label and copies into label_buf.
+ * label_buf: struct label_header + struct pv_header + struct pv_header_extension
+ *
+ * FIXME: we don't need to copy one sector from bb->data into label_buf,
+ * we can just point label_buf at one sector in ld->buf.
+ */
+ if (!(labeller = _find_lvm_header(dev, bb->data, label_buf, §or, 0))) {
+
+ /*
+ * Non-PVs exit here
+ *
+ * FIXME: check for PVs with errors that also exit here!
+ * i.e. this code cannot distinguish between a non-lvm
+ * device an an lvm device with errors.
+ */
+
+ log_very_verbose("%s: No lvm label detected", dev_name(dev));
+
+ if ((info = lvmcache_info_from_pvid(dev->pvid, dev, 0))) {
+ /* FIXME: if this case is actually happening, fix it. */
+ log_warn("Device %s has no label, removing PV info from lvmcache.", dev_name(dev));
+ lvmcache_del(info);
+ }
+
+ *is_lvm_device = 0;
+ goto_out;
+ }
+
+ *is_lvm_device = 1;
+
+ /*
+ * This is the point where the scanning code dives into the rest of
+ * lvm. ops->read() is usually _text_read() which reads the pv_header,
+ * mda locations, mda contents. As these bits of data are read, they
+ * are saved into lvmcache as info/vginfo structs.
+ */
+
+ if ((ret = (labeller->ops->read)(labeller, dev, label_buf, &label)) && label) {
+ label->dev = dev;
+ label->sector = sector;
+ } else {
+ /* FIXME: handle errors */
+ }
+ out:
+ return ret;
+}
+
+/*
+ * Read or reread label/metadata from selected devs.
+ *
+ * Reads and looks at label_header, pv_header, pv_header_extension,
+ * mda_header, raw_locns, vg metadata from each device.
+ *
+ * Effect is populating lvmcache with latest info/vginfo (PV/VG) data
+ * from the devs. If a scanned device does not have a label_header,
+ * its info is removed from lvmcache.
+ */
+
+static int _scan_list(struct dm_list *devs)
+{
+ struct dm_list wait_devs;
+ struct dm_list done_devs;
+ struct device_list *devl, *devl2;
+ struct block *bb;
+ int scan_failed_count = 0;
+ int scan_lvm_count = 0;
+ int rem_prefetches;
+ int scan_failed;
+ int is_lvm_device;
+
+ dm_list_init(&wait_devs);
+ dm_list_init(&done_devs);
+
+ log_debug_devs("Scanning %d devices.", dm_list_size(devs));
+
+ scan_more:
+ rem_prefetches = bcache_max_prefetches(scan_bcache);
+
+ dm_list_iterate_items_safe(devl, devl2, devs) {
+
+ /*
+ * If we prefetch more devs than blocks in the cache, then the
+ * cache will wait for earlier reads to complete, toss the
+ * results, and reuse those blocks before we've had a chance to
+ * use them. So, prefetch as many as are available, wait for
+ * and process them, then repeat.
+ */
+ if (!rem_prefetches)
+ break;
+
+ /*
+ * The in-bcache flag corresponds with this dev_open.
+ * Clearing the in-bcache flag should be paired with
+ * a dev_close. (This dev may already be in bcache.)
+ */
+ if (!_in_bcache(devl->dev)) {
+ if (!dev_open_readonly(devl->dev)) {
+ log_debug_devs("%s: Failed to open device.", dev_name(devl->dev));
+ continue;
+ }
+ }
+
+ bcache_prefetch(scan_bcache, devl->dev->fd, 0);
+
+ rem_prefetches--;
+
+ dm_list_del(&devl->list);
+ dm_list_add(&wait_devs, &devl->list);
+ }
+
+ dm_list_iterate_items_safe(devl, devl2, &wait_devs) {
+ bb = NULL;
+
+ if (!bcache_get(scan_bcache, devl->dev->fd, 0, 0, &bb)) {
+ log_debug_devs("%s: Failed to scan device.", dev_name(devl->dev));
+ scan_failed_count++;
+ scan_failed = 1;
+ } else {
+ log_debug_devs("Processing data from device %s fd %d block %p", dev_name(devl->dev), devl->dev->fd, bb);
+ _process_block(devl->dev, bb, &is_lvm_device);
+ scan_lvm_count++;
+ scan_failed = 0;
+ }
+
+ if (bb)
+ bcache_put(bb);
+
+ /*
+ * Keep the bcache block of lvm devices we have processed so
+ * that the vg_read phase can reuse it. If bcache failed to
+ * read the block, or the device does not belong to lvm, then
+ * drop it from bcache.
+ */
+ if (scan_failed || !is_lvm_device) {
+ devl->dev->flags &= ~DEV_IN_BCACHE;
+ bcache_invalidate_fd(scan_bcache, devl->dev->fd);
+ dev_close(devl->dev);
+ } else {
+ /* The device must be kept open while it's in bcache. */
+ devl->dev->flags |= DEV_IN_BCACHE;
+ }
+
+ dm_list_del(&devl->list);
+ dm_list_add(&done_devs, &devl->list);
+ }
+
+ if (!dm_list_empty(devs))
+ goto scan_more;
+
+ /* FIXME: let the caller know if some lvm devices failed to be scanned. */
+
+ log_debug_devs("Scanned %d devices: %d for lvm, %d failed.",
+ dm_list_size(&done_devs), scan_lvm_count, scan_failed_count);
+
+ return 0;
+}
+
+/*
+ * Scan and cache lvm data from all devices on the system.
+ * The cache should be empty/reset before calling this.
+ */
+
+int label_scan(struct cmd_context *cmd)
+{
+ struct dm_list all_devs;
+ struct dev_iter *iter;
+ struct device_list *devl;
+ struct device *dev;
+ struct io_engine *ioe;
+
+ log_debug_devs("Finding devices to scan");
+
+ dm_list_init(&all_devs);
+
+ /*
+ * Iterate through all the devices in dev-cache (block devs that appear
+ * under /dev that could possibly hold a PV and are not excluded by
+ * filters). Read each to see if it's an lvm device, and if so
+ * populate lvmcache with some basic info about the device and the VG
+ * on it. This info will be used by the vg_read() phase of the
+ * command.
+ */
+ dev_cache_full_scan(cmd->full_filter);
+
+ if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
+ log_error("Scanning failed to get devices.");
+ return 0;
+ }
+
+ while ((dev = dev_iter_get(iter))) {
+ if (!(devl = dm_pool_zalloc(cmd->mem, sizeof(*devl))))
+ return 0;
+ devl->dev = dev;
+ dm_list_add(&all_devs, &devl->list);
+
+ /*
+ * label_scan should not generally be called a second time,
+ * so this will usually not be true.
+ */
+ if (_in_bcache(dev))
+ bcache_invalidate_fd(scan_bcache, dev->fd);
+ };
+ dev_iter_destroy(iter);
+
+ if (!scan_bcache) {
+
+ /*
+ * 100 is arbitrary, it's the max number of concurrent aio's
+ * possible, i.e, the number of devices that can be read at
+ * once. Should this be configurable?
+ */
+ if (!(ioe = create_async_io_engine(100)))
+ return 0;
+
+ /*
+ * Configure one cache block for each device on the system.
+ * We won't generally need to cache that many because some
+ * of the devs will not be lvm devices, and we don't need
+ * an entry for those. We might want to change this.
+ */
+ if (!(scan_bcache = bcache_create(BCACHE_BLOCK_SIZE_IN_SECTORS, dm_list_size(&all_devs), ioe)))
+ return 0;
+ }
+
+ return _scan_list(&all_devs);
+}
+
+/*
+ * Scan and cache lvm data from the listed devices. If a device is already
+ * scanned and cached, this replaces the previously cached lvm data for the
+ * device. This is called when vg_read() wants to guarantee that it is using
+ * the latest data from the devices in the VG (since the scan populated bcache
+ * without a lock.)
+ */
+
+int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs)
+{
+ struct device_list *devl;
+
+ dm_list_iterate_items(devl, devs) {
+ if (_in_bcache(devl->dev))
+ bcache_invalidate_fd(scan_bcache, devl->dev->fd);
+ }
+
+ return _scan_list(devs);
+}
+
+void label_scan_invalidate(struct device *dev)
+{
+ if (_in_bcache(dev)) {
+ dev->flags &= ~DEV_IN_BCACHE;
+ bcache_invalidate_fd(scan_bcache, dev->fd);
+ dev_close(dev);
+ }
+}
+
+/*
+ * Undo label_scan()
+ *
+ * Close devices that are open because bcache is holding blocks for them.
+ * Destroy the bcache.
+ */
+
+void label_scan_destroy(struct cmd_context *cmd)
+{
+ struct dev_iter *iter;
+ struct device *dev;
+
+ if (!scan_bcache)
+ return;
+
+ if (!(iter = dev_iter_create(cmd->full_filter, 0))) {
+ return;
+ }
+
+ while ((dev = dev_iter_get(iter)))
+ label_scan_invalidate(dev);
+ dev_iter_destroy(iter);
+
+ bcache_destroy(scan_bcache);
+ scan_bcache = NULL;
+}
+
+/*
+ * Read (or re-read) and process (or re-process) the data for a device. This
+ * will reset (clear and repopulate) the bcache and lvmcache info for this
+ * device. There are only a couple odd places that want to reread a specific
+ * device, this is not a commonly used function.
+ */
+
+/* FIXME: remove unused_sector arg */
+
+int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector)
+{
+ struct dm_list one_dev;
+ struct device_list *devl;
+ int ret;
+
+ /* scanning is done by list, so make a single item list for this dev */
+ if (!(devl = dm_zalloc(sizeof(*devl))))
+ return 0;
+ devl->dev = dev;
+ dm_list_init(&one_dev);
+ dm_list_add(&one_dev, &devl->list);
+
+ if (_in_bcache(dev))
+ bcache_invalidate_fd(scan_bcache, dev->fd);
+
+ ret = _scan_list(&one_dev);
+
+ /*
+ * FIXME: this ugliness of returning a pointer to the label is
+ * temporary until the callers can be updated to not use this.
+ */
+ if (labelp) {
+ struct lvmcache_info *info;
+
+ info = lvmcache_info_from_pvid(dev->pvid, dev, 1);
+ if (info)
+ *labelp = lvmcache_get_label(info);
+ }
+
+ return ret;
+}
+
+/*
+ * Read a label from a specfic, non-zero sector. This is used in only
+ * one place: pvck -> pv_analyze.
+ */
+
+int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector)
+{
+ if (scan_sector) {
+ /* TODO: not yet implemented */
+ /* When is this done? When does it make sense? Is it actually possible? */
+ return 0;
+ }
+
+ return label_read(dev, labelp, 0);
+}
+
diff --git a/lib/label/label.h b/lib/label/label.h
index ea11290..d9e36bc 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -18,6 +18,8 @@
#include "uuid.h"
#include "device.h"
+#include "bcache.h"
+#include "toolcontext.h"
#define LABEL_ID "LABELONE"
#define LABEL_SIZE SECTOR_SIZE /* Think very carefully before changing this */
@@ -63,7 +65,7 @@ struct label_ops {
* Read a label from a volume.
*/
int (*read) (struct labeller * l, struct device * dev,
- void *buf, struct label ** label);
+ void *label_buf, struct label ** label);
/*
* Populate label_type etc.
@@ -94,10 +96,17 @@ int label_register_handler(struct labeller *handler);
struct labeller *label_get_handler(const char *name);
int label_remove(struct device *dev);
-int label_read(struct device *dev, struct label **result,
- uint64_t scan_sector);
int label_write(struct device *dev, struct label *label);
struct label *label_create(struct labeller *labeller);
void label_destroy(struct label *label);
+extern struct bcache *scan_bcache;
+
+int label_scan(struct cmd_context *cmd);
+int label_scan_devs(struct cmd_context *cmd, struct dm_list *devs);
+void label_scan_invalidate(struct device *dev);
+void label_scan_destroy(struct cmd_context *cmd);
+int label_read(struct device *dev, struct label **labelp, uint64_t unused_sector);
+int label_read_sector(struct device *dev, struct label **labelp, uint64_t scan_sector);
+
#endif
diff --git a/lib/metadata/metadata-exported.h b/lib/metadata/metadata-exported.h
index 2bc7927..73041cf 100644
--- a/lib/metadata/metadata-exported.h
+++ b/lib/metadata/metadata-exported.h
@@ -377,6 +377,19 @@ struct pv_segment {
*/
#define FMT_INSTANCE_PRIVATE_MDAS 0x00000008U
+/*
+ * Each VG has its own fid struct. The fid for a VG describes where
+ * the metadata for that VG can be found. The lists hold mda locations.
+ *
+ * label scan finds the metadata locations (devs and offsets) for a VG,
+ * and saves this info in lvmcache vginfo/info lists.
+ *
+ * vg_read() then creates an fid for a given VG, and the mda locations
+ * from lvmcache are copied onto the fid lists. Those mda locations
+ * are read again by vg_read() to get VG metadata that is used to
+ * create the 'vg' struct.
+ */
+
struct format_instance {
unsigned ref_count; /* Refs to this fid from VG and PV structs */
struct dm_pool *mem;
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index 2249d2f..00b7737 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -719,6 +719,10 @@ int check_pv_dev_sizes(struct volume_group *vg)
* source file. All the following and more are only used by liblvm:
*
* . get_pvs()
+ * . get_vgids()
+ * . get_vgnames()
+ * . lvmcache_get_vgids()
+ * . lvmcache_get_vgnames()
* . the vg->pvs_to_write list and pv_to_write struct
*/
@@ -3909,12 +3913,16 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
/* Ensure contents of all metadata areas match - else do recovery */
inconsistent_mda_count=0;
dm_list_iterate_items(mda, &fid->metadata_areas_in_use) {
+ struct device *mda_dev = mda_get_device(mda);
+
use_previous_vg = 0;
+ log_debug_metadata("Reading VG %s from %s", vgname, dev_name(mda_dev));
+
if ((use_precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
(!use_precommitted &&
- !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg)) {
+ !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
inconsistent = 1;
vg_fmtdata = NULL;
continue;
@@ -4106,7 +4114,7 @@ static struct volume_group *_vg_read(struct cmd_context *cmd,
if ((use_precommitted &&
!(vg = mda->ops->vg_read_precommit(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg) ||
(!use_precommitted &&
- !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg, 0)) && !use_previous_vg)) {
+ !(vg = mda->ops->vg_read(fid, vgname, mda, &vg_fmtdata, &use_previous_vg)) && !use_previous_vg)) {
inconsistent = 1;
vg_fmtdata = NULL;
continue;
diff --git a/lib/metadata/metadata.h b/lib/metadata/metadata.h
index 1fa14e8..5b8d690 100644
--- a/lib/metadata/metadata.h
+++ b/lib/metadata/metadata.h
@@ -80,8 +80,7 @@ struct metadata_area_ops {
const char *vg_name,
struct metadata_area * mda,
struct cached_vg_fmtdata **vg_fmtdata,
- unsigned *use_previous_vg,
- int single_device);
+ unsigned *use_previous_vg);
struct volume_group *(*vg_read_precommit) (struct format_instance * fi,
const char *vg_name,
struct metadata_area * mda,
@@ -183,6 +182,11 @@ void mda_set_ignored(struct metadata_area *mda, unsigned mda_ignored);
unsigned mda_locns_match(struct metadata_area *mda1, struct metadata_area *mda2);
struct device *mda_get_device(struct metadata_area *mda);
+/*
+ * fic is used to create an fid. It's used to pass fmt/vgname/vgid args
+ * to create_instance() which creates an fid for the specified vg.
+ */
+
struct format_instance_ctx {
uint32_t type;
union {
6 years
master - [makefile] add -laio to makefiles
by David Teigland
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=697fa7aa1dbcc2ed8e1...
Commit: 697fa7aa1dbcc2ed8e141d9d13118cb38d609161
Parent: 93fc9374294aae679faa23aef0bd631db2e9a31a
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Feb 8 09:32:19 2018 -0600
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Fri Apr 20 11:13:17 2018 -0500
[makefile] add -laio to makefiles
---
daemons/clvmd/Makefile.in | 2 +-
liblvm/Makefile.in | 2 +-
scripts/Makefile.in | 2 +-
tools/Makefile.in | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/daemons/clvmd/Makefile.in b/daemons/clvmd/Makefile.in
index 7b1b49b..83af00e 100644
--- a/daemons/clvmd/Makefile.in
+++ b/daemons/clvmd/Makefile.in
@@ -74,7 +74,7 @@ TARGETS = \
include $(top_builddir)/make.tmpl
-LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS)
+LIBS += $(LVMINTERNAL_LIBS) -ldevmapper $(PTHREAD_LIBS) -laio
CFLAGS += -fno-strict-aliasing $(EXTRA_EXEC_CFLAGS)
INSTALL_TARGETS = \
diff --git a/liblvm/Makefile.in b/liblvm/Makefile.in
index 6d0325c..be3049a 100644
--- a/liblvm/Makefile.in
+++ b/liblvm/Makefile.in
@@ -43,7 +43,7 @@ LDDEPS += $(top_builddir)/lib/liblvm-internal.a
include $(top_builddir)/make.tmpl
LDFLAGS += -L$(top_builddir)/lib -L$(top_builddir)/daemons/dmeventd
-LIBS += $(LVMINTERNAL_LIBS) -ldevmapper
+LIBS += $(LVMINTERNAL_LIBS) -ldevmapper -laio
.PHONY: install_dynamic install_static install_include install_pkgconfig
diff --git a/scripts/Makefile.in b/scripts/Makefile.in
index d06766f..720ae9f 100644
--- a/scripts/Makefile.in
+++ b/scripts/Makefile.in
@@ -28,7 +28,7 @@ ifeq ("@APPLIB@", "yes")
ifeq ("@BUILD_DMEVENTD@", "yes")
LDFLAGS += -Wl,-rpath-link,$(top_builddir)/daemons/dmeventd
endif
- LVMLIBS = @LVM2APP_LIB@ -ldevmapper
+ LVMLIBS = @LVM2APP_LIB@ -ldevmapper -laio
endif
LVM_SCRIPTS = lvmdump.sh lvmconf.sh
diff --git a/tools/Makefile.in b/tools/Makefile.in
index 61c6f38..103b767 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -95,7 +95,7 @@ ifeq ("@STATIC_LINK@", "yes")
INSTALL_CMDLIB_TARGETS += install_cmdlib_static
endif
-LVMLIBS = $(LVMINTERNAL_LIBS) -ldevmapper
+LVMLIBS = $(LVMINTERNAL_LIBS) -ldevmapper -laio
LIB_VERSION = $(LIB_VERSION_LVM)
CLEAN_TARGETS = liblvm2cmd.$(LIB_SUFFIX) $(TARGETS_DM) \
6 years