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:
commit
dbba1e9b93
52
.gitignore
vendored
52
.gitignore
vendored
@ -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
|
||||
|
@ -1 +1 @@
|
||||
1.02.147-git (2017-12-18)
|
||||
1.02.147-git (2018-05-24)
|
||||
|
27
WHATS_NEW
27
WHATS_NEW
@ -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
|
||||
=====================================
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -44,6 +44,8 @@ LVMDBUS_BUILDDIR_FILES = \
|
||||
|
||||
LVMDBUSD = lvmdbusd
|
||||
|
||||
CLEAN_DIRS += __pycache__
|
||||
|
||||
include $(top_builddir)/make.tmpl
|
||||
|
||||
.PHONY: install_lvmdbusd
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
53
doc/release-notes/2.02.178
Normal file
53
doc/release-notes/2.02.178
Normal 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.
|
@ -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
125
lib/cache/lvmcache.c
vendored
@ -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;
|
||||
}
|
||||
|
||||
|
2
lib/cache/lvmcache.h
vendored
2
lib/cache/lvmcache.h
vendored
@ -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
2
lib/cache/lvmetad.c
vendored
@ -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;
|
||||
|
@ -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 {
|
||||