1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-01-03 05:18:29 +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. * converted into arrays of strings.
*/ */
struct flag { struct flag {
const char description[32];
const uint64_t mask; const uint64_t mask;
const char *description;
int kind; int kind;
}; };
static const struct flag _vg_flags[] = { static const struct flag _vg_flags[] = {
{EXPORTED_VG, "EXPORTED", STATUS_FLAG}, /* Alphabetically sorted by description! */
{RESIZEABLE_VG, "RESIZEABLE", STATUS_FLAG}, { "CLUSTERED", CLUSTERED, STATUS_FLAG },
{PVMOVE, "PVMOVE", STATUS_FLAG}, { "EXPORTED", EXPORTED_VG, STATUS_FLAG },
{LVM_READ, "READ", STATUS_FLAG}, { "NOAUTOACTIVATE", NOAUTOACTIVATE, COMPATIBLE_FLAG },
{LVM_WRITE, "WRITE", STATUS_FLAG}, { "PVMOVE", PVMOVE, STATUS_FLAG },
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG}, { "READ", LVM_READ, STATUS_FLAG },
{NOAUTOACTIVATE, "NOAUTOACTIVATE", COMPATIBLE_FLAG}, { "RESIZEABLE", RESIZEABLE_VG, STATUS_FLAG },
{CLUSTERED, "CLUSTERED", STATUS_FLAG}, { "SHARED", SHARED, STATUS_FLAG },
{SHARED, "SHARED", STATUS_FLAG}, { "WRITE", LVM_WRITE, STATUS_FLAG },
{PARTIAL_VG, NULL, 0}, { "WRITE_LOCKED", LVM_WRITE_LOCKED, COMPATIBLE_FLAG },
{PRECOMMITTED, NULL, 0}, { "", (PARTIAL_VG |
{ARCHIVED_VG, NULL, 0}, PRECOMMITTED |
{0, NULL, 0} ARCHIVED_VG), 0 },
}; };
static const struct flag _pv_flags[] = { static const struct flag _pv_flags[] = {
{ALLOCATABLE_PV, "ALLOCATABLE", STATUS_FLAG}, /* Alphabetically sorted by description! */
{EXPORTED_VG, "EXPORTED", STATUS_FLAG}, { "ALLOCATABLE", ALLOCATABLE_PV, STATUS_FLAG },
{MISSING_PV, "MISSING", COMPATIBLE_FLAG}, { "EXPORTED", EXPORTED_VG, STATUS_FLAG },
{MISSING_PV, "MISSING", STATUS_FLAG}, { "MISSING", MISSING_PV, COMPATIBLE_FLAG | STATUS_FLAG }, /* 1st. */
{PV_MOVED_VG, NULL, 0}, { "", (PV_MOVED_VG |
{UNLABELLED_PV, NULL, 0}, UNLABELLED_PV), 0 },
{0, NULL, 0}
}; };
static const struct flag _lv_flags[] = { static const struct flag _lv_flags[] = {
{LVM_READ, "READ", STATUS_FLAG}, /* Alphabetically sorted by description! */
{LVM_WRITE, "WRITE", STATUS_FLAG}, { "ACTIVATION_SKIP", LV_ACTIVATION_SKIP, COMPATIBLE_FLAG },
{LVM_WRITE_LOCKED, "WRITE_LOCKED", COMPATIBLE_FLAG}, { "CACHE_USES_CACHEVOL", LV_CACHE_USES_CACHEVOL, SEGTYPE_FLAG },
{FIXED_MINOR, "FIXED_MINOR", STATUS_FLAG}, { "CACHE_VOL", LV_CACHE_VOL, COMPATIBLE_FLAG },
{VISIBLE_LV, "VISIBLE", STATUS_FLAG}, { "CROP_METADATA", LV_CROP_METADATA, SEGTYPE_FLAG },
{PVMOVE, "PVMOVE", STATUS_FLAG}, { "ERROR_WHEN_FULL", LV_ERROR_WHEN_FULL, COMPATIBLE_FLAG },
{LOCKED, "LOCKED", STATUS_FLAG}, { "FIXED_MINOR", FIXED_MINOR, STATUS_FLAG },
{LV_NOTSYNCED, "NOTSYNCED", STATUS_FLAG}, { "LOCKED", LOCKED, STATUS_FLAG },
{LV_REBUILD, "REBUILD", STATUS_FLAG}, { "METADATA_FORMAT", LV_METADATA_FORMAT, SEGTYPE_FLAG },
{LV_RESHAPE, "RESHAPE", SEGTYPE_FLAG}, { "NOAUTOACTIVATE", LV_NOAUTOACTIVATE, COMPATIBLE_FLAG },
{LV_RESHAPE_DATA_OFFSET, "RESHAPE_DATA_OFFSET", SEGTYPE_FLAG}, { "NOTSYNCED", LV_NOTSYNCED, STATUS_FLAG },
{LV_RESHAPE_DELTA_DISKS_PLUS, "RESHAPE_DELTA_DISKS_PLUS", SEGTYPE_FLAG}, { "PVMOVE", PVMOVE, STATUS_FLAG },
{LV_RESHAPE_DELTA_DISKS_MINUS, "RESHAPE_DELTA_DISKS_MINUS", SEGTYPE_FLAG}, { "READ", LVM_READ, STATUS_FLAG },
{LV_REMOVE_AFTER_RESHAPE, "REMOVE_AFTER_RESHAPE", SEGTYPE_FLAG}, { "REBUILD", LV_REBUILD, STATUS_FLAG },
{LV_WRITEMOSTLY, "WRITEMOSTLY", STATUS_FLAG}, { "REMOVE_AFTER_RESHAPE", LV_REMOVE_AFTER_RESHAPE, SEGTYPE_FLAG },
{LV_ACTIVATION_SKIP, "ACTIVATION_SKIP", COMPATIBLE_FLAG}, { "RESHAPE", LV_RESHAPE, SEGTYPE_FLAG },
{LV_NOAUTOACTIVATE, "NOAUTOACTIVATE", COMPATIBLE_FLAG}, { "RESHAPE_DATA_OFFSET", LV_RESHAPE_DATA_OFFSET, SEGTYPE_FLAG },
{LV_ERROR_WHEN_FULL, "ERROR_WHEN_FULL", COMPATIBLE_FLAG}, { "RESHAPE_DELTA_DISKS_MINUS", LV_RESHAPE_DELTA_DISKS_MINUS, SEGTYPE_FLAG },
{LV_METADATA_FORMAT, "METADATA_FORMAT", SEGTYPE_FLAG}, { "RESHAPE_DELTA_DISKS_PLUS", LV_RESHAPE_DELTA_DISKS_PLUS, SEGTYPE_FLAG },
{LV_CROP_METADATA, "CROP_METADATA", SEGTYPE_FLAG}, { "VISIBLE", VISIBLE_LV, STATUS_FLAG },
{LV_CACHE_VOL, "CACHE_VOL", COMPATIBLE_FLAG}, { "WRITE", LVM_WRITE, STATUS_FLAG },
{LV_CACHE_USES_CACHEVOL, "CACHE_USES_CACHEVOL", SEGTYPE_FLAG}, { "WRITEMOSTLY", LV_WRITEMOSTLY, STATUS_FLAG },
{LV_NOSCAN, NULL, 0}, { "WRITE_LOCKED", LVM_WRITE_LOCKED, COMPATIBLE_FLAG },
{LV_TEMPORARY, NULL, 0}, { "", (LV_NOSCAN |
{POOL_METADATA_SPARE, NULL, 0}, LV_TEMPORARY |
{LOCKD_SANLOCK_LV, NULL, 0}, POOL_METADATA_SPARE |
{RAID, NULL, 0}, LOCKD_SANLOCK_LV |
{RAID_META, NULL, 0}, RAID |
{RAID_IMAGE, NULL, 0}, RAID_META |
{MIRROR, NULL, 0}, RAID_IMAGE |
{MIRROR_IMAGE, NULL, 0}, MIRROR |
{MIRROR_LOG, NULL, 0}, MIRROR_IMAGE |
{MIRRORED, NULL, 0}, MIRROR_LOG |
{VIRTUAL, NULL, 0}, MIRRORED |
{SNAPSHOT, NULL, 0}, VIRTUAL |
{MERGING, NULL, 0}, SNAPSHOT |
{CONVERTING, NULL, 0}, MERGING |
{PARTIAL_LV, NULL, 0}, CONVERTING |
{POSTORDER_FLAG, NULL, 0}, PARTIAL_LV |
{VIRTUAL_ORIGIN, NULL, 0}, POSTORDER_FLAG |
{THIN_VOLUME, NULL, 0}, VIRTUAL_ORIGIN |
{THIN_POOL, NULL, 0}, THIN_VOLUME |
{THIN_POOL_DATA, NULL, 0}, THIN_POOL |
{THIN_POOL_METADATA, NULL, 0}, THIN_POOL_DATA |
{CACHE, NULL, 0}, THIN_POOL_METADATA |
{CACHE_POOL, NULL, 0}, CACHE |
{CACHE_POOL_DATA, NULL, 0}, CACHE_POOL |
{CACHE_POOL_METADATA, NULL, 0}, CACHE_POOL_DATA |
{LV_VDO, NULL, 0}, CACHE_POOL_METADATA |
{LV_VDO_POOL, NULL, 0}, LV_VDO |
{LV_VDO_POOL_DATA, NULL, 0}, LV_VDO_POOL |
{WRITECACHE, NULL, 0}, LV_VDO_POOL_DATA |
{INTEGRITY, NULL, 0}, WRITECACHE |
{INTEGRITY_METADATA, NULL, 0}, INTEGRITY |
{LV_PENDING_DELETE, NULL, 0}, /* FIXME Display like COMPATIBLE_FLAG */ INTEGRITY_METADATA |
{LV_REMOVED, NULL, 0}, LV_PENDING_DELETE | /* FIXME Display like COMPATIBLE_FLAG */
{0, NULL, 0} 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) { switch (type) {
case VG_FLAGS: case VG_FLAGS:
*flags_count = DM_ARRAY_SIZE(_vg_flags);
return _vg_flags; return _vg_flags;
case PV_FLAGS: case PV_FLAGS:
*flags_count = DM_ARRAY_SIZE(_pv_flags);
return _pv_flags; return _pv_flags;
case LV_FLAGS: case LV_FLAGS:
*flags_count = DM_ARRAY_SIZE(_lv_flags);
return _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 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; const struct flag *flags;
size_t flags_count;
if (!(flags = _get_flags(type))) if (!(flags = _get_flags(type, &flags_count)))
return_0; return_0;
if (size) if (!size)
return 0;
buffer[0] = 0; buffer[0] = 0;
for (f = 0; flags[f].mask; f++) { for (; status; ++flags) {
if (status & flags[f].mask) { if (status & flags->mask) {
status &= ~flags[f].mask; status &= ~flags->mask;
if (mask != flags[f].kind) if (!(mask & flags->kind)) {
continue; if (!flags->kind)
break; /* Internal-only flag? */
/* Internal-only flag? */
if (!flags[f].description)
continue; continue;
}
if (!emit_to_buffer(&buffer, &size, "%s\"%s\"", if (!emit_to_buffer(&buffer, &size, "%s\"%s\"",
(!first) ? ", " : "", (!first) ? ", " : "",
flags[f].description)) flags->description))
return_0; return_0;
first = 0; first = 0;
} } else if (!flags->kind)
break;
} }
if (status) 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) 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); uint64_t s = UINT64_C(0);
const struct flag *flags; 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; return_0;
if (cv->type == DM_CFG_EMPTY_ARRAY) if (cv->type == DM_CFG_EMPTY_ARRAY)
@ -191,23 +198,24 @@ int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm
return 0; return 0;
} }
/*
* 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 ((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 * For a short time CACHE_VOL was a STATUS_FLAG, then it
* was changed to COMPATIBLE_FLAG, so we want to read it * was changed to COMPATIBLE_FLAG, so we want to read it
* from either place. * from either place.
*/ */
if (type == LV_FLAGS && !strcmp(cv->v.str, "CACHE_VOL"))
mask = (STATUS_FLAG | COMPATIBLE_FLAG); mask = (STATUS_FLAG | COMPATIBLE_FLAG);
if (found->kind & mask)
for (f = 0; flags[f].description; f++) { s |= found->mask;
if ((flags[f].kind & mask) && } else {
!strcmp(flags[f].description, cv->v.str)) { if ((type == VG_FLAGS) && !strcmp(cv->v.str, "PARTIAL")) {
s |= flags[f].mask;
break;
}
}
if (type == VG_FLAGS && !strcmp(cv->v.str, "PARTIAL")) {
/* /*
* Exception: We no longer write this flag out, but it * Exception: We no longer write this flag out, but it
* might be encountered in old backup files, so restore * might be encountered in old backup files, so restore
@ -216,11 +224,11 @@ int read_flags(uint64_t *status, enum pv_vg_lv_e type, int mask, const struct dm
* by this case. * by this case.
*/ */
s |= PARTIAL_VG; s |= PARTIAL_VG;
} else if (!flags[f].description && (mask & STATUS_FLAG)) { } else if (mask & STATUS_FLAG) {
log_error("Unknown status flag '%s'.", cv->v.str); log_error("Unknown status flag '%s'.", cv->v.str);
return 0; return 0;
} }
}
} while ((cv = cv->next)); } while ((cv = cv->next));
out: 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) int read_lvflags(uint64_t *status, const char *flags_str)
{ {
const struct flag *flags = _lv_flags; const struct flag *flags;
const char *delim; const char *delim;
size_t len; size_t len;
unsigned i;
do { do {
if ((delim = strchr(flags_str, '+'))) if ((delim = strchr(flags_str, '+')))
@ -249,15 +256,18 @@ int read_lvflags(uint64_t *status, const char *flags_str)
else else
len = strlen(flags_str); len = strlen(flags_str);
for (i = 0; flags[i].kind; ++i) /* Scan all lv_flags
if ((flags[i].kind & SEGTYPE_FLAG) && * Not using bsearch() ATM, as the string may end with '+'
!strncmp(flags_str, flags[i].description, len) && * and these segtypes are rare in metadata set */
!flags[i].description[len]) { for (flags = _lv_flags; flags->kind; ++flags)
*status |= flags[i].mask; if ((flags->kind & SEGTYPE_FLAG) &&
!strncmp(flags_str, flags->description, len) &&
!flags->description[len]) {
*status |= flags->mask;
break; /* Found matching flag */ break; /* Found matching flag */
} }
if (!flags[i].kind) { if (!flags->kind) {
log_warn("WARNING: Unrecognised flag(s) %s.", flags_str); log_warn("WARNING: Unrecognised flag(s) %s.", flags_str);
return 0; /* Unknown flag is incompatible */ 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) int print_segtype_lvflags(char *buffer, size_t size, uint64_t status)
{ {
unsigned i; const struct flag *flags;
const struct flag *flags = _lv_flags;
if (!size)
return 0;
buffer[0] = 0; buffer[0] = 0;
for (i = 0; flags[i].mask; i++)
if ((flags[i].kind & SEGTYPE_FLAG) && for (flags = _lv_flags; status && flags->kind; ++flags) {
(status & flags[i].mask) && if ((flags->kind & SEGTYPE_FLAG) &&
(status & flags->mask) &&
!emit_to_buffer(&buffer, &size, "+%s", !emit_to_buffer(&buffer, &size, "+%s",
flags[i].description)) flags->description))
return 0; return 0;
status &= ~flags->mask;
}
return 1; return 1;
} }