mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
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.
This commit is contained in:
parent
e035e32350
commit
b876dbfc24
@ -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) {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user