1
0
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:
Zdenek Kabelac 2024-10-20 01:57:30 +02:00
parent 84fbbcac45
commit 797265f424

View File

@ -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;
}