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;
}
/*
* 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)),
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_total_sectors = _mda_total_sectors_raw,
.mda_in_vg = _mda_in_vg_raw,
.pv_analyze_mda = _pv_analyze_mda_raw,
.mda_locns_match = _mda_locns_match_raw,
.mda_get_device = _mda_get_device_raw,
};

View File

@ -1198,66 +1198,6 @@ int label_read(struct device *dev)
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)
{
if (!scan_bcache) {

View File

@ -4664,41 +4664,6 @@ int is_real_vg(const char *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? */
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;
}
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;
int good_id = 1, good_type = 1;
int bad = 0;
if (memcmp(lh->id, LABEL_ID, sizeof(lh->id))) {
log_print("CHECK: label_header.id expected %s", LABEL_ID);
good_id = 0;
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))) {
log_print("CHECK: label_header.type expected %s", LVM2_LABEL);
good_type = 0;
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)
return 0;
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
* 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];
uint32_t crc;
int good_magic = 1;
int bad = 0;
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))) {
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++;
}
@ -174,6 +184,10 @@ static int _check_mda_header(struct mda_header *mh, int mda_num, uint64_t mda_of
bad++;
}
/* Report a header is found if at least magic is correct. */
if (found_header && good_magic)
*found_header = 1;
if (bad)
return 0;
return 1;
@ -684,6 +698,7 @@ static int _dump_meta_text(struct device *dev,
config_destroy(cft);
}
if (print_fields || print_metadata)
log_print("metadata text at %llu crc 0x%x # vgname %s seqno %u",
(unsigned long long)(mda_offset + meta_offset), crc,
vgname ? vgname : "?", seqno);
@ -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,
struct device *dev,
int *found_label,
uint64_t *mda1_offset, uint64_t *mda1_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"));
}
if (!_check_label_header(lh, labelsector))
if (!_check_label_header(lh, labelsector, found_label))
bad++;
/*
@ -972,7 +988,8 @@ static int _dump_mda_header(struct cmd_context *cmd,
const char *tofile,
struct device *dev,
uint64_t mda_offset, uint64_t mda_size,
uint32_t *checksum0_ret)
uint32_t *checksum0_ret,
int *found_header)
{
char str[256];
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));
}
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++;
if (print_area) {
@ -1108,7 +1125,7 @@ static int _dump_headers(struct cmd_context *cmd,
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))
bad++;
@ -1125,7 +1142,7 @@ static int _dump_headers(struct cmd_context *cmd,
* 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++;
/*
@ -1136,7 +1153,7 @@ static int _dump_headers(struct cmd_context *cmd,
* but there is a valid header elsewhere.
*/
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++;
/* 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();
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))
bad++;
@ -1204,14 +1221,14 @@ static int _dump_metadata(struct cmd_context *cmd,
*/
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++;
} else if (mda_num == 2) {
if (!mda2_offset) {
log_print("CHECK: second mda not found");
bad++;
} 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++;
}
}
@ -1223,16 +1240,59 @@ static int _dump_metadata(struct cmd_context *cmd,
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)
{
struct dm_list devs;
struct device_list *devl;
struct device *dev;
const char *dump;
const char *pv_name;
uint64_t labelsector;
uint64_t labelsector = 1;
int bad = 0;
int i;
int ret_max = ECMD_PROCESSED;
if (arg_is_set(cmd, dump_ARG)) {
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;
}
/*
* The old/original form of pvck, which did not do much,
* but this is here to preserve the historical output.
*/
if (arg_is_set(cmd, labelsector_ARG))
labelsector = arg_uint64_value(cmd, labelsector_ARG, UINT64_C(0));
dm_list_init(&devs);
label_scan_setup_bcache();
for (i = 0; i < argc; i++) {
dm_unescape_colons_and_at_signs(argv[i], NULL, NULL);
pv_name = argv[i];
dev = dev_cache_get(cmd, pv_name, cmd->filter);
if (!dev) {
if (!(dev = dev_cache_get(cmd, argv[i], cmd->filter))) {
log_error("Device %s %s.", pv_name, dev_cache_filtered_reason(pv_name));
continue;
}
if (!(devl = zalloc(sizeof(*devl))))
continue;
devl->dev = dev;
dm_list_add(&devs, &devl->list);
if (!_dump_found(cmd, dev, labelsector))
bad++;
}
label_scan_setup_bcache();
label_scan_devs(cmd, cmd->filter, &devs);
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;
if (bad)
return ECMD_FAILED;
return ECMD_PROCESSED;
}