1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-10-06 22:19:30 +03:00

Merge branch 'master' into 2018-05-11-fork-libdm

This commit is contained in:
Joe Thornber 2018-06-01 13:04:12 +01:00
commit dbba1e9b93
286 changed files with 2635 additions and 900 deletions

52
.gitignore vendored
View File

@ -79,5 +79,55 @@ test/lib/vgrename
test/lib/vgs
test/lib/vgscan
test/lib/vgsplit
test/api/lvtest.t
test/api/pe_start.t
test/api/percent.t
test/api/python_lvm_unit.py
test/api/test
test/api/thin_percent.t
test/api/vglist.t
test/api/vgtest.t
test/lib/aux
test/lib/check
test/lib/clvmd
test/lib/dm-version-expected
test/lib/dmeventd
test/lib/dmsetup
test/lib/dmstats
test/lib/fail
test/lib/flavour-ndev-cluster
test/lib/flavour-ndev-cluster-lvmpolld
test/lib/flavour-ndev-lvmetad
test/lib/flavour-ndev-lvmetad-lvmpolld
test/lib/flavour-ndev-lvmpolld
test/lib/flavour-ndev-vanilla
test/lib/flavour-udev-cluster
test/lib/flavour-udev-cluster-lvmpolld
test/lib/flavour-udev-lvmetad
test/lib/flavour-udev-lvmetad-lvmpolld
test/lib/flavour-udev-lvmlockd-dlm
test/lib/flavour-udev-lvmlockd-sanlock
test/lib/flavour-udev-lvmlockd-test
test/lib/flavour-udev-lvmpolld
test/lib/flavour-udev-vanilla
test/lib/fsadm
test/lib/get
test/lib/inittest
test/lib/invalid
test/lib/lvm
test/lib/lvm-wrapper
test/lib/lvmchange
test/lib/lvmdbusd.profile
test/lib/lvmetad
test/lib/lvmpolld
test/lib/not
test/lib/paths
test/lib/paths-common
test/lib/runner
test/lib/should
test/lib/test
test/lib/thin-performance.profile
test/lib/utils
test/lib/version-expected
test/unit/dmraid_t.c
test/unit/unit-test

View File

@ -1 +1 @@
2.02.178(2)-git (2017-12-18)
2.02.178(2)-git (2018-05-24)

View File

@ -1 +1 @@
1.02.147-git (2017-12-18)
1.02.147-git (2018-05-24)

View File

@ -1,16 +1,22 @@
Version 2.02.178 -
=====================================
Version 2.02.178 -
====================================
Use versionsort to fix archive file expiry beyond 100000 files.
Version 2.02.178-rc1 - 24th May 2018
====================================
Add libaio dependency for build.
Remove lvm1 and pool format handling and add filter to ignore them.
Move some filter checks to after disks are read.
Rework disk scanning and when it is used.
Add new io layer and shift code to using it.
lvconvert: don't return success on degraded -m raid1 conversion
Fix lvconvert's return code on degraded -m raid1 conversion.
--enable-testing switch for ./configure has been removed.
--with-snapshots switch for ./configure has been removed.
--with-mirrors switch for ./configure has been removed.
--with-raid switch for ./configure has been removed.
--with-thin switch for ./configure has been removed.
--with-cache switch for ./configure has been removed.
Include new unit-test framework and unit tests.
Extend validation of region_size for mirror segment.
Reload whole device stack when reinitilizing mirror log.
Mirrors without monitoring are WARNING and not blocking on error.
@ -18,7 +24,7 @@ Version 2.02.178 -
Fix evaluation of maximal region size for mirror log.
Enhance mirror log size estimation and use smaller size when possible.
Fix incorrect mirror log size calculation on 32bit arch.
Enhnace preloading tree creating.
Enhance preloading tree creating.
Fix regression on acceptance of any LV on lvconvert.
Restore usability of thin LV to be again external origin for another thin.
Keep systemd vars on change event in 69-dm-lvm-metad.rules for systemd reload.
@ -34,8 +40,8 @@ Version 2.02.178 -
Enhance mirror log initialization for old mirror target.
Skip private crypto and stratis devices.
Skip frozen raid devices from scanning.
Activate RAID SubLVs on read_only_volume_list readwrite
Offer convenience type raid5_n converting to raid10
Activate RAID SubLVs on read_only_volume_list readwrite.
Offer convenience type raid5_n converting to raid10.
Automatically avoid reading invalid snapshots during device scan.
Ensure COW device is writable even for read-only thick snapshots.
Support activation of component LVs in read-only mode.
@ -53,20 +59,13 @@ Version 2.02.178 -
Improve validation of created strings in vgimportclone.
Add missing initialisation of mem pool in systemd generator.
Do not reopen output streams for multithreaded users of liblvm.
Use versionsort to fix archive file expiry beyond 100000 files.
Add devices/use_aio, aio_max, aio_memory to configure AIO limits.
Support asynchronous I/O when scanning devices.
Detect asynchronous I/O capability in configure or accept --disable-aio.
Add AIO_SUPPORTED_CODE_PATH to indicate whether AIO may be used.
Configure ensures /usr/bin dir is checked for dmpd tools.
Restore pvmove support for wide-clustered active volumes (2.02.177).
Avoid non-exclusive activation of exclusive segment types.
Fix trimming sibling PVs when doing a pvmove of raid subLVs.
Preserve exclusive activation during thin snaphost merge.
Suppress some repeated reads of the same disk data at the device layer.
Avoid exceeding array bounds in allocation tag processing.
Refactor metadata reading code to use callback functions.
Move memory allocation for the key dev_reads into the device layer.
Add --lockopt to common options and add option to skip selected locks.
Version 2.02.177 - 18th December 2017
=====================================

View File

@ -1,5 +1,8 @@
Version 1.02.147 -
=====================================
Version 1.02.147 -
====================================
Version 1.02.147-rc1 - 24th May 2018
====================================
Reuse uname() result for mirror target.
Recognize also mounted btrfs through dm_device_has_mounted_fs().
Add missing log_error() into dm_stats_populate() returning 0.

View File

@ -68,31 +68,43 @@ struct node48 {
};
struct node256 {
uint32_t nr_entries;
struct value values[256];
};
struct radix_tree {
unsigned nr_entries;
struct value root;
radix_value_dtr dtr;
void *dtr_context;
};
//----------------------------------------------------------------
struct radix_tree *radix_tree_create(void)
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context)
{
struct radix_tree *rt = malloc(sizeof(*rt));
if (rt) {
rt->nr_entries = 0;
rt->root.type = UNSET;
rt->dtr = dtr;
rt->dtr_context = dtr_context;
}
return rt;
}
static void _free_node(struct value v, radix_value_dtr dtr, void *context)
static inline void _dtr(struct radix_tree *rt, union radix_value v)
{
unsigned i;
if (rt->dtr)
rt->dtr(rt->dtr_context, v);
}
// Returns the number of values removed
static unsigned _free_node(struct radix_tree *rt, struct value v)
{
unsigned i, nr = 0;
struct value_chain *vc;
struct prefix_chain *pc;
struct node4 *n4;
@ -105,63 +117,69 @@ static void _free_node(struct value v, radix_value_dtr dtr, void *context)
break;
case VALUE:
if (dtr)
dtr(context, v.value);
_dtr(rt, v.value);
nr = 1;
break;
case VALUE_CHAIN:
vc = v.value.ptr;
if (dtr)
dtr(context, vc->value);
_free_node(vc->child, dtr, context);
_dtr(rt, vc->value);
nr = 1 + _free_node(rt, vc->child);
free(vc);
break;
case PREFIX_CHAIN:
pc = v.value.ptr;
_free_node(pc->child, dtr, context);
nr = _free_node(rt, pc->child);
free(pc);
break;
case NODE4:
n4 = (struct node4 *) v.value.ptr;
for (i = 0; i < n4->nr_entries; i++)
_free_node(n4->values[i], dtr, context);
nr += _free_node(rt, n4->values[i]);
free(n4);
break;
case NODE16:
n16 = (struct node16 *) v.value.ptr;
for (i = 0; i < n16->nr_entries; i++)
_free_node(n16->values[i], dtr, context);
nr += _free_node(rt, n16->values[i]);
free(n16);
break;
case NODE48:
n48 = (struct node48 *) v.value.ptr;
for (i = 0; i < n48->nr_entries; i++)
_free_node(n48->values[i], dtr, context);
nr += _free_node(rt, n48->values[i]);
free(n48);
break;
case NODE256:
n256 = (struct node256 *) v.value.ptr;
for (i = 0; i < 256; i++)
_free_node(n256->values[i], dtr, context);
nr += _free_node(rt, n256->values[i]);
free(n256);
break;
}
return nr;
}
void radix_tree_destroy(struct radix_tree *rt, radix_value_dtr dtr, void *context)
void radix_tree_destroy(struct radix_tree *rt)
{
_free_node(rt->root, dtr, context);
_free_node(rt, rt->root);
free(rt);
}
static bool _insert(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
unsigned radix_tree_size(struct radix_tree *rt)
{
return rt->nr_entries;
}
static bool _insert_unset(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv);
static bool _insert_unset(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
unsigned len = ke - kb;
@ -169,6 +187,7 @@ static bool _insert_unset(struct value *v, uint8_t *kb, uint8_t *ke, union radix
// value
v->type = VALUE;
v->value = rv;
rt->nr_entries++;
} else {
// prefix -> value
struct prefix_chain *pc = zalloc(sizeof(*pc) + len);
@ -181,12 +200,13 @@ static bool _insert_unset(struct value *v, uint8_t *kb, uint8_t *ke, union radix
memcpy(pc->prefix, kb, len);
v->type = PREFIX_CHAIN;
v->value.ptr = pc;
rt->nr_entries++;
}
return true;
}
static bool _insert_value(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_value(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
unsigned len = ke - kb;
@ -201,7 +221,7 @@ static bool _insert_value(struct value *v, uint8_t *kb, uint8_t *ke, union radix
return false;
vc->value = v->value;
if (!_insert(&vc->child, kb, ke, rv)) {
if (!_insert(rt, &vc->child, kb, ke, rv)) {
free(vc);
return false;
}
@ -213,10 +233,10 @@ static bool _insert_value(struct value *v, uint8_t *kb, uint8_t *ke, union radix
return true;
}
static bool _insert_value_chain(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_value_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct value_chain *vc = v->value.ptr;
return _insert(&vc->child, kb, ke, rv);
return _insert(rt, &vc->child, kb, ke, rv);
}
static unsigned min(unsigned lhs, unsigned rhs)
@ -227,7 +247,7 @@ static unsigned min(unsigned lhs, unsigned rhs)
return rhs;
}
static bool _insert_prefix_chain(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_prefix_chain(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct prefix_chain *pc = v->value.ptr;
@ -251,7 +271,7 @@ static bool _insert_prefix_chain(struct value *v, uint8_t *kb, uint8_t *ke, unio
pc->child.value.ptr = pc2;
pc->len = i;
if (!_insert(&pc->child, kb + i, ke, rv)) {
if (!_insert(rt, &pc->child, kb + i, ke, rv)) {
free(pc2);
return false;
}
@ -263,7 +283,7 @@ static bool _insert_prefix_chain(struct value *v, uint8_t *kb, uint8_t *ke, unio
return false;
n4->keys[0] = *kb;
if (!_insert(n4->values, kb + 1, ke, rv)) {
if (!_insert(rt, n4->values, kb + 1, ke, rv)) {
free(n4);
return false;
}
@ -289,7 +309,7 @@ static bool _insert_prefix_chain(struct value *v, uint8_t *kb, uint8_t *ke, unio
return true;
}
static bool _insert_node4(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_node4(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node4 *n4 = v->value.ptr;
if (n4->nr_entries == 4) {
@ -302,7 +322,7 @@ static bool _insert_node4(struct value *v, uint8_t *kb, uint8_t *ke, union radix
memcpy(n16->values, n4->values, sizeof(n4->values));
n16->keys[4] = *kb;
if (!_insert(n16->values + 4, kb + 1, ke, rv)) {
if (!_insert(rt, n16->values + 4, kb + 1, ke, rv)) {
free(n16);
return false;
}
@ -311,7 +331,7 @@ static bool _insert_node4(struct value *v, uint8_t *kb, uint8_t *ke, union radix
v->value.ptr = n16;
} else {
n4 = v->value.ptr;
if (!_insert(n4->values + n4->nr_entries, kb + 1, ke, rv))
if (!_insert(rt, n4->values + n4->nr_entries, kb + 1, ke, rv))
return false;
n4->keys[n4->nr_entries] = *kb;
@ -320,7 +340,7 @@ static bool _insert_node4(struct value *v, uint8_t *kb, uint8_t *ke, union radix
return true;
}
static bool _insert_node16(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_node16(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node16 *n16 = v->value.ptr;
@ -340,7 +360,7 @@ static bool _insert_node16(struct value *v, uint8_t *kb, uint8_t *ke, union radi
}
n48->keys[*kb] = 16;
if (!_insert(n48->values + 16, kb + 1, ke, rv)) {
if (!_insert(rt, n48->values + 16, kb + 1, ke, rv)) {
free(n48);
return false;
}
@ -349,7 +369,7 @@ static bool _insert_node16(struct value *v, uint8_t *kb, uint8_t *ke, union radi
v->type = NODE48;
v->value.ptr = n48;
} else {
if (!_insert(n16->values + n16->nr_entries, kb + 1, ke, rv))
if (!_insert(rt, n16->values + n16->nr_entries, kb + 1, ke, rv))
return false;
n16->keys[n16->nr_entries] = *kb;
n16->nr_entries++;
@ -358,7 +378,7 @@ static bool _insert_node16(struct value *v, uint8_t *kb, uint8_t *ke, union radi
return true;
}
static bool _insert_node48(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_node48(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node48 *n48 = v->value.ptr;
if (n48->nr_entries == 48) {
@ -374,7 +394,7 @@ static bool _insert_node48(struct value *v, uint8_t *kb, uint8_t *ke, union radi
n256->values[i] = n48->values[n48->keys[i]];
}
if (!_insert(n256->values + *kb, kb + 1, ke, rv)) {
if (!_insert(rt, n256->values + *kb, kb + 1, ke, rv)) {
free(n256);
return false;
}
@ -384,7 +404,7 @@ static bool _insert_node48(struct value *v, uint8_t *kb, uint8_t *ke, union radi
v->value.ptr = n256;
} else {
if (!_insert(n48->values + n48->nr_entries, kb + 1, ke, rv))
if (!_insert(rt, n48->values + n48->nr_entries, kb + 1, ke, rv))
return false;
n48->keys[*kb] = n48->nr_entries;
@ -394,24 +414,28 @@ static bool _insert_node48(struct value *v, uint8_t *kb, uint8_t *ke, union radi
return true;
}
static bool _insert_node256(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert_node256(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct node256 *n256 = v->value.ptr;
if (!_insert(n256->values + *kb, kb + 1, ke, rv)) {
n256->values[*kb].type = UNSET;
bool was_unset = n256->values[*kb].type == UNSET;
if (!_insert(rt, n256->values + *kb, kb + 1, ke, rv))
return false;
}
if (was_unset)
n256->nr_entries++;
return true;
}
// FIXME: the tree should not be touched if insert fails (eg, OOM)
static bool _insert(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
static bool _insert(struct radix_tree *rt, struct value *v, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
if (kb == ke) {
if (v->type == UNSET) {
v->type = VALUE;
v->value = rv;
rt->nr_entries++;
} else if (v->type == VALUE) {
v->value = rv;
@ -425,34 +449,35 @@ static bool _insert(struct value *v, uint8_t *kb, uint8_t *ke, union radix_value
vc->child = *v;
v->type = VALUE_CHAIN;
v->value.ptr = vc;
rt->nr_entries++;
}
return true;
}
switch (v->type) {
case UNSET:
return _insert_unset(v, kb, ke, rv);
return _insert_unset(rt, v, kb, ke, rv);
case VALUE:
return _insert_value(v, kb, ke, rv);
return _insert_value(rt, v, kb, ke, rv);
case VALUE_CHAIN:
return _insert_value_chain(v, kb, ke, rv);
return _insert_value_chain(rt, v, kb, ke, rv);
case PREFIX_CHAIN:
return _insert_prefix_chain(v, kb, ke, rv);
return _insert_prefix_chain(rt, v, kb, ke, rv);
case NODE4:
return _insert_node4(v, kb, ke, rv);
return _insert_node4(rt, v, kb, ke, rv);
case NODE16:
return _insert_node16(v, kb, ke, rv);
return _insert_node16(rt, v, kb, ke, rv);
case NODE48:
return _insert_node48(v, kb, ke, rv);
return _insert_node48(rt, v, kb, ke, rv);
case NODE256:
return _insert_node256(v, kb, ke, rv);
return _insert_node256(rt, v, kb, ke, rv);
}
// can't get here
@ -530,17 +555,216 @@ static struct lookup_result _lookup_prefix(struct value *v, uint8_t *kb, uint8_t
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value rv)
{
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (_insert(lr.v, lr.kb, ke, rv)) {
rt->nr_entries++;
return true;
return _insert(rt, lr.v, lr.kb, ke, rv);
}
// Note the degrade functions also free the original node.
static void _degrade_to_n4(struct node16 *n16, struct value *result)
{
struct node4 *n4 = zalloc(sizeof(*n4));
n4->nr_entries = n16->nr_entries;
memcpy(n4->keys, n16->keys, n16->nr_entries * sizeof(*n4->keys));
memcpy(n4->values, n16->values, n16->nr_entries * sizeof(*n4->values));
free(n16);
result->type = NODE4;
result->value.ptr = n4;
}
static void _degrade_to_n16(struct node48 *n48, struct value *result)
{
struct node4 *n16 = zalloc(sizeof(*n16));
n16->nr_entries = n48->nr_entries;
memcpy(n16->keys, n48->keys, n48->nr_entries * sizeof(*n16->keys));
memcpy(n16->values, n48->values, n48->nr_entries * sizeof(*n16->values));
free(n48);
result->type = NODE16;
result->value.ptr = n16;
}
static void _degrade_to_n48(struct node256 *n256, struct value *result)
{
unsigned i, count = 0;
struct node4 *n48 = zalloc(sizeof(*n48));
n48->nr_entries = n256->nr_entries;
for (i = 0; i < 256; i++) {
if (n256->values[i].type == UNSET)
continue;
n48->keys[count] = i;
n48->values[count] = n256->values[i];
count++;
}
free(n256);
result->type = NODE48;
result->value.ptr = n48;
}
static bool _remove(struct radix_tree *rt, struct value *root, uint8_t *kb, uint8_t *ke)
{
bool r;
unsigned i;
struct value_chain *vc;
struct prefix_chain *pc;
struct node4 *n4;
struct node16 *n16;
struct node48 *n48;
struct node256 *n256;
if (kb == ke) {
if (root->type == VALUE) {
root->type = UNSET;
_dtr(rt, root->value);
return true;
} else if (root->type == VALUE_CHAIN) {
vc = root->value.ptr;
_dtr(rt, vc->value);
memcpy(root, &vc->child, sizeof(*root));
free(vc);
return true;
} else
return false;
}
switch (root->type) {
case UNSET:
case VALUE:
// this is a value for a prefix of the key
return false;
case VALUE_CHAIN:
vc = root->value.ptr;
r = _remove(rt, &vc->child, kb, ke);
if (r && (vc->child.type == UNSET)) {
memcpy(root, &vc->child, sizeof(*root));
free(vc);
}
return r;
case PREFIX_CHAIN:
pc = root->value.ptr;
if (ke - kb < pc->len)
return false;
for (i = 0; i < pc->len; i++)
if (kb[i] != pc->prefix[i])
return false;
return _remove(rt, &pc->child, kb + pc->len, ke);
case NODE4:
n4 = root->value.ptr;
for (i = 0; i < n4->nr_entries; i++) {
if (n4->keys[i] == *kb) {
r = _remove(rt, n4->values + i, kb + 1, ke);
if (r && n4->values[i].type == UNSET) {
n4->nr_entries--;
if (i < n4->nr_entries)
// slide the entries down
memmove(n4->keys + i, n4->keys + i + 1,
sizeof(*n4->keys) * (n4->nr_entries - i));
if (!n4->nr_entries)
root->type = UNSET;
}
return r;
}
}
return false;
case NODE16:
n16 = root->value.ptr;
for (i = 0; i < n16->nr_entries; i++) {
if (n16->keys[i] == *kb) {
r = _remove(rt, n16->values + i, kb + 1, ke);
if (r && n16->values[i].type == UNSET) {
n16->nr_entries--;
if (i < n16->nr_entries)
// slide the entries down
memmove(n16->keys + i, n16->keys + i + 1,
sizeof(*n16->keys) * (n16->nr_entries - i));
if (n16->nr_entries <= 4)
_degrade_to_n4(n16, root);
}
return r;
}
}
return false;
case NODE48:
n48 = root->value.ptr;
i = n48->keys[*kb];
if (i < 48) {
r = _remove(rt, n48->values + i, kb + 1, ke);
if (r && n48->values[i].type == UNSET) {
n48->keys[*kb] = 48;
n48->nr_entries--;
if (n48->nr_entries <= 16)
_degrade_to_n16(n48, root);
}
return r;
}
return false;
case NODE256:
n256 = root->value.ptr;
r = _remove(rt, n256->values + (*kb), kb + 1, ke);
if (r && n256->values[*kb].type == UNSET) {
n256->nr_entries--;
if (n256->nr_entries <= 48)
_degrade_to_n48(n256, root);
}
return r;
}
return false;
}
void radix_tree_delete(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
bool radix_tree_remove(struct radix_tree *rt, uint8_t *key_begin, uint8_t *key_end)
{
assert(0);
if (_remove(rt, &rt->root, key_begin, key_end)) {
rt->nr_entries--;
return true;
}
return false;
}
static bool _prefix_chain_matches(struct lookup_result *lr, uint8_t *ke)
{
// It's possible the top node is a prefix chain, and
// the remaining key matches part of it.
if (lr->v->type == PREFIX_CHAIN) {
unsigned i, rlen = ke - lr->kb;
struct prefix_chain *pc = lr->v->value.ptr;
if (rlen < pc->len) {
for (i = 0; i < rlen; i++)
if (pc->prefix[i] != lr->kb[i])
return false;
return true;
}
}
return false;
}
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *kb, uint8_t *ke)
{
unsigned count = 0;
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke || _prefix_chain_matches(&lr, ke)) {
count = _free_node(rt, *lr.v);
lr.v->type = UNSET;
}
rt->nr_entries -= count;
return count;
}
bool radix_tree_lookup(struct radix_tree *rt,
@ -567,4 +791,72 @@ bool radix_tree_lookup(struct radix_tree *rt,
return false;
}
// FIXME: build up the keys too
static bool _iterate(struct value *v, struct radix_tree_iterator *it)
{
unsigned i;
struct value_chain *vc;
struct prefix_chain *pc;
struct node4 *n4;
struct node16 *n16;
struct node48 *n48;
struct node256 *n256;
switch (v->type) {
case UNSET:
// can't happen
break;
case VALUE:
return it->visit(it, NULL, NULL, v->value);
case VALUE_CHAIN:
vc = v->value.ptr;
return it->visit(it, NULL, NULL, vc->value) && _iterate(&vc->child, it);
case PREFIX_CHAIN:
pc = v->value.ptr;
return _iterate(&pc->child, it);
case NODE4:
n4 = (struct node4 *) v->value.ptr;
for (i = 0; i < n4->nr_entries; i++)
if (!_iterate(n4->values + i, it))
return false;
return true;
case NODE16:
n16 = (struct node16 *) v->value.ptr;
for (i = 0; i < n16->nr_entries; i++)
if (!_iterate(n16->values + i, it))
return false;
return true;
case NODE48:
n48 = (struct node48 *) v->value.ptr;
for (i = 0; i < n48->nr_entries; i++)
if (!_iterate(n48->values + i, it))
return false;
return true;
case NODE256:
n256 = (struct node256 *) v->value.ptr;
for (i = 0; i < 256; i++)
if (n256->values[i].type != UNSET && !_iterate(n256->values + i, it))
return false;
return true;
}
// can't get here
return false;
}
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
struct radix_tree_iterator *it)
{
struct lookup_result lr = _lookup_prefix(&rt->root, kb, ke);
if (lr.kb == ke || _prefix_chain_matches(&lr, ke))
_iterate(lr.v, it);
}
//----------------------------------------------------------------

View File

@ -25,19 +25,34 @@ union radix_value {
uint64_t n;
};
struct radix_tree *radix_tree_create(void);
typedef void (*radix_value_dtr)(void *context, union radix_value v);
// dtr may be NULL
void radix_tree_destroy(struct radix_tree *rt, radix_value_dtr dtr, void *context);
// dtr will be called on any deleted entries. dtr may be NULL.
struct radix_tree *radix_tree_create(radix_value_dtr dtr, void *dtr_context);
void radix_tree_destroy(struct radix_tree *rt);
unsigned radix_tree_size(struct radix_tree *rt);
bool radix_tree_insert(struct radix_tree *rt, uint8_t *kb, uint8_t *ke, union radix_value v);
void radix_tree_delete(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
bool radix_tree_remove(struct radix_tree *rt, uint8_t *kb, uint8_t *ke);
// Returns the number of values removed
unsigned radix_tree_remove_prefix(struct radix_tree *rt, uint8_t *prefix_b, uint8_t *prefix_e);
bool radix_tree_lookup(struct radix_tree *rt,
uint8_t *kb, uint8_t *ke, union radix_value *result);
// The radix tree stores entries in lexicographical order. Which means
// we can iterate entries, in order. Or iterate entries with a particular
// prefix.
struct radix_tree_iterator {
// Returns false if the iteration should end.
bool (*visit)(struct radix_tree_iterator *it,
uint8_t *kb, uint8_t *ke, union radix_value v);
};
void radix_tree_iterate(struct radix_tree *rt, uint8_t *kb, uint8_t *ke,
struct radix_tree_iterator *it);
//----------------------------------------------------------------
#endif

View File

@ -832,7 +832,7 @@ void lvm_do_backup(const char *vgname)
pthread_mutex_lock(&lvm_lock);
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, WARN_PV_READ, &consistent);
vg = vg_read_internal(cmd, vgname, NULL /*vgid*/, 0, WARN_PV_READ, &consistent);
if (vg && consistent)
check_current_backup(vg);

View File

@ -44,6 +44,8 @@ LVMDBUS_BUILDDIR_FILES = \
LVMDBUSD = lvmdbusd
CLEAN_DIRS += __pycache__
include $(top_builddir)/make.tmpl
.PHONY: install_lvmdbusd

View File

@ -497,7 +497,7 @@ class Lv(LvCommon):
# it is a thin lv
if not dbo.IsThinVolume:
if optional_size == 0:
space = dbo.SizeBytes / 80
space = dbo.SizeBytes // 80
remainder = space % 512
optional_size = space + 512 - remainder

View File

@ -1009,6 +1009,8 @@ static void add_work_action(struct action *act)
pthread_mutex_unlock(&worker_mutex);
}
#define ERR_LVMETAD_NOT_RUNNING -200
static daemon_reply send_lvmetad(const char *id, ...)
{
daemon_reply reply;
@ -1029,9 +1031,9 @@ retry:
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0) {
err = lvmetad_handle.error ?: lvmetad_handle.socket_fd;
pthread_mutex_unlock(&lvmetad_mutex);
log_error("lvmetad_open reconnect error %d", err);
log_debug("lvmetad_open reconnect error %d", err);
memset(&reply, 0, sizeof(reply));
reply.error = err;
reply.error = ERR_LVMETAD_NOT_RUNNING;
va_end(ap);
return reply;
} else {
@ -1265,6 +1267,15 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
* caches, and tell lvmetad to set global invalid to 0.
*/
/*
* lvmetad not running:
* Even if we have not previously found lvmetad running,
* we attempt to connect and invalidate in case it has
* been started while lvmlockd is running. We don't
* want to allow lvmetad to be used with invalid data if
* it happens to be enabled and started after lvmlockd.
*/
if (inval_meta && (r->type == LD_RT_VG)) {
daemon_reply reply;
char *uuid;
@ -1284,8 +1295,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
"version = " FMTd64, (int64_t)new_version,
NULL);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
log_error("set_vg_info in lvmetad failed %d", reply.error);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
if (reply.error != ERR_LVMETAD_NOT_RUNNING)
log_error("set_vg_info in lvmetad failed %d", reply.error);
}
daemon_reply_destroy(reply);
}
@ -1300,8 +1313,10 @@ static int res_lock(struct lockspace *ls, struct resource *r, struct action *act
"global_invalid = " FMTd64, INT64_C(1),
NULL);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK"))
log_error("set_global_info in lvmetad failed %d", reply.error);
if (reply.error || strcmp(daemon_reply_str(reply, "response", ""), "OK")) {
if (reply.error != ERR_LVMETAD_NOT_RUNNING)
log_error("set_global_info in lvmetad failed %d", reply.error);
}
daemon_reply_destroy(reply);
}
@ -5848,7 +5863,7 @@ static int main_loop(daemon_state *ds_arg)
pthread_mutex_init(&lvmetad_mutex, NULL);
lvmetad_handle = lvmetad_open(NULL);
if (lvmetad_handle.error || lvmetad_handle.socket_fd < 0)
log_error("lvmetad_open error %d", lvmetad_handle.error);
log_debug("lvmetad_open error %d", lvmetad_handle.error);
else
lvmetad_connected = 1;
@ -5856,8 +5871,13 @@ static int main_loop(daemon_state *ds_arg)
* Attempt to rejoin lockspaces and adopt locks from a previous
* instance of lvmlockd that left behind lockspaces/locks.
*/
if (adopt_opt)
adopt_locks();
if (adopt_opt) {
/* FIXME: implement this without lvmetad */
if (!lvmetad_connected)
log_error("Cannot adopt locks without lvmetad running.");
else
adopt_locks();
}
while (1) {
rv = poll(pollfd, pollfd_maxi + 1, -1);

View File

@ -0,0 +1,53 @@
Version 2.02.178
================
There are going to be some large changes to the lvm2 codebase
over the next year or so. Starting with this release. These
changes should be internal rather than having a big effect on
the command line. Inevitably these changes will increase the
chance of bugs, so please be on the alert.
Remove support for obsolete metadata formats
--------------------------------------------
Support for the GFS pool format, and format used by the
original 1990's version of LVM1 have been removed.
Use asynchronous IO
-------------------
Almost all IO uses libaio now.
Rewrite label scanning
----------------------
Dave Teigland has reworked the label scanning and metadata reading
logic to minimise the amount of IOs issued. Combined with the aio changes
this can greatly improve scanning speed for some systems.
./configure options
-------------------
We're going to try and remove as many options from ./configure as we
can. Each option multiplies the number of possible configurations
that we should test (this testing is currently not occurring).
The first batch to be removed are:
--enable-testing
--with-snapshots
--with-mirrors
--with-raid
--with-thin
--with-cache
Stable targets that are in the upstream kernel will just be supported.
In future optional target flags will be given in two situations:
1) The target is experimental, or not upstream at all (eg, vdo).
2) The target is deprecated and support will be removed at some future date.
This decision could well be contentious, so could distro maintainers feel
free to comment.

View File

@ -21,6 +21,7 @@ ifeq ("@CLUSTER@", "shared")
endif
SOURCES =\
../base/data-struct/radix-tree.c \
activate/activate.c \
cache/lvmcache.c \
cache_segtype/cache.c \

125
lib/cache/lvmcache.c vendored
View File

@ -981,11 +981,25 @@ int lvmcache_dev_is_unchosen_duplicate(struct device *dev)
* The actual filters are evaluated too early, before a complete
* picture of all PVs is available, to eliminate these duplicates.
*
* By removing the filtered duplicates from unused_duplicate_devs, we remove
* By removing some duplicates from unused_duplicate_devs here, we remove
* the restrictions that are placed on using duplicate devs or VGs with
* duplicate devs.
*
* There may other kinds of duplicates that we want to ignore.
* In cases where we know that two duplicates refer to the same underlying
* storage, and we know which dev path to use, it's best for us to just
* use that one preferred device path and ignore the others. It is the cases
* where we are unsure whether dups refer to the same underlying storage where
* we need to keep the unused duplicate referenced in the
* unused_duplicate_devs list, and restrict what we allow done with it.
*
* In the case of md components, we usually filter these out in filter-md,
* but in the special case of md superblocks <= 1.0 where the superblock
* is at the end of the device, filter-md doesn't always eliminate them
* first, so we eliminate them here.
*
* There may other kinds of duplicates that we want to eliminate at
* this point (using the knowledge from the scan) that we couldn't
* eliminate in the filters prior to the scan.
*/
static void _filter_duplicate_devs(struct cmd_context *cmd)
@ -1004,6 +1018,34 @@ static void _filter_duplicate_devs(struct cmd_context *cmd)
dm_free(devl);
}
}
if (dm_list_empty(&_unused_duplicate_devs))
_found_duplicate_pvs = 0;
}
static void _warn_duplicate_devs(struct cmd_context *cmd)
{
char uuid[64] __attribute__((aligned(8)));
struct lvmcache_info *info;
struct device_list *devl, *devl2;
dm_list_iterate_items_safe(devl, devl2, &_unused_duplicate_devs) {
if (!id_write_format((const struct id *)devl->dev->pvid, uuid, sizeof(uuid)))
stack;
log_warn("WARNING: Not using device %s for PV %s.", dev_name(devl->dev), uuid);
}
dm_list_iterate_items_safe(devl, devl2, &_unused_duplicate_devs) {
/* info for the preferred device that we're actually using */
info = lvmcache_info_from_pvid(devl->dev->pvid, NULL, 0);
if (!id_write_format((const struct id *)info->dev->pvid, uuid, sizeof(uuid)))
stack;
log_warn("WARNING: PV %s prefers device %s because %s.",
uuid, dev_name(info->dev), info->dev->duplicate_prefer_reason);
}
}
/*
@ -1028,7 +1070,6 @@ static void _choose_preferred_devs(struct cmd_context *cmd,
struct dm_list *del_cache_devs,
struct dm_list *add_cache_devs)
{
char uuid[64] __attribute__((aligned(8)));
const char *reason;
struct dm_list altdevs;
struct dm_list new_unused;
@ -1229,9 +1270,7 @@ next:
alt = devl;
}
if (!id_write_format((const struct id *)dev1->pvid, uuid, sizeof(uuid)))
stack;
log_warn("WARNING: PV %s prefers device %s because %s.", uuid, dev_name(dev1), reason);
dev1->duplicate_prefer_reason = reason;
}
if (dev1 != info->dev) {
@ -1480,11 +1519,21 @@ int lvmcache_label_scan(struct cmd_context *cmd)
dm_list_splice(&_unused_duplicate_devs, &del_cache_devs);
/*
* We might want to move the duplicate device warnings until
* after this filtering so that we can skip warning about
* duplicates that we are filtering out.
* This may remove some entries from the unused_duplicates list for
* devs that we know are the same underlying dev.
*/
_filter_duplicate_devs(cmd);
/*
* Warn about remaining duplicates that may actually be separate copies of
* the same device.
*/
_warn_duplicate_devs(cmd);
if (!_found_duplicate_pvs && lvmetad_used()) {
log_warn("WARNING: Disabling lvmetad cache which does not support duplicate PVs.");
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_DUPLICATES);
}
}
/* Perform any format-specific scanning e.g. text files */
@ -1509,6 +1558,53 @@ int lvmcache_label_scan(struct cmd_context *cmd)
return r;
}
/*
* When not using lvmetad, lvmcache_label_scan() detects duplicates in
* the basic label_scan(), then filters out some dups, and chooses
* preferred duplicates to use.
*
* When using lvmetad, pvscan --cache does not use lvmcache_label_scan(),
* only label_scan() which detects the duplicates. This function is used
* after pvscan's label_scan() to filter out some dups, print any warnings,
* and disable lvmetad if any dups are left.
*/
void lvmcache_pvscan_duplicate_check(struct cmd_context *cmd)
{
struct device_list *devl;
/* Check if label_scan() detected any dups. */
if (!_found_duplicate_pvs)
return;
/*
* Once all the dups are identified, they are moved from the
* "found" list to the "unused" list to sort out.
*/
dm_list_splice(&_unused_duplicate_devs, &_found_duplicate_devs);
/*
* Remove items from the dups list that we know are the same
* underlying dev, e.g. md components, that we want to just ignore.
*/
_filter_duplicate_devs(cmd);
/*
* If no more dups after ignoring some, then we can use lvmetad.
*/
if (!_found_duplicate_pvs)
return;
/* Duplicates are found where we would have to pick one, so disable lvmetad. */
dm_list_iterate_items(devl, &_unused_duplicate_devs)
log_warn("WARNING: found device with duplicate %s", dev_name(devl->dev));
log_warn("WARNING: Disabling lvmetad cache which does not support duplicate PVs.");
lvmetad_set_disabled(cmd, LVMETAD_DISABLE_REASON_DUPLICATES);
lvmetad_make_unused(cmd);
}
int lvmcache_get_vgnameids(struct cmd_context *cmd, int include_internal,
struct dm_list *vgnameids)
{
@ -2303,14 +2399,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller,
*/
if (!created) {
if (info->dev != dev) {
log_warn("WARNING: PV %s on %s was already found on %s.",
uuid, dev_name(dev), dev_name(info->dev));
if (!_found_duplicate_pvs && lvmetad_used()) {
log_warn("WARNING: Disabling lvmetad cache which does not support duplicate PVs.");
lvmetad_set_disabled(labeller->fmt->cmd, LVMETAD_DISABLE_REASON_DUPLICATES);
}
_found_duplicate_pvs = 1;
log_debug_cache("PV %s on %s was already found on %s.",
uuid, dev_name(dev), dev_name(info->dev));
strncpy(dev->pvid, pvid_s, sizeof(dev->pvid));
@ -2328,6 +2418,7 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller,
devl->dev = dev;
dm_list_add(&_found_duplicate_devs, &devl->list);
_found_duplicate_pvs = 1;
return NULL;
}

View File

@ -188,6 +188,8 @@ uint64_t lvmcache_smallest_mda_size(struct lvmcache_info *info);
int lvmcache_found_duplicate_pvs(void);
void lvmcache_pvscan_duplicate_check(struct cmd_context *cmd);
int lvmcache_get_unused_duplicate_devs(struct cmd_context *cmd, struct dm_list *head);
int vg_has_duplicate_pvs(struct volume_group *vg);

2
lib/cache/lvmetad.c vendored
View File

@ -2350,6 +2350,8 @@ int lvmetad_pvscan_all_devs(struct cmd_context *cmd, int do_wait)
label_scan(cmd);
lvmcache_pvscan_duplicate_check(cmd);
if (lvmcache_found_duplicate_pvs()) {
log_warn("WARNING: Scan found duplicate PVs.");
return 0;

View File

@ -15,6 +15,8 @@
#define _GNU_SOURCE
#include "lib/device/bcache.h"
#include "base/data-struct/radix-tree.h"
#include "lib/log/lvm-logging.h"
#include "lib/log/log.h"
@ -133,6 +135,7 @@ struct async_engine {
struct io_engine e;
io_context_t aio_context;
struct cb_set *cbs;
unsigned page_mask;
};
static struct async_engine *_to_async(struct io_engine *e)
@ -163,7 +166,7 @@ static bool _async_issue(struct io_engine *ioe, enum dir d, int fd,
struct control_block *cb;
struct async_engine *e = _to_async(ioe);
if (((uintptr_t) data) & (PAGE_SIZE - 1)) {
if (((uintptr_t) data) & e->page_mask) {
log_warn("misaligned data buffer");
return false;
}
@ -275,6 +278,8 @@ struct io_engine *create_async_io_engine(void)
return NULL;
}
e->page_mask = sysconf(_SC_PAGESIZE) - 1;
return &e->e;
}
@ -450,12 +455,7 @@ struct bcache {
struct dm_list clean;
struct dm_list io_pending;
/*
* Hash table.
*/
unsigned nr_buckets;
unsigned hash_mask;
struct dm_list *buckets;
struct radix_tree *rtree;
/*
* Statistics
@ -470,85 +470,60 @@ struct bcache {
//----------------------------------------------------------------
/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */
#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001ULL
struct key_parts {