mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-21 13:34:40 +03:00
dev_manager: fix table for cache with cachevol
When using cached LV with cachevols (so not with cachepool), the loaded table could have been using more then one mapping line for sub devices - resulting into data corruption in some cases when i.e. taking snapshot of such cached LV with and instead of single line - 2 lines were generated into DM table as the code skipped protection again repeated addition. vg-fast_cvol-cdata: 0 16384 linear 253:2 16384 vg-fast_cvol-cdata: 16384 16384 linear 253:2 16384 New code is also refactoring to use _add_new_cvol_subdev_to_dtree (similar _add_cvol_subdev.. ) and also the addition of subdev has been moved after check for already processed node. Also the cachevol sub devices are now added with the insertion of cachevol with cached LV.
This commit is contained in:
parent
ad582da3ca
commit
a985d5c63d
@ -3330,6 +3330,66 @@ static int _add_new_external_lv_to_dtree(struct dev_manager *dm,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_new_cvol_subdev_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
const struct logical_volume *lv,
|
||||
struct lv_activate_opts *laopts,
|
||||
struct lv_layer *lvlayer,
|
||||
int meta_or_data)
|
||||
{
|
||||
const char *layer = meta_or_data ? "cmeta" : "cdata";
|
||||
const struct lv_segment *lvseg = first_seg(lv);
|
||||
uint64_t size = meta_or_data ? lvseg->metadata_len : lvseg->data_len;
|
||||
const struct logical_volume *pool_lv = lvseg->pool_lv;
|
||||
struct dm_tree_node *dnode;
|
||||
char *dlid, *dlid_pool, *name;
|
||||
union lvid lvid = {
|
||||
{
|
||||
lv->vg->id,
|
||||
/* When ID is provided in form of metadata_id or data_id, otherwise use CVOL ID */
|
||||
(meta_or_data && lvseg->metadata_id) ? *lvseg->metadata_id :
|
||||
(lvseg->data_id) ? *lvseg->data_id : pool_lv->lvid.id[1]
|
||||
}
|
||||
};
|
||||
|
||||
if (!(dlid = dm_build_dm_uuid(dm->mem, UUID_PREFIX, (const char *)&lvid.s, layer)))
|
||||
return_0;
|
||||
|
||||
if (!(name = dm_build_dm_name(dm->mem, lv->vg->name, pool_lv->name, layer)))
|
||||
return_0;
|
||||
|
||||
if (!(dnode = dm_tree_add_new_dev_with_udev_flags(dtree, name, dlid, -1, -1,
|
||||
read_only_lv(lv, laopts, layer),
|
||||
((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
|
||||
lvlayer,
|
||||
_get_udev_flags(dm, lv, layer, laopts->noscan,
|
||||
laopts->temporary, 0))))
|
||||
return_0;
|
||||
|
||||
if (dm->track_pending_delete) {
|
||||
log_debug_activation("Using error for pending delete of %s-%s.",
|
||||
display_lvname(lv), layer);
|
||||
if (!dm_tree_node_add_error_target(dnode, size))
|
||||
return_0;
|
||||
} else {
|
||||
/* add load_segment to meta dnode: linear, size of meta area */
|
||||
if (!add_linear_area_to_dtree(dnode, size, lv->vg->extent_size,
|
||||
lv->vg->cmd->use_linear_target,
|
||||
lv->vg->name, lv->name))
|
||||
return_0;
|
||||
|
||||
if (!(dlid_pool = build_dm_uuid(dm->mem, pool_lv, NULL)))
|
||||
return_0;
|
||||
|
||||
/* add seg_area to prev load_seg: offset 0 maps to cachevol lv offset 0 */
|
||||
if (!dm_tree_node_add_target_area(dnode, NULL, dlid_pool,
|
||||
meta_or_data ? 0 : lvseg->metadata_len))
|
||||
return_0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int _add_segment_to_dtree(struct dev_manager *dm,
|
||||
struct dm_tree *dtree,
|
||||
struct dm_tree_node *dnode,
|
||||
@ -3465,114 +3525,6 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lv_is_cache(lv) && lv_is_cache_vol(first_seg(lv)->pool_lv)) {
|
||||
struct logical_volume *pool_lv = first_seg(lv)->pool_lv;
|
||||
struct lv_segment *lvseg = first_seg(lv);
|
||||
struct volume_group *vg = lv->vg;
|
||||
struct dm_tree_node *dnode_meta;
|
||||
struct dm_tree_node *dnode_data;
|
||||
union lvid lvid_meta;
|
||||
union lvid lvid_data;
|
||||
char *name_meta;
|
||||
char *name_data;
|
||||
char *dlid_meta;
|
||||
char *dlid_data;
|
||||
char *dlid_pool;
|
||||
uint64_t meta_size = first_seg(lv)->metadata_len;
|
||||
uint64_t data_size = first_seg(lv)->data_len;
|
||||
uint16_t udev_flags = _get_udev_flags(dm, lv, layer,
|
||||
laopts->noscan, laopts->temporary,
|
||||
0);
|
||||
|
||||
if (lv_is_pending_delete(lvseg->lv))
|
||||
dm->track_pending_delete = 1;
|
||||
|
||||
log_debug("Add cachevol %s to dtree before cache %s.", pool_lv->name, lv->name);
|
||||
|
||||
if (!_add_new_lv_to_dtree(dm, dtree, pool_lv, laopts, lv_layer(pool_lv))) {
|
||||
log_error("Failed to add cachevol to dtree before cache.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&lvid_meta, 0, sizeof(lvid_meta));
|
||||
memset(&lvid_data, 0, sizeof(lvid_meta));
|
||||
memcpy(&lvid_meta.id[0], &vg->id, sizeof(struct id));
|
||||
memcpy(&lvid_meta.id[1], lvseg->metadata_id ? : &pool_lv->lvid.id[1], sizeof(struct id));
|
||||
memcpy(&lvid_data.id[0], &vg->id, sizeof(struct id));
|
||||
memcpy(&lvid_data.id[1], lvseg->data_id ? : &pool_lv->lvid.id[1], sizeof(struct id));
|
||||
|
||||
if (!(dlid_meta = dm_build_dm_uuid(dm->mem, UUID_PREFIX, (const char *)&lvid_meta.s, "cmeta")))
|
||||
return_0;
|
||||
if (!(dlid_data = dm_build_dm_uuid(dm->mem, UUID_PREFIX, (const char *)&lvid_data.s, "cdata")))
|
||||
return_0;
|
||||
|
||||
if (!(name_meta = dm_build_dm_name(dm->mem, vg->name, pool_lv->name, "cmeta")))
|
||||
return_0;
|
||||
if (!(name_data = dm_build_dm_name(dm->mem, vg->name, pool_lv->name, "cdata")))
|
||||
return_0;
|
||||
|
||||
if (!(dlid_pool = build_dm_uuid(dm->mem, pool_lv, NULL)))
|
||||
return_0;
|
||||
|
||||
/* add meta dnode */
|
||||
if (!(dnode_meta = dm_tree_add_new_dev_with_udev_flags(dtree,
|
||||
name_meta,
|
||||
dlid_meta,
|
||||
-1, -1,
|
||||
read_only_lv(lv, laopts, layer),
|
||||
((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
|
||||
lvlayer,
|
||||
udev_flags)))
|
||||
return_0;
|
||||
|
||||
if (dm->track_pending_delete) {
|
||||
log_debug_activation("Using error for pending meta delete %s.", display_lvname(lv));
|
||||
if (!dm_tree_node_add_error_target(dnode_meta, meta_size))
|
||||
return_0;
|
||||
} else {
|
||||
/* add load_segment to meta dnode: linear, size of meta area */
|
||||
if (!add_linear_area_to_dtree(dnode_meta,
|
||||
meta_size,
|
||||
lv->vg->extent_size,
|
||||
lv->vg->cmd->use_linear_target,
|
||||
lv->vg->name, lv->name))
|
||||
return_0;
|
||||
|
||||
/* add seg_area to prev load_seg: offset 0 maps to cachepool lv offset 0 */
|
||||
if (!dm_tree_node_add_target_area(dnode_meta, NULL, dlid_pool, 0))
|
||||
return_0;
|
||||
}
|
||||
|
||||
/* add data dnode */
|
||||
if (!(dnode_data = dm_tree_add_new_dev_with_udev_flags(dtree,
|
||||
name_data,
|
||||
dlid_data,
|
||||
-1, -1,
|
||||
read_only_lv(lv, laopts, layer),
|
||||
((lv->vg->status & PRECOMMITTED) | laopts->revert) ? 1 : 0,
|
||||
lvlayer,
|
||||
udev_flags)))
|
||||
return_0;
|
||||
|
||||
if (dm->track_pending_delete) {
|
||||
log_debug_activation("Using error for pending data delete %s.", display_lvname(lv));
|
||||
if (!dm_tree_node_add_error_target(dnode_data, data_size))
|
||||
return_0;
|
||||
} else {
|
||||
/* add load_segment to data dnode: linear, size of data area */
|
||||
if (!add_linear_area_to_dtree(dnode_data,
|
||||
data_size,
|
||||
lv->vg->extent_size,
|
||||
lv->vg->cmd->use_linear_target,
|
||||
lv->vg->name, lv->name))
|
||||
return_0;
|
||||
|
||||
/* add seg_area to prev load_seg: offset 0 maps to cachepool lv after meta */
|
||||
if (!dm_tree_node_add_target_area(dnode_data, NULL, dlid_pool, meta_size))
|
||||
return_0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME Seek a simpler way to lay out the snapshot-merge tree. */
|
||||
|
||||
if (!layer && lv_is_merging_origin(lv)) {
|
||||
@ -3675,6 +3627,14 @@ static int _add_new_lv_to_dtree(struct dev_manager *dm, struct dm_tree *dtree,
|
||||
/* Fow now used only by cache segtype, TODO snapshots */
|
||||
dm->track_pending_delete = 1;
|
||||
|
||||
if (lv_is_cache_vol(lv))
|
||||
dm_list_iterate_items(sl, &lv->segs_using_this_lv)
|
||||
if (lv_is_cache(sl->seg->lv) &&
|
||||
/* Cachevol is used by cache LV segment -> add cvol-cdata/cmeta extra layer */
|
||||
(!_add_new_cvol_subdev_to_dtree(dm, dtree, sl->seg->lv, laopts, lvlayer, 0) ||
|
||||
!_add_new_cvol_subdev_to_dtree(dm, dtree, sl->seg->lv, laopts, lvlayer, 1)))
|
||||
return_0;
|
||||
|
||||
/* This is unused cache-pool - make metadata accessible */
|
||||
if (lv_is_cache_pool(lv))
|
||||
lv = first_seg(lv)->metadata_lv;
|
||||
|
Loading…
Reference in New Issue
Block a user