1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-10-27 11:33:19 +03:00

pvck: new dump option to extract metadata

The new command 'pvck --dump metadata PV' will extract
the current version of VG metadata from a PV for testing
and debugging.  --dump metadata_area extracts the entire
text metadata area.
This commit is contained in:
David Teigland
2019-05-22 14:25:08 -05:00
parent 1022b88a66
commit 52586b1039
9 changed files with 386 additions and 3 deletions

View File

@@ -2602,3 +2602,221 @@ bad:
return NULL;
}
static char *_read_metadata_text(struct cmd_context *cmd, struct device *dev,
uint64_t area_start, uint64_t area_size,
uint32_t *len, uint64_t *disk_offset)
{
struct mda_header *mh;
struct raw_locn *rlocn_slot0;
uint64_t text_offset, text_size;
char *area_buf;
char *text_buf;
/*
* Read the entire metadata area, including mda_header and entire
* circular buffer.
*/
if (!(area_buf = malloc(area_size)))
return_NULL;
if (!dev_read_bytes(dev, area_start, area_size, area_buf)) {
log_error("Failed to read device %s at %llu size %llu",
dev_name(dev),
(unsigned long long)area_start,
(unsigned long long)area_size);
return NULL;
}
mh = (struct mda_header *)area_buf;
_xlate_mdah(mh);
rlocn_slot0 = &mh->raw_locns[0];
text_offset = rlocn_slot0->offset;
text_size = rlocn_slot0->size;
/*
* Copy and return the current metadata text out of the metadata area.
*/
if (!(text_buf = malloc(text_size)))
return_NULL;
memcpy(text_buf, area_buf + text_offset, text_size);
if (len)
*len = (uint32_t)text_size;
if (disk_offset)
*disk_offset = area_start + text_offset;
free(area_buf);
return text_buf;
}
int dump_metadata_text(struct cmd_context *cmd,
const char *vgname,
const char *vgid,
struct device *dev,
struct metadata_area *mda,
const char *tofile)
{
char *textbuf;
struct format_instance *fid;
struct format_instance_ctx fic;
struct mda_context *mdac;
struct volume_group *vg;
unsigned use_previous_vg = 0;
uint32_t textlen = 0;
uint32_t textcrc;
uint64_t text_disk_offset;
int ret = 0;
/*
* Set up overhead/abstractions for reading a given vgname
* (fmt/fid/fic/vgid).
*/
fic.type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS;
fic.context.vg_ref.vg_name = vgname;
fic.context.vg_ref.vg_id = vgid;
if (!(fid = _text_create_text_instance(cmd->fmt, &fic))) {
log_error("Failed to create format instance");
return 0;
}
mdac = mda->metadata_locn;
/*
* Read the VG metadata from the device as a raw chunk of original text.
*/
textbuf = _read_metadata_text(cmd, dev,
mdac->area.start, mdac->area.size,
&textlen, &text_disk_offset);
if (!textbuf || !textlen) {
log_error("No metadata text found on %s", dev_name(dev));
_text_destroy_instance(fid);
return 0;
}
textcrc = calc_crc(INITIAL_CRC, (uint8_t *)textbuf, textlen);
/*
* Read the same VG metadata, but imported/parsed into a vg struct
* format so we know it's valid/parsable, and can look at values in it.
*/
if (!(vg = _vg_read_raw(fid, vgname, mda, NULL, &use_previous_vg))) {
log_warn("WARNING: parse error for metadata on %s.", dev_name(dev));
_text_destroy_instance(fid);
}
log_print("Metadata for %s from %s at %llu size %u with seqno %u checksum 0x%x.",
vgname, dev_name(dev),
(unsigned long long)text_disk_offset, textlen,
vg ? vg->seqno : 0, textcrc);
if (!tofile) {
log_print("---");
printf("%s\n", textbuf);
log_print("---");
} else {
FILE *fp;
if (!(fp = fopen(tofile, "wx"))) {
log_error("Failed to create file %s", tofile);
goto out;
}
fprintf(fp, "%s", textbuf);
if (fflush(fp))
stack;
if (fclose(fp))
stack;
}
if (vg)
release_vg(vg);
free(textbuf);
ret = 1;
out:
return ret;
}
static char *_read_metadata_area(struct cmd_context *cmd, struct device *dev,
uint64_t area_start, uint64_t area_size)
{
char *area_buf;
/*
* Read the entire metadata area, including mda_header and entire
* circular buffer.
*/
if (!(area_buf = malloc(area_size)))
return_NULL;
if (!dev_read_bytes(dev, area_start, area_size, area_buf)) {
log_error("Failed to read device %s at %llu size %llu",
dev_name(dev),
(unsigned long long)area_start,
(unsigned long long)area_size);
return NULL;
}
return area_buf;
}
int dump_metadata_area(struct cmd_context *cmd,
const char *vgname,
const char *vgid,
struct device *dev,
struct metadata_area *mda,
const char *tofile)
{
char *areabuf;
char *textbuf;
struct mda_context *mdac;
int ret = 0;
mdac = mda->metadata_locn;
areabuf = _read_metadata_area(cmd, dev,
mdac->area.start, mdac->area.size);
if (!areabuf) {
log_error("No metadata area found on %s", dev_name(dev));
return 0;
}
log_print("Metadata buffer for %s from %s in area at %llu size %llu offset 512.",
vgname, dev_name(dev),
(unsigned long long)mdac->area.start,
(unsigned long long)mdac->area.size);
/* text starts after mda_header which uses 512 bytes */
textbuf = areabuf + 512;
if (!tofile) {
/* N.B. this will often include unprintable data */
log_print("---");
fwrite(textbuf, mdac->area.size - 512, 1, stdout);
log_print("---");
} else {
FILE *fp;
if (!(fp = fopen(tofile, "wx"))) {
log_error("Failed to create file %s", tofile);
goto out;
}
fwrite(textbuf, mdac->area.size - 512, 1, fp);
if (fflush(fp))
stack;
if (fclose(fp))
stack;
}
ret = 1;
out:
free(areabuf);
return ret;
}