mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
export: optimise flag reading and printing
When parsing list of flags, we can use 'alphabetically' sorted array and use 'bsearch()' to look for particular bit. When creating string representation of flags, we can reduce some unnecessary bit lookups by join those flags without string description together, so there is no need to check for those individual 'bits', but still maintaining the bit validation. Also exit the printing loop early, if there are no any more status bit present.
This commit is contained in:
parent
84fbbcac45
commit
797265f424
@ -23,107 +23,109 @@
|
||||
* converted into arrays of strings.
|
||||
*/
|
||||
struct flag {
|
||||
const char description[32];
|
||||
const uint64_t mask;
|
||||
const char *description;
|
||||
int kind;
|
||||
};
|
||||
|
||||
static const struct flag _vg_flags[] = {
|
||||
{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
|
||||
{RESIZEABLE_VG, "RESIZEABLE", STATUS_FLAG},
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG},
|
||||
{NOAUTOACTIVATE, "NOAUTOACTIVATE", COMPATIBLE_FLAG},
|
||||
{CLUSTERED, "CLUSTERED", STATUS_FLAG},
|
||||
{SHARED, "SHARED", STATUS_FLAG},
|
||||
{PARTIAL_VG, NULL, 0},
|
||||
{PRECOMMITTED, NULL, 0},
|
||||
{ARCHIVED_VG, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
/* Alphabetically sorted by description! */
|
||||
{ "CLUSTERED", CLUSTERED, STATUS_FLAG },
|
||||
{ "EXPORTED", EXPORTED_VG, STATUS_FLAG },
|
||||
{ "NOAUTOACTIVATE", NOAUTOACTIVATE, COMPATIBLE_FLAG },
|
||||
{ "PVMOVE", PVMOVE, STATUS_FLAG },
|
||||
{ "READ", LVM_READ, STATUS_FLAG },
|
||||
{ "RESIZEABLE", RESIZEABLE_VG, STATUS_FLAG },
|
||||
{ "SHARED", SHARED, STATUS_FLAG },
|
||||
{ "WRITE", LVM_WRITE, STATUS_FLAG },
|
||||
{ "WRITE_LOCKED", LVM_WRITE_LOCKED, COMPATIBLE_FLAG },
|
||||
{ "", (PARTIAL_VG |
|
||||
PRECOMMITTED |
|
||||
ARCHIVED_VG), 0 },
|
||||
};
|
||||
|
||||
static const struct flag _pv_flags[] = {
|
||||
{ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG},
|
||||
{EXPORTED_VG, "EXPORTED", STATUS_FLAG},
|
||||
{MISSING_PV, "MISSING", COMPATIBLE_FLAG},
|
||||
{MISSING_PV, "MISSING", STATUS_FLAG},
|
||||
{PV_MOVED_VG, NULL, 0},
|
||||
{UNLABELLED_PV, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
/* Alphabetically sorted by description! */
|
||||
{ "ALLOCATABLE", ALLOCATABLE_PV, STATUS_FLAG },
|
||||
{ "EXPORTED", EXPORTED_VG, STATUS_FLAG },
|
||||
{ "MISSING", MISSING_PV, COMPATIBLE_FLAG | STATUS_FLAG }, /* 1st. */
|
||||
{ "", (PV_MOVED_VG |
|
||||
UNLABELLED_PV), 0 },
|
||||
};
|
||||
|
||||
static const struct flag _lv_flags[] = {
|
||||
{LVM_READ, "READ", STATUS_FLAG},
|
||||
{LVM_WRITE, "WRITE", STATUS_FLAG},
|
||||
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG},
|
||||
{FIXED_MINOR, "FIXED_MINOR", STATUS_FLAG},
|
||||
{VISIBLE_LV, "VISIBLE", STATUS_FLAG},
|
||||
{PVMOVE, "PVMOVE", STATUS_FLAG},
|
||||
{LOCKED, "LOCKED", STATUS_FLAG},
|
||||
{LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG},
|
||||
{LV_REBUILD, "REBUILD", STATUS_FLAG},
|
||||
{LV_RESHAPE, "RESHAPE", SEGTYPE_FLAG},
|
||||
{LV_RESHAPE_DATA_OFFSET, "RESHAPE_DATA_OFFSET", SEGTYPE_FLAG},
|
||||
{LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", SEGTYPE_FLAG},
|
||||
{LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", SEGTYPE_FLAG},
|
||||
{LV_REMOVE_AFTER_RESHAPE, "REMOVE_AFTER_RESHAPE", SEGTYPE_FLAG},
|
||||
{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG},
|
||||
{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG},
|
||||
{LV_NOAUTOACTIVATE, "NOAUTOACTIVATE", COMPATIBLE_FLAG},
|
||||
{LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG},
|
||||
{LV_METADATA_FORMAT, "METADATA_FORMAT", SEGTYPE_FLAG},
|
||||
{LV_CROP_METADATA, "CROP_METADATA", SEGTYPE_FLAG},
|
||||
{LV_CACHE_VOL, "CACHE_VOL", COMPATIBLE_FLAG},
|
||||
{LV_CACHE_USES_CACHEVOL, "CACHE_USES_CACHEVOL", SEGTYPE_FLAG},
|
||||
{LV_NOSCAN, NULL, 0},
|
||||
{LV_TEMPORARY, NULL, 0},
|
||||
{POOL_METADATA_SPARE, NULL, 0},
|
||||
{LOCKD_SANLOCK_LV, NULL, 0},
|
||||
{RAID, NULL, 0},
|
||||
{RAID_META, NULL, 0},
|
||||
{RAID_IMAGE, NULL, 0},
|
||||
{MIRROR, NULL, 0},
|
||||
{MIRROR_IMAGE, NULL, 0},
|
||||
{MIRROR_LOG, NULL, 0},
|
||||
{MIRRORED, NULL, 0},
|
||||
{VIRTUAL, NULL, 0},
|
||||
{SNAPSHOT, NULL, 0},
|
||||
{MERGING, NULL, 0},
|
||||
{CONVERTING, NULL, 0},
|
||||
{PARTIAL_LV, NULL, 0},
|
||||
{POSTORDER_FLAG, NULL, 0},
|
||||
{VIRTUAL_ORIGIN, NULL, 0},
|
||||
{THIN_VOLUME, NULL, 0},
|
||||
{THIN_POOL, NULL, 0},
|
||||
{THIN_POOL_DATA, NULL, 0},
|
||||
{THIN_POOL_METADATA, NULL, 0},
|
||||
{CACHE, NULL, 0},
|
||||
{CACHE_POOL, NULL, 0},
|
||||
{CACHE_POOL_DATA, NULL, 0},
|
||||
{CACHE_POOL_METADATA, NULL, 0},
|
||||
{LV_VDO, NULL, 0},
|
||||
{LV_VDO_POOL, NULL, 0},
|
||||
{LV_VDO_POOL_DATA, NULL, 0},
|
||||
{WRITECACHE, NULL, 0},
|
||||
{INTEGRITY, NULL, 0},
|
||||
{INTEGRITY_METADATA, NULL, 0},
|
||||
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */
|
||||
{LV_REMOVED, NULL, 0},
|
||||
{0, NULL, 0}
|
||||
/* Alphabetically sorted by description! */
|
||||
{ "ACTIVATION_SKIP", LV_ACTIVATION_SKIP, COMPATIBLE_FLAG },
|
||||
{ "CACHE_USES_CACHEVOL", LV_CACHE_USES_CACHEVOL, SEGTYPE_FLAG },
|
||||
{ "CACHE_VOL", LV_CACHE_VOL, COMPATIBLE_FLAG },
|
||||
{ "CROP_METADATA", LV_CROP_METADATA, SEGTYPE_FLAG },
|
||||
{ "ERROR_WHEN_FULL", LV_ERROR_WHEN_FULL, COMPATIBLE_FLAG },
|
||||
{ "FIXED_MINOR", FIXED_MINOR, STATUS_FLAG },
|
||||
{ "LOCKED", LOCKED, STATUS_FLAG },
|
||||
{ "METADATA_FORMAT", LV_METADATA_FORMAT, SEGTYPE_FLAG },
|
||||
{ "NOAUTOACTIVATE", LV_NOAUTOACTIVATE, COMPATIBLE_FLAG },
|
||||
{ "NOTSYNCED", LV_NOTSYNCED, STATUS_FLAG },
|
||||
{ "PVMOVE", PVMOVE, STATUS_FLAG },
|
||||
{ "READ", LVM_READ, STATUS_FLAG },
|
||||
{ "REBUILD", LV_REBUILD, STATUS_FLAG },
|
||||
{ "REMOVE_AFTER_RESHAPE", LV_REMOVE_AFTER_RESHAPE, SEGTYPE_FLAG },
|
||||
{ "RESHAPE", LV_RESHAPE, SEGTYPE_FLAG },
|
||||
{ "RESHAPE_DATA_OFFSET", LV_RESHAPE_DATA_OFFSET, SEGTYPE_FLAG },
|
||||
{ "RESHAPE_DELTA_DISKS_MINUS", LV_RESHAPE_DELTA_DISKS_MINUS, SEGTYPE_FLAG },
|
||||
{ "RESHAPE_DELTA_DISKS_PLUS", LV_RESHAPE_DELTA_DISKS_PLUS, SEGTYPE_FLAG },
|
||||
{ "VISIBLE", VISIBLE_LV, STATUS_FLAG },
|
||||
{ "WRITE", LVM_WRITE, STATUS_FLAG },
|
||||
{ "WRITEMOSTLY", LV_WRITEMOSTLY, STATUS_FLAG },
|
||||
{ "WRITE_LOCKED", LVM_WRITE_LOCKED, COMPATIBLE_FLAG },
|
||||
{ "", (LV_NOSCAN |
|
||||
LV_TEMPORARY |
|
||||
POOL_METADATA_SPARE |
|
||||
LOCKD_SANLOCK_LV |
|
||||
RAID |
|
||||
RAID_META |
|
||||
RAID_IMAGE |
|
||||
MIRROR |
|
||||
MIRROR_IMAGE |
|
||||
MIRROR_LOG |
|
||||
MIRRORED |
|
||||
VIRTUAL |
|
||||
SNAPSHOT |
|
||||
MERGING |
|
||||
CONVERTING |
|
||||
PARTIAL_LV |
|
||||
POSTORDER_FLAG |
|
||||
VIRTUAL_ORIGIN |
|
||||
THIN_VOLUME |
|
||||
THIN_POOL |
|
||||
THIN_POOL_DATA |
|
||||
THIN_POOL_METADATA |
|
||||
CACHE |
|
||||
CACHE_POOL |
|
||||
CACHE_POOL_DATA |
|
||||
CACHE_POOL_METADATA |
|
||||
LV_VDO |
|
||||
LV_VDO_POOL |
|
||||
LV_VDO_POOL_DATA |
|
||||
WRITECACHE |
|
||||
INTEGRITY |
|
||||
INTEGRITY_METADATA |
|
||||
LV_PENDING_DELETE | /* FIXME Display like COMPATIBLE_FLAG */
|
||||
LV_REMOVED), 0 },
|
||||
};
|
||||
|
||||
static const struct flag *_get_flags(enum pv_vg_lv_e type)
|
||||
static const struct flag *_get_flags(enum pv_vg_lv_e type, size_t *flags_count)
|
||||
{
|
||||
switch (type) {
|
||||
case VG_FLAGS:
|
||||
*flags_count = DM_ARRAY_SIZE(_vg_flags);
|
||||
return _vg_flags;
|
||||
|
||||
case PV_FLAGS:
|
||||
*flags_count = DM_ARRAY_SIZE(_pv_flags);
|
||||
return _pv_flags;
|
||||
|
||||
case LV_FLAGS:
|
||||
*flags_count = DM_ARRAY_SIZE(_lv_flags);
|
||||
return _lv_flags;
|
||||
}
|
||||
|
||||
@ -138,32 +140,35 @@ static const struct flag *_get_flags(enum pv_vg_lv_e type)
|
||||
*/
|
||||
int print_flags(char *buffer, size_t size, enum pv_vg_lv_e type, int mask, uint64_t status)
|
||||
{
|
||||
int f, first = 1;
|
||||
int first = 1;
|
||||
const struct flag *flags;
|
||||
size_t flags_count;
|
||||
|
||||
if (!(flags = _get_flags(type)))
|
||||
if (!(flags = _get_flags(type, &flags_count)))
|
||||
return_0;
|
||||
|
||||
if (size)
|
||||
buffer[0] = 0;
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
for (f = 0; flags[f].mask; f++) {
|
||||
if (status & flags[f].mask) {
|
||||
status &= ~flags[f].mask;
|
||||
buffer[0] = 0;
|
||||
|
||||
if (mask != flags[f].kind)
|
||||
continue;
|
||||
|
||||
/* Internal-only flag? */
|
||||
if (!flags[f].description)
|
||||
for (; status; ++flags) {
|
||||
if (status & flags->mask) {
|
||||
status &= ~flags->mask;
|
||||
|
||||
if (!(mask & flags->kind)) {
|
||||
if (!flags->kind)
|
||||
break; /* Internal-only flag? */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!emit_to_buffer(&buffer, &size, "%s\"%s\"",
|
||||
(!first) ? ", " : "",
|
||||
flags[f].description))
|
||||
flags->description))
|
||||
return_0;
|
||||
first = 0;
|
||||
}
|
||||
} else if (!flags->kind)
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
@ -175,11 +180,13 @@ int print_flags(char *buffer, size_t size, enum pv_vg_lv_e type, int mask, uint6
|
||||
|
||||
int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm_config_value *cv)
|
||||
{
|
||||
unsigned f;
|
||||
uint64_t s = UINT64_C(0);
|
||||
const struct flag *flags;
|
||||
struct flag *found;
|
||||
size_t flags_count;
|
||||
typedef int (*compare_fn_t) (const void *, const void *);
|
||||
|
||||
if (!(flags = _get_flags(type)))
|
||||
if (!(flags = _get_flags(type, &flags_count)))
|
||||
return_0;
|
||||
|
||||
if (cv->type == DM_CFG_EMPTY_ARRAY)
|
||||
@ -192,22 +199,23 @@ int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm
|
||||
}
|
||||
|
||||
/*
|
||||
* For a short time CACHE_VOL was a STATUS_FLAG, then it
|
||||
* was changed to COMPATIBLE_FLAG, so we want to read it
|
||||
* from either place.
|
||||
* v.str is a string as well as 'struct flag' starts with string.
|
||||
* So compare directly 'strcmp()'.
|
||||
* Since the last flags entry is always empty "", reduce count by 1
|
||||
*/
|
||||
if (type == LV_FLAGS && !strcmp(cv->v.str, "CACHE_VOL"))
|
||||
mask = (STATUS_FLAG | COMPATIBLE_FLAG);
|
||||
|
||||
for (f = 0; flags[f].description; f++) {
|
||||
if ((flags[f].kind & mask) &&
|
||||
!strcmp(flags[f].description, cv->v.str)) {
|
||||
s |= flags[f].mask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) {
|
||||
if ((found = bsearch((struct flag*)cv->v.str, flags, flags_count - 1,
|
||||
sizeof(struct flag), (compare_fn_t) strcmp))) {
|
||||
if ((type == LV_FLAGS) && (found->mask & LV_CACHE_VOL))
|
||||
/*
|
||||
* For a short time CACHE_VOL was a STATUS_FLAG, then it
|
||||
* was changed to COMPATIBLE_FLAG, so we want to read it
|
||||
* from either place.
|
||||
*/
|
||||
mask = (STATUS_FLAG | COMPATIBLE_FLAG);
|
||||
if (found->kind & mask)
|
||||
s |= found->mask;
|
||||
} else {
|
||||
if ((type == VG_FLAGS) && !strcmp(cv->v.str, "PARTIAL")) {
|
||||
/*
|
||||
* Exception: We no longer write this flag out, but it
|
||||
* might be encountered in old backup files, so restore
|
||||
@ -215,12 +223,12 @@ int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm
|
||||
* though, so only vgcfgrestore needs to be concerned
|
||||
* by this case.
|
||||
*/
|
||||
s |= PARTIAL_VG;
|
||||
} else if (!flags[f].description && (mask & STATUS_FLAG)) {
|
||||
log_error("Unknown status flag '%s'.", cv->v.str);
|
||||
return 0;
|
||||
s |= PARTIAL_VG;
|
||||
} else if (mask & STATUS_FLAG) {
|
||||
log_error("Unknown status flag '%s'.", cv->v.str);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} while ((cv = cv->next));
|
||||
|
||||
out:
|
||||
@ -238,10 +246,9 @@ int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm
|
||||
*/
|
||||
int read_lvflags(uint64_t *status, const char *flags_str)
|
||||
{
|
||||
const struct flag *flags = _lv_flags;
|
||||
const struct flag *flags;
|
||||
const char *delim;
|
||||
size_t len;
|
||||
unsigned i;
|
||||
|
||||
do {
|
||||
if ((delim = strchr(flags_str, '+')))
|
||||
@ -249,15 +256,18 @@ int read_lvflags(uint64_t *status, const char *flags_str)
|
||||
else
|
||||
len = strlen(flags_str);
|
||||
|
||||
for (i = 0; flags[i].kind; ++i)
|
||||
if ((flags[i].kind & SEGTYPE_FLAG) &&
|
||||
!strncmp(flags_str, flags[i].description, len) &&
|
||||
!flags[i].description[len]) {
|
||||
*status |= flags[i].mask;
|
||||
/* Scan all lv_flags
|
||||
* Not using bsearch() ATM, as the string may end with '+'
|
||||
* and these segtypes are rare in metadata set */
|
||||
for (flags = _lv_flags; flags->kind; ++flags)
|
||||
if ((flags->kind & SEGTYPE_FLAG) &&
|
||||
!strncmp(flags_str, flags->description, len) &&
|
||||
!flags->description[len]) {
|
||||
*status |= flags->mask;
|
||||
break; /* Found matching flag */
|
||||
}
|
||||
|
||||
if (!flags[i].kind) {
|
||||
if (!flags->kind) {
|
||||
log_warn("WARNING: Unrecognised flag(s) %s.", flags_str);
|
||||
return 0; /* Unknown flag is incompatible */
|
||||
}
|
||||
@ -270,16 +280,21 @@ int read_lvflags(uint64_t *status, const char *flags_str)
|
||||
|
||||
int print_segtype_lvflags(char *buffer, size_t size, uint64_t status)
|
||||
{
|
||||
unsigned i;
|
||||
const struct flag *flags = _lv_flags;
|
||||
const struct flag *flags;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
buffer[0] = 0;
|
||||
for (i = 0; flags[i].mask; i++)
|
||||
if ((flags[i].kind & SEGTYPE_FLAG) &&
|
||||
(status & flags[i].mask) &&
|
||||
|
||||
for (flags = _lv_flags; status && flags->kind; ++flags) {
|
||||
if ((flags->kind & SEGTYPE_FLAG) &&
|
||||
(status & flags->mask) &&
|
||||
!emit_to_buffer(&buffer, &size, "+%s",
|
||||
flags[i].description))
|
||||
flags->description))
|
||||
return 0;
|
||||
status &= ~flags->mask;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user