Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d5a06f9a7df5a43b2e231…
Commit: d5a06f9a7df5a43b2e2311db62ff8d3011217d74
Parent: b876dbfc245b8fe0a4c433b39d214652455c3f9e
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Thu Jul 1 17:25:43 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 6 10:18:07 2021 -0500
pvscan: skip indexing devices used by LVs
dev_cache_index_devs() is taking a large amount of time
when there are many PVs. The index keeps track of
devices that are currently in use by active LVs. This
info is used to print warnings for users in some limited
cases.
The checks/warnings that are enabled by the index are not
needed by pvscan --cache, so disable it in this case.
This may be expanded to other cases in future commits.
dev_cache_index_devs should also be improved in another
commit to avoid the extreme delays with many devices.
---
lib/commands/toolcontext.c | 1 +
lib/commands/toolcontext.h | 1 +
lib/device/dev-cache.c | 9 +++++----
lib/device/dev-cache.h | 2 +-
lib/metadata/metadata.c | 3 ++-
tools/lvmdevices.c | 2 +-
tools/pvscan.c | 2 ++
7 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/lib/commands/toolcontext.c b/lib/commands/toolcontext.c
index e2be89d0f..b295a20ef 100644
--- a/lib/commands/toolcontext.c
+++ b/lib/commands/toolcontext.c
@@ -1608,6 +1608,7 @@ struct cmd_context *create_toolcontext(unsigned is_clvmd,
cmd->handles_missing_pvs = 0;
cmd->handles_unknown_segments = 0;
cmd->hosttags = 0;
+ cmd->check_devs_used = 1;
dm_list_init(&cmd->arg_value_groups);
dm_list_init(&cmd->formats);
dm_list_init(&cmd->segtypes);
diff --git a/lib/commands/toolcontext.h b/lib/commands/toolcontext.h
index a47b7d760..34808ce46 100644
--- a/lib/commands/toolcontext.h
+++ b/lib/commands/toolcontext.h
@@ -192,6 +192,7 @@ struct cmd_context {
unsigned filter_nodata_only:1; /* only use filters that do not require data from the dev */
unsigned run_by_dmeventd:1; /* command is being run by dmeventd */
unsigned sysinit:1; /* --sysinit is used */
+ unsigned check_devs_used:1; /* check devs used by LVs */
/*
* Devices and filtering.
diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c
index d7fa93fd6..bb0d0f211 100644
--- a/lib/device/dev-cache.c
+++ b/lib/device/dev-cache.c
@@ -1139,7 +1139,7 @@ static int _insert(const char *path, const struct stat *info,
return 1;
}
-void dev_cache_scan(void)
+void dev_cache_scan(struct cmd_context *cmd)
{
log_debug_devs("Creating list of system devices.");
@@ -1147,7 +1147,8 @@ void dev_cache_scan(void)
_insert_dirs(&_cache.dirs);
- (void) dev_cache_index_devs();
+ if (cmd->check_devs_used)
+ (void) dev_cache_index_devs();
}
int dev_cache_has_scanned(void)
@@ -1583,7 +1584,7 @@ struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct
log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d",
(int)MAJOR(dev), (int)MINOR(dev));
- dev_cache_scan();
+ dev_cache_scan(cmd);
d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev);
if (!d)
@@ -1953,7 +1954,7 @@ int setup_devices(struct cmd_context *cmd)
* This will not open or read any devices, but may look at sysfs properties.
* This list of devs comes from looking /dev entries, or from asking libudev.
*/
- dev_cache_scan();
+ dev_cache_scan(cmd);
/*
* Match entries from cmd->use_devices with device structs in dev-cache.
diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h
index 9b7e39d33..c3f5eddda 100644
--- a/lib/device/dev-cache.h
+++ b/lib/device/dev-cache.h
@@ -48,7 +48,7 @@ int dev_cache_exit(void);
*/
int dev_cache_check_for_open_devices(void);
-void dev_cache_scan(void);
+void dev_cache_scan(struct cmd_context *cmd);
int dev_cache_has_scanned(void);
int dev_cache_add_dir(const char *path);
diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c
index d5b28a58f..0cbf67869 100644
--- a/lib/metadata/metadata.c
+++ b/lib/metadata/metadata.c
@@ -5132,7 +5132,8 @@ struct volume_group *vg_read(struct cmd_context *cmd, const char *vg_name, const
if (!check_pv_dev_sizes(vg))
log_warn("WARNING: One or more devices used as PVs in VG %s have changed sizes.", vg->name);
- _check_devs_used_correspond_with_vg(vg);
+ if (cmd->check_devs_used)
+ _check_devs_used_correspond_with_vg(vg);
if (!_access_vg_lock_type(cmd, vg, lockd_state, &failure)) {
/* Either FAILED_LOCK_TYPE or FAILED_LOCK_MODE were set. */
diff --git a/tools/lvmdevices.c b/tools/lvmdevices.c
index 3448bdd14..5117277a0 100644
--- a/tools/lvmdevices.c
+++ b/tools/lvmdevices.c
@@ -171,7 +171,7 @@ int lvmdevices(struct cmd_context *cmd, int argc, char **argv)
log_error("Failed to read the devices file.");
return ECMD_FAILED;
}
- dev_cache_scan();
+ dev_cache_scan(cmd);
device_ids_match(cmd);
if (arg_is_set(cmd, check_ARG) || arg_is_set(cmd, update_ARG)) {
diff --git a/tools/pvscan.c b/tools/pvscan.c
index f8d27372b..464501ad5 100644
--- a/tools/pvscan.c
+++ b/tools/pvscan.c
@@ -1627,6 +1627,8 @@ int pvscan_cache_cmd(struct cmd_context *cmd, int argc, char **argv)
dm_list_init(&complete_vgnames);
+ cmd->check_devs_used = 0;
+
if (do_activate &&
!find_config_tree_bool(cmd, global_event_activation_CFG, NULL)) {
log_verbose("Ignoring pvscan --cache -aay because event_activation is disabled.");
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=b876dbfc245b8fe0a4c43…
Commit: b876dbfc245b8fe0a4c433b39d214652455c3f9e
Parent: e035e323508383fdcd9df0ef036d276a9c9909ab
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Tue Jun 29 12:40:03 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 6 10:10:23 2021 -0500
scan: move metadata vgname check
There have been two separate checks for metadata
validity: first that the metadata text begins with
a valid VG name, and second the checksum of the
metadata text. These happen in different places,
which means there have been two separate error paths
for invalid metadata. This also causes large metadata
to be read in multiple parts, the first part is read
just to check the vgname, and then remaining parts are
read later when the full metadata is needed.
This patch moves the vg name verification so it's
done just before the checksum verification, which
results in a single error path for invalid metadata,
and causes the entire metadata to be read together
rather that in parts from different parts of the code.
---
lib/config/config.c | 25 +++++++++++-
lib/format_text/format-text.c | 94 +++++--------------------------------------
2 files changed, 33 insertions(+), 86 deletions(-)
diff --git a/lib/config/config.c b/lib/config/config.c
index 485063a3d..25a87c983 100644
--- a/lib/config/config.c
+++ b/lib/config/config.c
@@ -501,6 +501,9 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
checksum_fn_t checksum_fn, uint32_t checksum,
int checksum_only, int no_dup_node_check)
{
+ char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
+ int namelen = 0;
+ int bad_name = 0;
char *fb, *fe;
int r = 0;
int sz, use_plain_read = 1;
@@ -548,6 +551,23 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
fb = buf;
+ if (!(dev->flags & DEV_REGULAR)) {
+ memcpy(namebuf, buf, NAME_LEN);
+
+ while (namebuf[namelen] && !isspace(namebuf[namelen]) && namebuf[namelen] != '{' && namelen < (NAME_LEN - 1))
+ namelen++;
+ namebuf[namelen] = '\0';
+
+ /*
+ * Check that the text metadata begins with a valid name.
+ */
+ if (!validate_name(namebuf)) {
+ log_warn("WARNING: Metadata location on %s at offset %llu begins with invalid name.",
+ dev_name(dev), (unsigned long long)offset);
+ bad_name = 1;
+ }
+ }
+
/*
* The checksum passed in is the checksum from the mda_header
* preceding this metadata. They should always match.
@@ -557,10 +577,13 @@ int config_file_read_fd(struct dm_config_tree *cft, struct device *dev, dev_io_r
if (checksum_fn && checksum !=
(checksum_fn(checksum_fn(INITIAL_CRC, (const uint8_t *)fb, size),
(const uint8_t *)(fb + size), size2))) {
- log_error("%s: Checksum error at offset %" PRIu64, dev_name(dev), (uint64_t) offset);
+ log_warn("WARNING: Checksum error on %s at offset %llu.", dev_name(dev), (unsigned long long)offset);
goto out;
}
+ if (bad_name)
+ goto out;
+
if (!checksum_only) {
fe = fb + size + size2;
if (no_dup_node_check) {
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index dd550a6eb..26e55cec4 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -296,24 +296,11 @@ static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
const char *vgname,
int *precommitted)
{
- size_t len;
- char vgnamebuf[NAME_LEN + 2] __attribute__((aligned(8)));
struct raw_locn *rlocn, *rlocn_precommitted;
- struct lvmcache_info *info;
- struct lvmcache_vgsummary vgsummary_orphan = {
- .vgname = FMT_TEXT_ORPHAN_VG_NAME,
- };
- int rlocn_was_ignored;
-
- dm_list_init(&vgsummary_orphan.pvsummaries);
-
- memcpy(&vgsummary_orphan.vgid, FMT_TEXT_ORPHAN_VG_NAME, sizeof(FMT_TEXT_ORPHAN_VG_NAME));
rlocn = mdah->raw_locns; /* Slot 0 */
rlocn_precommitted = rlocn + 1; /* Slot 1 */
- rlocn_was_ignored = rlocn_is_ignored(rlocn);
-
/* Should we use precommitted metadata? */
if (*precommitted && rlocn_precommitted->size &&
(rlocn_precommitted->offset != rlocn->offset)) {
@@ -338,42 +325,7 @@ static struct raw_locn *_read_metadata_location_vg(struct cmd_context *cmd,
if (!rlocn->offset && !rlocn->size)
return NULL;
- /*
- * Don't try to check existing metadata
- * if given vgname is an empty string.
- */
- if (!vgname || !*vgname)
- return rlocn;
-
- /*
- * If live rlocn has ignored flag, data will be out-of-date so skip further checks.
- */
- if (rlocn_was_ignored)
- return rlocn;
-
- /*
- * Verify that the VG metadata pointed to by the rlocn
- * begins with a valid vgname.
- */
- memset(vgnamebuf, 0, sizeof(vgnamebuf));
-
- if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, vgnamebuf))
- goto fail;
-
- if (!strncmp(vgnamebuf, vgname, len = strlen(vgname)) &&
- (isspace(vgnamebuf[len]) || vgnamebuf[len] == '{'))
- return rlocn;
- fail:
- log_error("Metadata on %s at %llu has wrong VG name \"%s\" expected %s.",
- dev_name(dev_area->dev),
- (unsigned long long)(dev_area->start + rlocn->offset),
- vgnamebuf, vgname);
-
- if ((info = lvmcache_info_from_pvid(dev_area->dev->pvid, dev_area->dev, 0)) &&
- !lvmcache_update_vgname_and_id(cmd, info, &vgsummary_orphan))
- stack;
-
- return NULL;
+ return rlocn;
}
/*
@@ -487,9 +439,13 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
rlocn->checksum,
&when, &desc);
- if (!vg) {
- /* FIXME: detect and handle errors, and distinguish from the optimization
- that skips parsing the metadata which also returns NULL. */
+ if (!vg && !*use_previous_vg) {
+ log_warn("WARNING: failed to read metadata text on %s at %llu size %llu for VG %s.",
+ dev_name(area->dev),
+ (unsigned long long)(area->start + rlocn->offset),
+ (unsigned long long)rlocn->size,
+ vgname);
+ return NULL;
}
log_debug_metadata("Found metadata on %s at %llu size %llu for VG %s",
@@ -498,7 +454,7 @@ static struct volume_group *_vg_read_raw_area(struct cmd_context *cmd,
(unsigned long long)rlocn->size,
vgname);
- if (vg && precommitted)
+ if (precommitted)
vg->status |= PRECOMMITTED;
out:
@@ -1533,8 +1489,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
{
struct raw_locn *rlocn;
uint32_t wrap = 0;
- unsigned int len = 0;
- char namebuf[NAME_LEN + 1] __attribute__((aligned(8)));
uint64_t max_size;
if (!mdah) {
@@ -1563,36 +1517,6 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 0;
}
- /*
- * This code reading the start of the metadata area and verifying that
- * it looks like a vgname can be removed. The checksum verifies it.
- */
- log_debug_metadata("Reading metadata_vgname summary from %s at %llu",
- dev_name(dev_area->dev),
- (unsigned long long)(dev_area->start + rlocn->offset));
-
- memset(namebuf, 0, sizeof(namebuf));
-
- if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, namebuf))
- stack;
-
- while (namebuf[len] && !isspace(namebuf[len]) && namebuf[len] != '{' &&
- len < (NAME_LEN - 1))
- len++;
-
- namebuf[len] = '\0';
-
- /*
- * Check that the text metadata in the circular buffer begins with a
- * valid vg name.
- */
- if (!validate_name(namebuf)) {
- log_warn("WARNING: Metadata location on %s at %llu begins with invalid VG name.",
- dev_name(dev_area->dev),
- (unsigned long long)(dev_area->start + rlocn->offset));
- return 0;
- }
-
/*
* This function is used to read the vg summary during label scan.
* Save the text start location and checksum during scan. After the VG
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=e035e323508383fdcd9df…
Commit: e035e323508383fdcd9df0ef036d276a9c9909ab
Parent: d89942d157e49168d069a65f77a6ecb2c155b3fb
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jun 28 18:10:47 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 6 10:10:23 2021 -0500
scan: retry reading metadata on error
If label_scan encounters bad vg metadata, invalidate
bcache data for the device and reread the mda_header
and metadata text back to back. With concurrent commands
modifying large metadata, it's possible that the entire
metadata area can be rewritten in the time between a
command reading the mda_header and reading the metadata
text that the header points to. Since the label_scan
is just assembling an initial overview of devices, it
doesn't use locking to serialize with other commands
that may be modifying the vg metadata at the same time.
---
lib/format_text/format-text.c | 8 ++++++++
lib/format_text/text_label.c | 35 +++++++++++++++++++++++++++++++++++
lib/label/label.c | 5 +++++
lib/label/label.h | 1 +
4 files changed, 49 insertions(+)
diff --git a/lib/format_text/format-text.c b/lib/format_text/format-text.c
index 64ad4677c..dd550a6eb 100644
--- a/lib/format_text/format-text.c
+++ b/lib/format_text/format-text.c
@@ -1563,6 +1563,14 @@ int read_metadata_location_summary(const struct format_type *fmt,
return 0;
}
+ /*
+ * This code reading the start of the metadata area and verifying that
+ * it looks like a vgname can be removed. The checksum verifies it.
+ */
+ log_debug_metadata("Reading metadata_vgname summary from %s at %llu",
+ dev_name(dev_area->dev),
+ (unsigned long long)(dev_area->start + rlocn->offset));
+
memset(namebuf, 0, sizeof(namebuf));
if (!dev_read_bytes(dev_area->dev, dev_area->start + rlocn->offset, NAME_LEN, namebuf))
diff --git a/lib/format_text/text_label.c b/lib/format_text/text_label.c
index be5195039..7bc7a1ed3 100644
--- a/lib/format_text/text_label.c
+++ b/lib/format_text/text_label.c
@@ -327,6 +327,9 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
{
struct mda_context *mdac = (struct mda_context *) mda->metadata_locn;
struct mda_header *mdah;
+ int retries = 0;
+
+ retry:
if (!(mdah = raw_read_mda_header(fmt, &mdac->area, (mda->mda_num == 1), 0, bad_fields))) {
log_warn("WARNING: bad metadata header on %s at %llu.",
@@ -354,6 +357,38 @@ static int _read_mda_header_and_metadata(const struct format_type *fmt,
if (vgsummary->zero_offset)
return 1;
+ /*
+ * This code is used by label_scan to get a summary of the
+ * VG metadata that will be properly read later by vg_read.
+ * The initial read of this device during label_scan
+ * populates bcache with the first 128K of data from the
+ * device. That block of data contains the mda_header
+ * (at 4k) but will often not include the metadata text,
+ * which is often located further into the metadata area
+ * (beyond the 128K block saved in bcache.)
+ * So read_metadata_location_summary will usually get the
+ * mda_header from bcache which was read initially, and
+ * then it will often need to do a new disk read to get
+ * the actual metadata text that the mda_header points to.
+ * Since there is no locking around label_scan, it's
+ * possible (but very rare) that the entire metadata area
+ * can be rewritten by other commands between the time that
+ * this command read the mda_header and the time that it
+ * reads the metadata text. This means the expected metadata
+ * text isn't found, and an error is returned here.
+ * To handle this, invalidate all data in bcache for this
+ * device and reread the mda_header and metadata text back to
+ * back, so inconsistency is less likely (without locking
+ * there's no guarantee, e.g. if the command is blocked
+ * somehow between the two reads.)
+ */
+ if (!retries) {
+ log_print("Retrying metadata scan.");
+ retries++;
+ dev_invalidate(mdac->area.dev);
+ goto retry;
+ }
+
log_warn("WARNING: bad metadata text on %s in mda%d",
dev_name(mdac->area.dev), mda->mda_num);
*bad_fields |= BAD_MDA_TEXT;
diff --git a/lib/label/label.c b/lib/label/label.c
index 50107edc8..ac84b6293 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -1704,6 +1704,11 @@ bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len)
return bcache_invalidate_bytes(scan_bcache, dev->bcache_di, start, len);
}
+void dev_invalidate(struct device *dev)
+{
+ bcache_invalidate_di(scan_bcache, dev->bcache_di);
+}
+
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len)
{
return dev_set_bytes(dev, start, len, 0);
diff --git a/lib/label/label.h b/lib/label/label.h
index fcdc309ac..32ceebc34 100644
--- a/lib/label/label.h
+++ b/lib/label/label.h
@@ -130,6 +130,7 @@ bool dev_write_bytes(struct device *dev, uint64_t start, size_t len, void *data)
bool dev_write_zeros(struct device *dev, uint64_t start, size_t len);
bool dev_set_bytes(struct device *dev, uint64_t start, size_t len, uint8_t val);
bool dev_invalidate_bytes(struct device *dev, uint64_t start, size_t len);
+void dev_invalidate(struct device *dev);
void dev_set_last_byte(struct device *dev, uint64_t offset);
void dev_unset_last_byte(struct device *dev);
Gitweb: https://sourceware.org/git/?p=lvm2.git;a=commitdiff;h=d89942d157e49168d069a…
Commit: d89942d157e49168d069a65f77a6ecb2c155b3fb
Parent: a47e20a0929bc0d399851c398e7e3d06e97daf65
Author: David Teigland <teigland(a)redhat.com>
AuthorDate: Mon Jun 28 17:09:09 2021 -0500
Committer: David Teigland <teigland(a)redhat.com>
CommitterDate: Tue Jul 6 10:10:23 2021 -0500
scan: don't hold bcache block during scan
This allows data from the bcache block to be
invalidated and reread if needed.
---
lib/label/label.c | 71 +++++++++++++++++++++++++++++--------------------------
1 file changed, 38 insertions(+), 33 deletions(-)
diff --git a/lib/label/label.c b/lib/label/label.c
index cfb9ebc80..50107edc8 100644
--- a/lib/label/label.c
+++ b/lib/label/label.c
@@ -264,9 +264,8 @@ static bool _in_bcache(struct device *dev)
}
static struct labeller *_find_lvm_header(struct device *dev,
- char *scan_buf,
- uint32_t scan_buf_sectors,
- char *label_buf,
+ char *headers_buf,
+ int headers_buf_size,
uint64_t *label_sector,
uint64_t block_sector,
uint64_t start_sector)
@@ -277,24 +276,13 @@ static struct labeller *_find_lvm_header(struct device *dev,
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 = start_sector; sector < start_sector + LABEL_SCAN_SECTORS;
sector += LABEL_SIZE >> SECTOR_SHIFT) {
- /*
- * The scan_buf passed in is a bcache block, which is
- * BCACHE_BLOCK_SIZE_IN_SECTORS large. So if start_sector is
- * one of the last couple sectors in that buffer, we need to
- * break early.
- */
- if (sector >= scan_buf_sectors)
+ if ((sector * 512) >= headers_buf_size)
break;
- lh = (struct label_header *) (scan_buf + (sector << SECTOR_SHIFT));
+ lh = (struct label_header *) (headers_buf + (sector << SECTOR_SHIFT));
if (!memcmp(lh->id, LABEL_ID, sizeof(lh->id))) {
if (found) {
@@ -332,7 +320,6 @@ static struct labeller *_find_lvm_header(struct device *dev,
labeller_ret = li->l;
found = 1;
- memcpy(label_buf, lh, LABEL_SIZE);
if (label_sector)
*label_sector = block_sector + sector;
break;
@@ -354,13 +341,13 @@ static struct labeller *_find_lvm_header(struct device *dev,
* are performed in the processing functions to get that data.
*/
static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
- struct device *dev, struct block *bb,
+ struct device *dev, char *headers_buf, int headers_buf_size,
uint64_t block_sector, uint64_t start_sector,
int *is_lvm_device)
{
- char label_buf[LABEL_SIZE] __attribute__((aligned(8)));
+ char *label_buf;
struct labeller *labeller;
- uint64_t sector = 0;
+ uint64_t label_sector = 0;
int is_duplicate = 0;
int ret = 0;
@@ -396,13 +383,9 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
}
/*
- * 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.
+ * Finds the data sector containing the label.
*/
- if (!(labeller = _find_lvm_header(dev, bb->data, BCACHE_BLOCK_SIZE_IN_SECTORS, label_buf, §or, block_sector, start_sector))) {
+ if (!(labeller = _find_lvm_header(dev, headers_buf, headers_buf_size, &label_sector, block_sector, start_sector))) {
/*
* Non-PVs exit here
@@ -427,6 +410,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
dev->flags |= DEV_SCAN_FOUND_LABEL;
*is_lvm_device = 1;
+ label_buf = headers_buf + (label_sector * 512);
/*
* This is the point where the scanning code dives into the rest of
@@ -436,7 +420,7 @@ static int _process_block(struct cmd_context *cmd, struct dev_filter *f,
* info/vginfo structs. That lvmcache info is used later when the
* command wants to read the VG to do something to it.
*/
- ret = labeller->ops->read(cmd, labeller, dev, label_buf, sector, &is_duplicate);
+ ret = labeller->ops->read(cmd, labeller, dev, label_buf, label_sector, &is_duplicate);
if (!ret) {
if (is_duplicate) {
@@ -670,9 +654,12 @@ static void _invalidate_di(struct bcache *cache, int di)
* its info is removed from lvmcache.
*/
+#define HEADERS_BUF_SIZE 4096
+
static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
struct dm_list *devs, int want_other_devs, int *failed)
{
+ char headers_buf[HEADERS_BUF_SIZE];
struct dm_list wait_devs;
struct dm_list done_devs;
struct dm_list reopen_devs;
@@ -738,14 +725,35 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
scan_read_errors++;
scan_failed_count++;
lvmcache_del_dev(devl->dev);
+ if (bb)
+ bcache_put(bb);
} else {
- log_debug_devs("Processing data from device %s %d:%d di %d block %p",
+ /* copy the first 4k from bb that will contain label_header */
+
+ memcpy(headers_buf, bb->data, HEADERS_BUF_SIZE);
+
+ /*
+ * "put" the bcache block before process_block because
+ * processing metadata may need to invalidate and reread
+ * metadata that's covered by bb. invalidate/reread is
+ * not allowed while bb is held. The functions for
+ * filtering and scanning metadata for this device use
+ * dev_read_bytes(), which will generally grab the
+ * bcache block/data that we're putting here. Since
+ * we're doing put, it's possible but not likely that
+ * bcache could drop the block before dev_read_bytes()
+ * uses it again, in which case bcache will reread it
+ * from disk for dev_read_bytes().
+ */
+ bcache_put(bb);
+
+ log_debug_devs("Processing data from device %s %d:%d di %d",
dev_name(devl->dev),
(int)MAJOR(devl->dev->dev),
(int)MINOR(devl->dev->dev),
- devl->dev->bcache_di, (void *)bb);
+ devl->dev->bcache_di);
- ret = _process_block(cmd, f, devl->dev, bb, 0, 0, &is_lvm_device);
+ ret = _process_block(cmd, f, devl->dev, headers_buf, sizeof(headers_buf), 0, 0, &is_lvm_device);
if (!ret && is_lvm_device) {
log_debug_devs("Scan failed to process %s", dev_name(devl->dev));
@@ -754,9 +762,6 @@ static int _scan_list(struct cmd_context *cmd, struct dev_filter *f,
}
}
- 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