mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
pvck: allow disk locations to be specified
using --settings: mda_offset=<offset> mda_size=<size> can be used in place of the offset/size that normally come from headers. metadata_offset=<offset> prints/saves one instance of metadata text at the given offset, in metadata_all or metadata_search.
This commit is contained in:
parent
53126ceada
commit
9cf08836ef
@ -459,6 +459,10 @@ arg(setphysicalvolumesize_ARG, '\0', "setphysicalvolumesize", sizemb_VAL, 0, 0,
|
||||
"Overrides the automatically detected size of the PV.\n"
|
||||
"Use with care, or prior to reducing the physical size of the device.\n")
|
||||
|
||||
arg(settings_ARG, '\0', "settings", string_VAL, ARG_GROUPABLE, 0,
|
||||
"Specifies command specific settings in \"Key = Value\" form.\n"
|
||||
"Repeat this option to specify multiple values.\n")
|
||||
|
||||
arg(poll_ARG, '\0', "poll", bool_VAL, 0, 0,
|
||||
"When yes, start the background transformation of an LV.\n"
|
||||
"An incomplete transformation, e.g. pvmove or lvconvert interrupted\n"
|
||||
|
@ -1437,7 +1437,7 @@ ID: pvck_general
|
||||
DESC: Check for metadata on a device
|
||||
|
||||
pvck --dump String PV
|
||||
OO: --file String, --pvmetadatacopies MetadataCopiesPV, --labelsector Number
|
||||
OO: --settings String, --file String, --pvmetadatacopies MetadataCopiesPV, --labelsector Number
|
||||
ID: pvck_dump
|
||||
DESC: Print metadata from a device
|
||||
|
||||
|
218
tools/pvck.c
218
tools/pvck.c
@ -23,6 +23,16 @@
|
||||
#define PRINT_CURRENT 1
|
||||
#define PRINT_ALL 2
|
||||
|
||||
struct settings {
|
||||
uint64_t metadata_offset; /* start of text metadata, from start of disk */
|
||||
uint64_t mda_offset; /* start of mda_header, from start of disk */
|
||||
uint64_t mda_size; /* size of metadata area (mda_header + text area) */
|
||||
|
||||
unsigned metadata_offset_set:1;
|
||||
unsigned mda_offset_set:1;
|
||||
unsigned mda_size_set:1;
|
||||
};
|
||||
|
||||
static char *_chars_to_str(void *in, void *out, int num, int max, const char *field)
|
||||
{
|
||||
char *i = in;
|
||||
@ -237,7 +247,7 @@ static void _copy_line(char *in, char *out, int *len)
|
||||
*len = i+1;
|
||||
}
|
||||
|
||||
static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct device *dev,
|
||||
static int _dump_all_text(struct cmd_context *cmd, struct settings *set, const char *tofile, struct device *dev,
|
||||
int mda_num, uint64_t mda_offset, uint64_t mda_size, char *buf)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
@ -253,6 +263,7 @@ static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct de
|
||||
uint32_t crc;
|
||||
uint64_t text_size;
|
||||
uint64_t meta_size;
|
||||
int metadata_offset_found = 0;
|
||||
int multiple_vgs = 0;
|
||||
int bad_end;
|
||||
int vgnamelen;
|
||||
@ -319,6 +330,19 @@ static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct de
|
||||
buf_off = 512 + (count * 512);
|
||||
p = buf + buf_off;
|
||||
|
||||
/*
|
||||
* user specified metadata in one location
|
||||
*/
|
||||
if (set->metadata_offset_set && (set->metadata_offset != (mda_offset + buf_off))) {
|
||||
count++;
|
||||
continue;
|
||||
}
|
||||
if (set->metadata_offset_set) {
|
||||
if (metadata_offset_found)
|
||||
break;
|
||||
metadata_offset_found = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* copy line of possible metadata to check for vgname
|
||||
*/
|
||||
@ -427,7 +451,8 @@ static int _dump_all_text(struct cmd_context *cmd, const char *tofile, struct de
|
||||
|
||||
if (fp) {
|
||||
fprintf(fp, "%s", text_buf);
|
||||
fprintf(fp, "\n--\n");
|
||||
if (!set->metadata_offset_set)
|
||||
fprintf(fp, "\n--\n");
|
||||
}
|
||||
|
||||
free(text_buf);
|
||||
@ -676,19 +701,6 @@ static int _dump_meta_area(struct device *dev, const char *tofile,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for any instance of id_str[] in the metadata area,
|
||||
* where the id_str indicates the start of a metadata copy
|
||||
* (which could be complete or a fragment.)
|
||||
* id_str is an open brace followed by id = <uuid>.
|
||||
*
|
||||
* {\n
|
||||
* id = "lL7Mnk-oCGn-Bde2-9B6S-44Z7-VrHa-wvfC3v"
|
||||
*
|
||||
* 1\23456789012345678901234567890123456789012345678
|
||||
* 10 20 30 40
|
||||
*/
|
||||
|
||||
static int _dump_current_text(struct device *dev,
|
||||
int print_fields, int print_metadata, const char *tofile,
|
||||
int mda_num, int rlocn_index,
|
||||
@ -1049,7 +1061,7 @@ static int _dump_label_and_pv_header(struct cmd_context *cmd, uint64_t labelsect
|
||||
* pv_header is.
|
||||
*/
|
||||
|
||||
static int _dump_mda_header(struct cmd_context *cmd,
|
||||
static int _dump_mda_header(struct cmd_context *cmd, struct settings *set,
|
||||
int print_fields, int print_metadata, int print_area,
|
||||
const char *tofile,
|
||||
struct device *dev,
|
||||
@ -1171,7 +1183,7 @@ static int _dump_mda_header(struct cmd_context *cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
_dump_all_text(cmd, tofile, dev, mda_num, mda_offset, mda_size, buf);
|
||||
_dump_all_text(cmd, set, tofile, dev, mda_num, mda_offset, mda_size, buf);
|
||||
}
|
||||
|
||||
/* Should we also check text metadata if it exists in rlocn1? */
|
||||
@ -1183,7 +1195,8 @@ static int _dump_mda_header(struct cmd_context *cmd,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _dump_headers(struct cmd_context *cmd, uint64_t labelsector, struct device *dev,
|
||||
static int _dump_headers(struct cmd_context *cmd, const char *dump, struct settings *set,
|
||||
uint64_t labelsector, struct device *dev,
|
||||
int argc, char **argv)
|
||||
{
|
||||
uint64_t mda1_offset = 0, mda1_size = 0, mda2_offset = 0, mda2_size = 0;
|
||||
@ -1200,31 +1213,14 @@ static int _dump_headers(struct cmd_context *cmd, uint64_t labelsector, struct d
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
/* N.B. mda1_size and mda2_size may be different */
|
||||
|
||||
/*
|
||||
* The first mda is always 4096 bytes from the start of the device.
|
||||
*
|
||||
* TODO: A second mda may not exist. If the pv_header says there
|
||||
* is no second mda, we may still want to check for a second mda
|
||||
* in case it's the pv_header that is wrong. Try looking for
|
||||
* an mda_header at 1MB prior to the end of the device, if
|
||||
* mda2_offset is 0 or if we don't find an mda_header at mda2_offset
|
||||
* which may have been corrupted.
|
||||
*/
|
||||
|
||||
if (!_dump_mda_header(cmd, 1, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, NULL))
|
||||
if (!_dump_mda_header(cmd, set, 1, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, NULL))
|
||||
bad++;
|
||||
|
||||
/*
|
||||
* mda2_offset may be incorrect. Probe for a valid mda_header at
|
||||
* mda2_offset and at other possible/expected locations, e.g.
|
||||
* 1MB before end of device. Call dump_mda_header with a different
|
||||
* offset than mda2_offset if there's no valid header at mda2_offset
|
||||
* 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, NULL))
|
||||
if (!_dump_mda_header(cmd, set, 1, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum, NULL))
|
||||
bad++;
|
||||
|
||||
/* This probably indicates that one was committed and the other not. */
|
||||
@ -1239,7 +1235,8 @@ static int _dump_headers(struct cmd_context *cmd, uint64_t labelsector, struct d
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _dump_metadata(struct cmd_context *cmd, uint64_t labelsector, struct device *dev,
|
||||
static int _dump_metadata(struct cmd_context *cmd, const char *dump, struct settings *set,
|
||||
uint64_t labelsector, struct device *dev,
|
||||
int argc, char **argv,
|
||||
int print_metadata, int print_area)
|
||||
{
|
||||
@ -1270,30 +1267,16 @@ static int _dump_metadata(struct cmd_context *cmd, uint64_t labelsector, struct
|
||||
|
||||
/*
|
||||
* The first mda is always 4096 bytes from the start of the device.
|
||||
*
|
||||
* TODO: A second mda may not exist. If the pv_header says there
|
||||
* is no second mda, we may still want to check for a second mda
|
||||
* in case it's the pv_header that is wrong. Try looking for
|
||||
* an mda_header at 1MB prior to the end of the device, if
|
||||
* mda2_offset is 0 or if we don't find an mda_header at mda2_offset
|
||||
* which may have been corrupted.
|
||||
*
|
||||
* mda2_offset may be incorrect. Probe for a valid mda_header at
|
||||
* mda2_offset and at other possible/expected locations, e.g.
|
||||
* 1MB before end of device. Call dump_mda_header with a different
|
||||
* offset than mda2_offset if there's no valid header at mda2_offset
|
||||
* but there is a valid header elsewhere.
|
||||
*/
|
||||
|
||||
if (mda_num == 1) {
|
||||
if (!_dump_mda_header(cmd, 0, print_metadata, print_area, tofile, dev, 4096, mda1_size, &mda1_checksum, NULL))
|
||||
if (!_dump_mda_header(cmd, set, 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, NULL))
|
||||
if (!_dump_mda_header(cmd, set, 0, print_metadata, print_area, tofile, dev, mda2_offset, mda2_size, &mda2_checksum, NULL))
|
||||
bad++;
|
||||
}
|
||||
}
|
||||
@ -1305,7 +1288,7 @@ static int _dump_metadata(struct cmd_context *cmd, uint64_t labelsector, struct
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _dump_found(struct cmd_context *cmd, uint64_t labelsector, struct device *dev)
|
||||
static int _dump_found(struct cmd_context *cmd, struct settings *set, uint64_t labelsector, struct device *dev)
|
||||
{
|
||||
uint64_t mda1_offset = 0, mda1_size = 0, mda2_offset = 0, mda2_size = 0;
|
||||
uint32_t mda1_checksum = 0, mda2_checksum = 0;
|
||||
@ -1318,12 +1301,12 @@ static int _dump_found(struct cmd_context *cmd, uint64_t labelsector, struct dev
|
||||
bad++;
|
||||
|
||||
if (found_label && mda1_offset) {
|
||||
if (!_dump_mda_header(cmd, 0, 0, 0, NULL, dev, 4096, mda1_size, &mda1_checksum, &found_header1))
|
||||
if (!_dump_mda_header(cmd, set, 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))
|
||||
if (!_dump_mda_header(cmd, set, 0, 0, 0, NULL, dev, mda2_offset, mda2_size, &mda2_checksum, &found_header2))
|
||||
bad++;
|
||||
}
|
||||
|
||||
@ -1358,16 +1341,14 @@ static int _dump_found(struct cmd_context *cmd, uint64_t labelsector, struct dev
|
||||
* zeroed/damaged.
|
||||
*/
|
||||
|
||||
static int _dump_search(struct cmd_context *cmd, uint64_t labelsector, struct device *dev,
|
||||
static int _dump_search(struct cmd_context *cmd, const char *dump, struct settings *set,
|
||||
uint64_t labelsector, struct device *dev,
|
||||
int argc, char **argv)
|
||||
{
|
||||
char str[256];
|
||||
const char *tofile = NULL;
|
||||
char *buf;
|
||||
struct mda_header *mh;
|
||||
uint64_t mda1_offset = 0, mda1_size = 0, mda2_offset = 0, mda2_size = 0;
|
||||
uint64_t mda_offset, mda_size;
|
||||
int found_header = 0;
|
||||
int mda_count = 0;
|
||||
int mda_num = 1;
|
||||
|
||||
@ -1384,9 +1365,6 @@ static int _dump_search(struct cmd_context *cmd, uint64_t labelsector, struct de
|
||||
&mda1_offset, &mda1_size, &mda2_offset, &mda2_size, &mda_count);
|
||||
|
||||
/*
|
||||
* TODO: allow mda_offset and mda_size to be specified on the
|
||||
* command line.
|
||||
*
|
||||
* For mda1, mda_offset is always 4096 bytes from the start of
|
||||
* device, and mda_size is the space between mda_offset and
|
||||
* the first PE which is usually at 1MB.
|
||||
@ -1404,7 +1382,10 @@ static int _dump_search(struct cmd_context *cmd, uint64_t labelsector, struct de
|
||||
* at the end of device (mod 1MB extra) can make mda2 even
|
||||
* larger.
|
||||
*/
|
||||
if (mda_num == 1) {
|
||||
if (set->mda_offset_set && set->mda_size_set) {
|
||||
mda_offset = set->mda_offset;
|
||||
mda_size = set->mda_size;
|
||||
} else if (mda_num == 1) {
|
||||
mda_offset = 4096;
|
||||
mda_size = ONE_MB_IN_BYTES - 4096;
|
||||
} else if (mda_num == 2) {
|
||||
@ -1436,7 +1417,7 @@ static int _dump_search(struct cmd_context *cmd, uint64_t labelsector, struct de
|
||||
(unsigned long long)mda2_size);
|
||||
}
|
||||
|
||||
log_print("Searching for metadata in mda%d at offset %llu size %llu", mda_num,
|
||||
log_print("Searching for metadata at offset %llu size %llu",
|
||||
(unsigned long long)mda_offset, (unsigned long long)mda_size);
|
||||
|
||||
if (!(buf = malloc(mda_size)))
|
||||
@ -1450,28 +1431,88 @@ static int _dump_search(struct cmd_context *cmd, uint64_t labelsector, struct de
|
||||
return ECMD_FAILED;
|
||||
}
|
||||
|
||||
mh = (struct mda_header *)buf;
|
||||
|
||||
/* Can be useful to know if there's a valid mda_header at this location. */
|
||||
log_print("mda_header_%d at %llu # metadata area", mda_num, (unsigned long long)mda_offset);
|
||||
log_print("mda_header_%d.checksum 0x%x", mda_num, xlate32(mh->checksum_xl));
|
||||
log_print("mda_header_%d.magic 0x%s", mda_num, _chars_to_hexstr(mh->magic, str, 16, 256, "mda_header.magic"));
|
||||
log_print("mda_header_%d.version %u", mda_num, xlate32(mh->version));
|
||||
log_print("mda_header_%d.start %llu", mda_num, (unsigned long long)xlate64(mh->start));
|
||||
log_print("mda_header_%d.size %llu", mda_num, (unsigned long long)xlate64(mh->size));
|
||||
|
||||
_check_mda_header(mh, mda_num, mda_offset, mda_size, &found_header);
|
||||
|
||||
log_print("searching for metadata text");
|
||||
|
||||
_dump_all_text(cmd, tofile, dev, mda_num, mda_offset, mda_size, buf);
|
||||
_dump_all_text(cmd, set, tofile, dev, mda_num, mda_offset, mda_size, buf);
|
||||
|
||||
free(buf);
|
||||
return ECMD_PROCESSED;
|
||||
}
|
||||
|
||||
static int _get_one_setting(struct cmd_context *cmd, struct settings *set, char *key, char *val)
|
||||
{
|
||||
if (!strncmp(key, "metadata_offset", strlen("metadata_offset"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&set->metadata_offset) != 1)
|
||||
goto_bad;
|
||||
set->metadata_offset_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "mda_offset", strlen("mda_offset"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&set->mda_offset) != 1)
|
||||
goto_bad;
|
||||
set->mda_offset_set = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!strncmp(key, "mda_size", strlen("mda_size"))) {
|
||||
if (sscanf(val, "%llu", (unsigned long long *)&set->mda_size) != 1)
|
||||
goto_bad;
|
||||
set->mda_size_set = 1;
|
||||
return 1;
|
||||
}
|
||||
bad:
|
||||
log_error("Invalid setting: %s", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_settings(struct cmd_context *cmd, struct settings *set)
|
||||
{
|
||||
struct arg_value_group_list *group;
|
||||
const char *str;
|
||||
char key[64];
|
||||
char val[64];
|
||||
int num;
|
||||
int pos;
|
||||
|
||||
memset(set, 0, sizeof(struct settings));
|
||||
|
||||
/*
|
||||
* "grouped" means that multiple --settings options can be used.
|
||||
* Each option is also allowed to contain multiple key = val pairs.
|
||||
*/
|
||||
|
||||
dm_list_iterate_items(group, &cmd->arg_value_groups) {
|
||||
if (!grouped_arg_is_set(group->arg_values, settings_ARG))
|
||||
continue;
|
||||
|
||||
if (!(str = grouped_arg_str_value(group->arg_values, settings_ARG, NULL)))
|
||||
break;
|
||||
|
||||
pos = 0;
|
||||
|
||||
while (pos < strlen(str)) {
|
||||
/* scan for "key1=val1 key2 = val2 key3= val3" */
|
||||
|
||||
memset(key, 0, sizeof(key));
|
||||
memset(val, 0, sizeof(val));
|
||||
|
||||
if (sscanf(str + pos, " %63[^=]=%63s %n", key, val, &num) != 2) {
|
||||
log_error("Invalid setting at: %s", str+pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos += num;
|
||||
|
||||
if (!_get_one_setting(cmd, set, key, val))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
{
|
||||
struct settings set;
|
||||
struct device *dev;
|
||||
const char *dump;
|
||||
const char *pv_name;
|
||||
@ -1496,6 +1537,9 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (!_get_settings(cmd, &set))
|
||||
return ECMD_FAILED;
|
||||
|
||||
label_scan_setup_bcache();
|
||||
|
||||
if (arg_is_set(cmd, dump_ARG)) {
|
||||
@ -1504,19 +1548,19 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
dump = arg_str_value(cmd, dump_ARG, NULL);
|
||||
|
||||
if (!strcmp(dump, "metadata"))
|
||||
return _dump_metadata(cmd, labelsector, dev, argc, argv, PRINT_CURRENT, 0);
|
||||
return _dump_metadata(cmd, dump, &set, labelsector, dev, argc, argv, PRINT_CURRENT, 0);
|
||||
|
||||
if (!strcmp(dump, "metadata_all"))
|
||||
return _dump_metadata(cmd, labelsector, dev, argc, argv, PRINT_ALL, 0);
|
||||
return _dump_metadata(cmd, dump, &set, labelsector, dev, argc, argv, PRINT_ALL, 0);
|
||||
|
||||
if (!strcmp(dump, "metadata_area"))
|
||||
return _dump_metadata(cmd, labelsector, dev, argc, argv, 0, 1);
|
||||
return _dump_metadata(cmd, dump, &set, labelsector, dev, argc, argv, 0, 1);
|
||||
|
||||
if (!strcmp(dump, "metadata_search"))
|
||||
return _dump_search(cmd, labelsector, dev, argc, argv);
|
||||
return _dump_search(cmd, dump, &set, labelsector, dev, argc, argv);
|
||||
|
||||
if (!strcmp(dump, "headers"))
|
||||
return _dump_headers(cmd, labelsector, dev, argc, argv);
|
||||
return _dump_headers(cmd, dump, &set, labelsector, dev, argc, argv);
|
||||
|
||||
log_error("Unknown dump value.");
|
||||
return ECMD_FAILED;
|
||||
@ -1535,7 +1579,7 @@ int pvck(struct cmd_context *cmd, int argc, char **argv)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_dump_found(cmd, labelsector, dev))
|
||||
if (!_dump_found(cmd, &set, labelsector, dev))
|
||||
bad++;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user