1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

pvck: use new dump routines for old output

Use the recently added dump routines to produce the
old/traditional pvck output, and remove the code that
had been used for that.

The validation/checking done by the new routines means
that new lines prefixed with CHECK are printed for
incorrect values.
This commit is contained in:
David Teigland 2019-06-05 16:23:23 -05:00
parent 356ea897cc
commit 2b241eb1f6
4 changed files with 92 additions and 306 deletions

View File

@ -121,157 +121,6 @@ static struct device *_mda_get_device_raw(struct metadata_area *mda)
return mdac->area.dev; return mdac->area.dev;
} }
/*
* For circular region between region_start and region_start + region_size,
* back up one SECTOR_SIZE from 'region_ptr' and return the value.
* This allows reverse traversal through text metadata area to find old
* metadata.
*
* Parameters:
* region_start: start of the region (bytes)
* region_size: size of the region (bytes)
* region_ptr: pointer within the region (bytes)
* NOTE: region_start <= region_ptr <= region_start + region_size
*/
static uint64_t _get_prev_sector_circular(uint64_t region_start,
uint64_t region_size,
uint64_t region_ptr)
{
if (region_ptr >= region_start + SECTOR_SIZE)
return region_ptr - SECTOR_SIZE;
return (region_start + region_size - SECTOR_SIZE);
}
/*
* Analyze a metadata area for old metadata records in the circular buffer.
* This function just looks through and makes a first pass at the data in
* the sectors for particular things.
* FIXME: do something with each metadata area (try to extract vg, write
* raw data to file, etc)
*/
static int _pv_analyze_mda_raw (const struct format_type * fmt,
struct metadata_area *mda)
{
struct mda_header *mdah;
struct raw_locn *rlocn;
uint64_t area_start;
uint64_t area_size;
uint64_t prev_sector, prev_sector2;
uint64_t latest_mrec_offset;
uint64_t offset;
uint64_t offset2;
size_t size;
size_t size2;
char *buf=NULL;
struct device_area *area;
struct mda_context *mdac;
int r=0;
mdac = (struct mda_context *) mda->metadata_locn;
log_print("Found text metadata area: offset=" FMTu64 ", size="
FMTu64, mdac->area.start, mdac->area.size);
area = &mdac->area;
if (!(mdah = raw_read_mda_header(fmt, area, mda_is_primary(mda))))
goto_out;
rlocn = mdah->raw_locns;
/*
* The device area includes the metadata header as well as the
* records, so remove the metadata header from the start and size
*/
area_start = area->start + MDA_HEADER_SIZE;
area_size = area->size - MDA_HEADER_SIZE;
latest_mrec_offset = rlocn->offset + area->start;
/*
* Start searching at rlocn (point of live metadata) and go
* backwards.
*/
prev_sector = _get_prev_sector_circular(area_start, area_size,
latest_mrec_offset);
offset = prev_sector;
size = SECTOR_SIZE;
offset2 = size2 = 0;
while (prev_sector != latest_mrec_offset) {
prev_sector2 = prev_sector;
prev_sector = _get_prev_sector_circular(area_start, area_size,
prev_sector);
if (prev_sector > prev_sector2)
goto_out;
/*
* FIXME: for some reason, the whole metadata region from
* area->start to area->start+area->size is not used.
* Only ~32KB seems to contain valid metadata records
* (LVM2 format - format_text). As a result, I end up with
* "dm_config_maybe_section" returning true when there's no valid
* metadata in a sector (sectors with all nulls).
*/
if (!(buf = malloc(size + size2)))
goto_out;
if (!dev_read_bytes(area->dev, offset, size, buf)) {
log_error("Failed to read dev %s offset %llu size %llu",
dev_name(area->dev),
(unsigned long long)offset,
(unsigned long long)size);
goto out;
}
if (size2) {
if (!dev_read_bytes(area->dev, offset2, size2, buf + size)) {
log_error("Failed to read dev %s offset %llu size %llu",
dev_name(area->dev),
(unsigned long long)offset2,
(unsigned long long)size2);
goto out;
}
}
/*
* FIXME: We could add more sophisticated metadata detection
*/
if (dm_config_maybe_section(buf, size + size2)) {
/* FIXME: Validate region, pull out timestamp?, etc */
/* FIXME: Do something with this region */
log_verbose ("Found LVM2 metadata record at "
"offset=" FMTu64 ", size=" FMTsize_t ", "
"offset2=" FMTu64 " size2=" FMTsize_t,
offset, size, offset2, size2);
offset = prev_sector;
size = SECTOR_SIZE;
offset2 = size2 = 0;
} else {
/*
* Not a complete metadata record, assume we have
* metadata and just increase the size and offset.
* Start the second region if the previous sector is
* wrapping around towards the end of the disk.
*/
if (prev_sector > offset) {
offset2 = prev_sector;
size2 += SECTOR_SIZE;
} else {
offset = prev_sector;
size += SECTOR_SIZE;
}
}
free(buf);
buf = NULL;
}
r = 1;
out:
free(buf);
return r;
}
static int _text_lv_setup(struct format_instance *fid __attribute__((unused)), static int _text_lv_setup(struct format_instance *fid __attribute__((unused)),
struct logical_volume *lv) struct logical_volume *lv)
{ {
@ -1962,7 +1811,6 @@ static struct metadata_area_ops _metadata_text_raw_ops = {
.mda_free_sectors = _mda_free_sectors_raw, .mda_free_sectors = _mda_free_sectors_raw,
.mda_total_sectors = _mda_total_sectors_raw, .mda_total_sectors = _mda_total_sectors_raw,
.mda_in_vg = _mda_in_vg_raw, .mda_in_vg = _mda_in_vg_raw,
.pv_analyze_mda = _pv_analyze_mda_raw,
.mda_locns_match = _mda_locns_match_raw, .mda_locns_match = _mda_locns_match_raw,
.mda_get_device = _mda_get_device_raw, .mda_get_device = _mda_get_device_raw,
}; };

View File

@ -1198,66 +1198,6 @@ int label_read(struct device *dev)
return 1; return 1;
} }
/*
* 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, uint64_t read_sector)
{
struct block *bb = NULL;
uint64_t block_num;
uint64_t block_sector;
uint64_t start_sector;
int is_lvm_device = 0;
int result;
int ret;
block_num = read_sector / BCACHE_BLOCK_SIZE_IN_SECTORS;
block_sector = block_num * BCACHE_BLOCK_SIZE_IN_SECTORS;
start_sector = read_sector % BCACHE_BLOCK_SIZE_IN_SECTORS;
if (!label_scan_open(dev)) {
log_error("Error opening device %s for prefetch %llu sector.",
dev_name(dev), (unsigned long long)block_num);
return false;
}
bcache_prefetch(scan_bcache, dev->bcache_fd, block_num);
if (!bcache_get(scan_bcache, dev->bcache_fd, block_num, 0, &bb)) {
log_error("Scan failed to read %s at %llu",
dev_name(dev), (unsigned long long)block_num);
ret = 0;
goto out;
}
/*
* TODO: check if scan_sector is larger than the bcache block size.
* If it is, we need to fetch a later block from bcache.
*/
result = _process_block(NULL, NULL, dev, bb, block_sector, start_sector, &is_lvm_device);
if (!result && is_lvm_device) {
log_error("Scan failed to process %s", dev_name(dev));
ret = 0;
goto out;
}
if (!result || !is_lvm_device) {
log_error("Could not find LVM label on %s", dev_name(dev));
ret = 0;
goto out;
}
ret = 1;
out:
if (bb)
bcache_put(bb);
return ret;
}
int label_scan_setup_bcache(void) int label_scan_setup_bcache(void)
{ {
if (!scan_bcache) { if (!scan_bcache) {

View File

@ -4664,41 +4664,6 @@ int is_real_vg(const char *vg_name)
return (vg_name && *vg_name != '#'); return (vg_name && *vg_name != '#');
} }
static int _analyze_mda(struct metadata_area *mda, void *baton)
{
const struct format_type *fmt = baton;
mda->ops->pv_analyze_mda(fmt, mda);
return 1;
}
/*
* Returns:
* 0 - fail
* 1 - success
*/
int pv_analyze(struct cmd_context *cmd, struct device *dev,
uint64_t label_sector)
{
struct label *label;
struct lvmcache_info *info;
if (!(label = lvmcache_get_dev_label(dev))) {
log_error("Could not find LVM label on %s", dev_name(dev));
return 0;
}
log_print("Found label on %s, sector %"PRIu64", type=%.8s",
dev_name(dev), label->sector, label->type);
/*
* Next, loop through metadata areas
*/
info = label->info;
lvmcache_foreach_mda(info, _analyze_mda, (void *)lvmcache_fmt(info));
return 1;
}
/* FIXME: remove / combine this with locking? */ /* FIXME: remove / combine this with locking? */
int vg_check_write_mode(struct volume_group *vg) int vg_check_write_mode(struct volume_group *vg)
{ {

View File

@ -83,13 +83,16 @@ static char *_chars_to_hexstr(void *in, void *out, int num, int max, const char
return out; return out;
} }
static int _check_label_header(struct label_header *lh, uint64_t labelsector) static int _check_label_header(struct label_header *lh, uint64_t labelsector,
int *found_label)
{ {
uint32_t crc; uint32_t crc;
int good_id = 1, good_type = 1;
int bad = 0; int bad = 0;
if (memcmp(lh->id, LABEL_ID, sizeof(lh->id))) { if (memcmp(lh->id, LABEL_ID, sizeof(lh->id))) {
log_print("CHECK: label_header.id expected %s", LABEL_ID); log_print("CHECK: label_header.id expected %s", LABEL_ID);
good_id = 0;
bad++; bad++;
} }
@ -113,9 +116,14 @@ static int _check_label_header(struct label_header *lh, uint64_t labelsector)
if (memcmp(lh->type, LVM2_LABEL, sizeof(lh->type))) { if (memcmp(lh->type, LVM2_LABEL, sizeof(lh->type))) {
log_print("CHECK: label_header.type expected %s", LVM2_LABEL); log_print("CHECK: label_header.type expected %s", LVM2_LABEL);
good_type = 0;
bad++; bad++;
} }
/* Report a label is found if at least id and type are correct. */
if (found_label && good_id && good_type)
*found_label = 1;
if (bad) if (bad)
return 0; return 0;
return 1; return 1;
@ -140,10 +148,11 @@ static int _check_pv_header(struct pv_header *ph)
* mda_offset/mda_size are from the pv_header/disk_locn and could * mda_offset/mda_size are from the pv_header/disk_locn and could
* be incorrect. * be incorrect.
*/ */
static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_offset, uint64_t mda_size) static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_offset, uint64_t mda_size, int *found_header)
{ {
char str[256]; char str[256];
uint32_t crc; uint32_t crc;
int good_magic = 1;
int bad = 0; int bad = 0;
crc = calc_crc(INITIAL_CRC, (uint8_t *)mh->magic, crc = calc_crc(INITIAL_CRC, (uint8_t *)mh->magic,
@ -156,6 +165,7 @@ static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_of
if (memcmp(mh->magic, FMTT_MAGIC, sizeof(mh->magic))) { if (memcmp(mh->magic, FMTT_MAGIC, sizeof(mh->magic))) {
log_print("CHECK: mda_header_%d.magic expected 0x%s", mda_num, _chars_to_hexstr((void *)&FMTT_MAGIC, str, 16, 256, "mda_header.magic")); log_print("CHECK: mda_header_%d.magic expected 0x%s", mda_num, _chars_to_hexstr((void *)&FMTT_MAGIC, str, 16, 256, "mda_header.magic"));
good_magic = 0;
bad++; bad++;
} }
@ -174,6 +184,10 @@ static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_of
bad++; bad++;
} }
/* Report a header is found if at least magic is correct. */
if (found_header && good_magic)
*found_header = 1;
if (bad) if (bad)
return 0; return 0;
return 1; return 1;
@ -684,9 +698,10 @@ static int _dump_meta_text(struct device *dev,
config_destroy(cft); config_destroy(cft);
} }
log_print("metadata text at %llu crc 0x%x # vgname %s seqno %u", if (print_fields || print_metadata)
(unsigned long long)(mda_offset + meta_offset), crc, log_print("metadata text at %llu crc 0x%x # vgname %s seqno %u",
vgname ? vgname : "?", seqno); (unsigned long long)(mda_offset + meta_offset), crc,
vgname ? vgname : "?", seqno);
if (!print_metadata) if (!print_metadata)
goto out; goto out;
@ -720,6 +735,7 @@ static int _dump_meta_text(struct device *dev,
static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields, static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields,
struct device *dev, struct device *dev,
int *found_label,
uint64_t *mda1_offset, uint64_t *mda1_size, uint64_t *mda1_offset, uint64_t *mda1_size,
uint64_t *mda2_offset, uint64_t *mda2_size) uint64_t *mda2_offset, uint64_t *mda2_size)
{ {
@ -771,7 +787,7 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, int print_fields,
log_print("label_header.type %s", _chars_to_str(lh->type, str, 8, 256, "label_header.type")); log_print("label_header.type %s", _chars_to_str(lh->type, str, 8, 256, "label_header.type"));
} }
if (!_check_label_header(lh, labelsector)) if (!_check_label_header(lh, labelsector, found_label))
bad++; bad++;
/* /*
@ -972,7 +988,8 @@ static int _dump_mda_header(struct cmd_context *cmd,
const char *tofile, const char *tofile,
struct device *dev, struct device *dev,
uint64_t mda_offset, uint64_t mda_size, uint64_t mda_offset, uint64_t mda_size,
uint32_t *checksum0_ret) uint32_t *checksum0_ret,
int *found_header)
{ {
char str[256]; char str[256];
char *buf; char *buf;
@ -1018,7 +1035,7 @@ static int _dump_mda_header(struct cmd_context *cmd,
log_print("mda_header_%d.size %llu", mda_num, (unsigned long long)xlate64(mh->size)); log_print("mda_header_%d.size %llu", mda_num, (unsigned long long)xlate64(mh->size));
} }
if (!_check_mda_header(mh, mda_num, mda_offset, mda_size)) if (!_check_mda_header(mh, mda_num, mda_offset, mda_size, found_header))
bad++; bad++;
if (print_area) { if (print_area) {
@ -1108,7 +1125,7 @@ static int _dump_headers(struct cmd_context *cmd,
label_scan_setup_bcache(); label_scan_setup_bcache();
if (!_dump_label_and_pv_header(cmd, 1, dev, if (!_dump_label_and_pv_header(cmd, 1, dev, NULL,
&mda1_offset, &mda1_size, &mda2_offset, &mda2_size)) &mda1_offset, &mda1_size, &mda2_offset, &mda2_size))
bad++; bad++;
@ -1125,7 +1142,7 @@ static int _dump_headers(struct cmd_context *cmd,
* which may have been corrupted. * which may have been corrupted.
*/ */
if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum)) if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, NULL))
bad++; bad++;
/* /*
@ -1136,7 +1153,7 @@ static int _dump_headers(struct cmd_context *cmd,
* but there is a valid header elsewhere. * but there is a valid header elsewhere.
*/ */
if (mda2_offset) { if (mda2_offset) {
if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum)) if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum, NULL))
bad++; bad++;
/* This probably indicates that one was committed and the other not. */ /* This probably indicates that one was committed and the other not. */
@ -1181,7 +1198,7 @@ static int _dump_metadata(struct cmd_context *cmd,
label_scan_setup_bcache(); label_scan_setup_bcache();
if (!_dump_label_and_pv_header(cmd, 0, dev, if (!_dump_label_and_pv_header(cmd, 0, dev, NULL,
&mda1_offset, &mda1_size, &mda2_offset, &mda2_size)) &mda1_offset, &mda1_size, &mda2_offset, &mda2_size))
bad++; bad++;
@ -1204,14 +1221,14 @@ static int _dump_metadata(struct cmd_context *cmd,
*/ */
if (mda_num == 1) { if (mda_num == 1) {
if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, 4096, mda1_size, &mda1_checksum)) if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, 4096, mda1_size, &mda1_checksum, NULL))
bad++; bad++;
} else if (mda_num == 2) { } else if (mda_num == 2) {
if (!mda2_offset) { if (!mda2_offset) {
log_print("CHECK: second mda not found"); log_print("CHECK: second mda not found");
bad++; bad++;
} else { } else {
if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, mda2_offset, mda2_size, &mda2_checksum)) if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, mda2_offset, mda2_size, &mda2_checksum, NULL))
bad++; bad++;
} }
} }
@ -1223,16 +1240,59 @@ static int _dump_metadata(struct cmd_context *cmd,
return ECMD_PROCESSED; return ECMD_PROCESSED;
} }
static int _dump_found(struct cmd_context *cmd, struct device *dev,
uint64_t labelsector)
{
uint64_t mda1_offset = 0, mda1_size = 0, mda2_offset = 0, mda2_size = 0;
uint32_t mda1_checksum = 0, mda2_checksum = 0;
int found_label = 0, found_header1 = 0, found_header2 = 0;
int bad = 0;
if (!_dump_label_and_pv_header(cmd, 0, dev, &found_label,
&mda1_offset, &mda1_size, &mda2_offset, &mda2_size))
bad++;
if (found_label && mda1_offset) {
if (!_dump_mda_header(cmd, 0, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, &found_header1))
bad++;
}
if (found_label && mda2_offset) {
if (!_dump_mda_header(cmd, 0, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum, &found_header2))
bad++;
}
if (found_label)
log_print("Found label on %s, sector %llu, type=LVM2 001",
dev_name(dev), (unsigned long long)labelsector);
else {
log_error("Could not find LVM label on %s", dev_name(dev));
return 0;
}
if (found_header1)
log_print("Found text metadata area: offset=%llu, size=%llu",
(unsigned long long)mda1_offset,
(unsigned long long)mda1_size);
if (found_header2)
log_print("Found text metadata area: offset=%llu, size=%llu",
(unsigned long long)mda2_offset,
(unsigned long long)mda2_size);
if (bad)
return 0;
return 1;
}
int pvck(struct cmd_context *cmd, int argc, char **argv) int pvck(struct cmd_context *cmd, int argc, char **argv)
{ {
struct dm_list devs;
struct device_list *devl;
struct device *dev; struct device *dev;
const char *dump; const char *dump;
const char *pv_name; const char *pv_name;
uint64_t labelsector; uint64_t labelsector = 1;
int bad = 0;
int i; int i;
int ret_max = ECMD_PROCESSED;
if (arg_is_set(cmd, dump_ARG)) { if (arg_is_set(cmd, dump_ARG)) {
dump = arg_str_value(cmd, dump_ARG, NULL); dump = arg_str_value(cmd, dump_ARG, NULL);
@ -1253,56 +1313,29 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
return ECMD_FAILED; return ECMD_FAILED;
} }
labelsector = arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0)); /*
* The old/original form of pvck, which did not do much,
* but this is here to preserve the historical output.
*/
dm_list_init(&devs); if (arg_is_set(cmd, labelsector_ARG))
labelsector = arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0));
label_scan_setup_bcache();
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
pv_name = argv[i]; pv_name = argv[i];
dev = dev_cache_get(cmd, pv_name, cmd->filter); if (!(dev = dev_cache_get(cmd, argv[i], cmd->filter))) {
if (!dev) {
log_error("Device %s %s.", pv_name, dev_cache_filtered_reason(pv_name)); log_error("Device %s %s.", pv_name, dev_cache_filtered_reason(pv_name));
continue; continue;
} }
if (!(devl = zalloc(sizeof(*devl)))) if (!_dump_found(cmd, dev, labelsector))
continue; bad++;
devl->dev = dev;
dm_list_add(&devs, &devl->list);
} }
label_scan_setup_bcache(); if (bad)
label_scan_devs(cmd, cmd->filter, &devs); return ECMD_FAILED;
return ECMD_PROCESSED;
dm_list_iterate_items(devl, &devs) {
/*
* The scan above will populate lvmcache with any info from the
* standard locations at the start of the device. Now populate
* lvmcache with any info from non-standard offsets.
*
* FIXME: is it possible for a real lvm label sector to be
* anywhere other than the first four sectors of the disk?
* If not, drop the code in label_read_sector/find_lvm_header
* that supports searching at any sector.
*/
if (labelsector) {
if (!label_read_sector(devl->dev, labelsector)) {
stack;
ret_max = ECMD_FAILED;
continue;
}
}
if (!pv_analyze(cmd, devl->dev, labelsector)) {
stack;
ret_max = ECMD_FAILED;
}
}
return ret_max;
} }