From 352a99b95aa9bcbeb48b357070aba5ab79cb72de Mon Sep 17 00:00:00 2001 From: Alasdair Kergon Date: Tue, 25 Oct 2005 19:08:21 +0000 Subject: [PATCH] Use dm_is_dm_major instead of local copy. Allow mapped devices to be used as PVs safely. --- WHATS_NEW | 3 ++ lib/activate/activate.c | 35 ++++++++++++++++ lib/activate/activate.h | 6 +++ lib/activate/dev_manager.c | 82 ++++++++++++++++++++++++++++++++++---- lib/activate/dev_manager.h | 5 +++ lib/cache/lvmcache.c | 8 ++-- lib/filters/filter.c | 20 +--------- lib/filters/filter.h | 1 - lib/metadata/lv_manip.c | 3 ++ lib/metadata/metadata.c | 8 ++++ tools/vgmerge.c | 20 ++++++++++ 11 files changed, 159 insertions(+), 32 deletions(-) diff --git a/WHATS_NEW b/WHATS_NEW index 892fce126..2d12114cb 100644 --- a/WHATS_NEW +++ b/WHATS_NEW @@ -1,5 +1,8 @@ Version 2.02.00 - =================================== + Add DEFS to make.tmpl. + Use dm_is_dm_major instead of local copy. + Allow mapped devices to be used as PVs. Move set_selinux_context into libdevmapper. Fix automatic text metadata buffer expansion (using macro). Cache formatted text metadata buffer between metadata area writes. diff --git a/lib/activate/activate.c b/lib/activate/activate.c index bbf45f7c1..6bc72ed69 100644 --- a/lib/activate/activate.c +++ b/lib/activate/activate.c @@ -26,6 +26,7 @@ #include "dev_manager.h" #include "str_list.h" #include "config.h" +#include "filter.h" #include #include @@ -144,6 +145,12 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) return 1; } +int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv, + struct volume_group *vg) +{ + return 0; +} + void activation_exit(void) { return; @@ -790,6 +797,34 @@ int lv_mknodes(struct cmd_context *cmd, const struct logical_volume *lv) return r; } +/* + * Does PV use VG somewhere in its construction? + * Returns 1 on failure. + */ +int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv, + struct volume_group *vg) +{ + struct dev_manager *dm; + int r; + + if (!activation()) + return 0; + + if (!dm_is_dm_major(MAJOR(pv->dev->dev))) + return 0; + + if (!(dm = dev_manager_create(cmd, vg->name))) { + stack; + return 1; + } + + r = dev_manager_device_uses_vg(dm, pv->dev, vg); + + dev_manager_destroy(dm); + + return r; +} + void activation_exit(void) { dev_manager_exit(); diff --git a/lib/activate/activate.h b/lib/activate/activate.h index 98e0876ad..bf5b8b089 100644 --- a/lib/activate/activate.h +++ b/lib/activate/activate.h @@ -76,4 +76,10 @@ int lv_mirror_percent(struct cmd_context *cmd, struct logical_volume *lv, int wa int lvs_in_vg_activated(struct volume_group *vg); int lvs_in_vg_opened(struct volume_group *vg); +/* + * Returns 1 if PV has a dependency tree that uses anything in VG. + */ +int pv_uses_vg(struct cmd_context *cmd, struct physical_volume *pv, + struct volume_group *vg); + #endif diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index de92333e5..2ade5a459 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -24,6 +24,7 @@ #include "toolcontext.h" #include "targets.h" #include "config.h" +#include "filter.h" #include #include @@ -54,6 +55,7 @@ */ #define MAX_TARGET_PARAMSIZE 50000 +#define UUID_PREFIX "LVM-" enum { ACTIVE = 0, @@ -170,14 +172,14 @@ static char *_build_dlid(struct dm_pool *mem, const char *lvid, const char *laye if (!layer) layer = ""; - len = 4 + strlen(lvid) + strlen(layer) + 2; + len = sizeof(UUID_PREFIX) + sizeof(union lvid) + strlen(layer); if (!(dlid = dm_pool_alloc(mem, len))) { stack; return NULL; } - sprintf(dlid, "LVM-%s%s%s", lvid, (*layer) ? "-" : "", layer); + sprintf(dlid, UUID_PREFIX "%s%s%s", lvid, (*layer) ? "-" : "", layer); return dlid; } @@ -2279,7 +2281,7 @@ fail: /* * Deactivate LV and all devices it references that nothing else has open. */ -int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv) +static int _tree_action(struct dev_manager *dm, struct logical_volume *lv, action_t action) { struct deptree *dtree; struct deptree_node *dnode; @@ -2302,12 +2304,23 @@ int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv) } /* Only process nodes with uuid of "LVM-" plus VG id. */ - if (!dm_deptree_deactivate_children(dnode, dlid, ID_LEN + 4)) { - stack; + switch(action) { + case DEACTIVATE: + if (!dm_deptree_deactivate_children(dnode, dlid, ID_LEN + 4)) { + stack; + goto out; + } + break; + case SUSPEND: + if (!dm_deptree_suspend_children(dnode, dlid, ID_LEN + 4)) { + stack; + goto out; + } + break; + default: + log_error("_tree_action: Action %u not supported.", action); goto out; - } - - fs_del_lv(lv); + } r = 1; @@ -2317,3 +2330,56 @@ out: return r; } +int dev_manager_deactivate(struct dev_manager *dm, struct logical_volume *lv) +{ + int r; + + r = _tree_action(dm, lv, DEACTIVATE); + + fs_del_lv(lv); + + return r; +} + +/* + * Does device use VG somewhere in its construction? + * Returns 1 if uncertain. + */ +int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev, + struct volume_group *vg) +{ + struct deptree *dtree; + struct deptree_node *dnode; + char dlid[sizeof(UUID_PREFIX) + sizeof(struct id) - 1]; + int r = 1; + + if (!(dtree = dm_deptree_create())) { + log_error("partial deptree creation failed"); + return r; + } + + if (!dm_deptree_add_dev(dtree, MAJOR(dev->dev), MINOR(dev->dev))) { + log_error("Failed to add device %s (%" PRIu32 ":%" PRIu32") to deptree", + dev_name(dev), (uint32_t) MAJOR(dev->dev), (uint32_t) MINOR(dev->dev)); + goto out; + } + + memcpy(dlid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1); + memcpy(dlid + sizeof(UUID_PREFIX) - 1, &vg->id.uuid[0], sizeof(vg->id)); + + if (!(dnode = dm_deptree_find_node(dtree, 0, 0))) { + log_error("Lost dependency tree root node"); + goto out; + } + + if (dm_deptree_children_use_uuid(dnode, dlid, sizeof(UUID_PREFIX) + sizeof(vg->id) - 1)) { + stack; + goto out; + } + + r = 0; + +out: + dm_deptree_free(dtree); + return r; +} diff --git a/lib/activate/dev_manager.h b/lib/activate/dev_manager.h index 4abca2a08..6a7519feb 100644 --- a/lib/activate/dev_manager.h +++ b/lib/activate/dev_manager.h @@ -17,9 +17,11 @@ #define _LVM_DEV_MANAGER_H struct logical_volume; +struct volume_group; struct cmd_context; struct dev_manager; struct dm_info; +struct device; /* * Constructor and destructor. @@ -55,4 +57,7 @@ int dev_manager_lv_rmnodes(const struct logical_volume *lv); */ int dev_manager_execute(struct dev_manager *dm); +int dev_manager_device_uses_vg(struct dev_manager *dm, struct device *dev, + struct volume_group *vg); + #endif diff --git a/lib/cache/lvmcache.c b/lib/cache/lvmcache.c index a104aa24d..773b80139 100644 --- a/lib/cache/lvmcache.c +++ b/lib/cache/lvmcache.c @@ -494,8 +494,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, pvid, dev_name(dev), dev_name(existing->dev)); return NULL; - } else if (is_dm_major(MAJOR(existing->dev->dev)) && - !is_dm_major(MAJOR(dev->dev))) { + } else if (dm_is_dm_major(MAJOR(existing->dev->dev)) && + !dm_is_dm_major(MAJOR(dev->dev))) { log_very_verbose("Ignoring duplicate PV %s on " "%s - using dm %s", pvid, dev_name(dev), @@ -507,8 +507,8 @@ struct lvmcache_info *lvmcache_add(struct labeller *labeller, const char *pvid, "using md %s", pvid, dev_name(existing->dev), dev_name(dev)); - else if (!is_dm_major(MAJOR(existing->dev->dev)) && - is_dm_major(MAJOR(dev->dev))) + else if (!dm_is_dm_major(MAJOR(existing->dev->dev)) && + dm_is_dm_major(MAJOR(dev->dev))) log_very_verbose("Duplicate PV %s on %s - " "using dm %s", pvid, dev_name(existing->dev), diff --git a/lib/filters/filter.c b/lib/filters/filter.c index f4968bef3..83aefe895 100644 --- a/lib/filters/filter.c +++ b/lib/filters/filter.c @@ -28,7 +28,6 @@ #define NUMBER_OF_MAJORS 4096 -/* FIXME Make this sparse */ /* 0 means LVM won't use this major number. */ static int _max_partitions_by_major[NUMBER_OF_MAJORS]; @@ -38,18 +37,12 @@ typedef struct { } device_info_t; static int _md_major = -1; -static dm_bitset_t _dm_bitset; int md_major(void) { return _md_major; } -int is_dm_major(int major) -{ - return dm_bit(_dm_bitset, major) ? 1 : 0; -} - /* * Devices are only checked for partition tables if their minor number * is a multiple of the number corresponding to their type below @@ -78,6 +71,7 @@ static const device_info_t device_info[] = { {"gnbd", 1}, /* Network block device */ {"ramdisk", 1}, /* RAM disk */ {"aoe", 16}, /* ATA over Ethernet */ + {"device-mapper", 1}, /* Other mapped devices */ {NULL, 0} }; @@ -187,11 +181,6 @@ static int _scan_proc_dev(const char *proc, const struct config_node *cn) if (!strncmp("md", line + i, 2) && isspace(*(line + i + 2))) _md_major = line_maj; - /* Look for dm devices */ - if (!strncmp("device-mapper", line + i, 13) && - isspace(*(line + i + 13))) - dm_bit_set(_dm_bitset, line_maj); - /* Go through the valid device names and if there is a match store max number of partitions */ for (j = 0; device_info[j].name != NULL; j++) { @@ -262,12 +251,6 @@ struct dev_filter *lvm_type_filter_create(const char *proc, f->destroy = lvm_type_filter_destroy; f->private = NULL; - if (!(_dm_bitset = dm_bitset_create(NULL, NUMBER_OF_MAJORS))) { - stack; - dm_free(f); - return NULL; - } - if (!_scan_proc_dev(proc, cn)) { stack; return NULL; @@ -278,7 +261,6 @@ struct dev_filter *lvm_type_filter_create(const char *proc, void lvm_type_filter_destroy(struct dev_filter *f) { - dm_bitset_destroy(_dm_bitset); dm_free(f); return; } diff --git a/lib/filters/filter.h b/lib/filters/filter.h index a05062d7d..c4c76c05e 100644 --- a/lib/filters/filter.h +++ b/lib/filters/filter.h @@ -36,7 +36,6 @@ struct dev_filter *lvm_type_filter_create(const char *proc, void lvm_type_filter_destroy(struct dev_filter *f); int md_major(void); -int is_dm_major(int major); int max_partitions(int major); #endif diff --git a/lib/metadata/lv_manip.c b/lib/metadata/lv_manip.c index 9b22b95d3..c7f9c807f 100644 --- a/lib/metadata/lv_manip.c +++ b/lib/metadata/lv_manip.c @@ -229,6 +229,9 @@ void set_lv_segment_area_lv(struct lv_segment *seg, uint32_t area_num, lv->status |= flags; } +static int _lv_segment_add_areas(struct logical_volume *lv, + struct lv_segment *seg, + uint32_t new_area_count) __attribute__ ((unused)); /* * Prepare for adding parallel areas to an existing segment. */ diff --git a/lib/metadata/metadata.c b/lib/metadata/metadata.c index 0fbaca72b..d68071945 100644 --- a/lib/metadata/metadata.c +++ b/lib/metadata/metadata.c @@ -22,6 +22,7 @@ #include "memlock.h" #include "str_list.h" #include "pv_alloc.h" +#include "activate.h" static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg, const char *pv_name) @@ -58,6 +59,13 @@ static int _add_pv_to_vg(struct format_instance *fid, struct volume_group *vg, return 0; } + /* Ensure PV doesn't depend on another PV already in the VG */ + if (pv_uses_vg(fid->fmt->cmd, pv, vg)) { + log_error("Physical volume %s might be constructed from same " + "volume group %s", pv_name, vg->name); + return 0; + } + if (!(pv->vg_name = dm_pool_strdup(mem, vg->name))) { log_error("vg->name allocation failed for '%s'", pv_name); return 0; diff --git a/tools/vgmerge.c b/tools/vgmerge.c index afe8c01de..fb6447082 100644 --- a/tools/vgmerge.c +++ b/tools/vgmerge.c @@ -20,6 +20,7 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, { struct volume_group *vg_to, *vg_from; struct lv_list *lvl1, *lvl2; + struct pv_list *pvl; int active; int consistent = 1; @@ -122,6 +123,25 @@ static int _vgmerge_single(struct cmd_context *cmd, const char *vg_name_to, } } + /* Check no PVs are constructed from either VG */ + list_iterate_items(pvl, &vg_to->pvs) { + if (pv_uses_vg(cmd, pvl->pv, vg_from)) { + log_error("Physical volume %s might be constructed " + "from same volume group %s.", + dev_name(pvl->pv->dev), vg_from->name); + goto error; + } + } + + list_iterate_items(pvl, &vg_from->pvs) { + if (pv_uses_vg(cmd, pvl->pv, vg_to)) { + log_error("Physical volume %s might be constructed " + "from same volume group %s.", + dev_name(pvl->pv->dev), vg_to->name); + goto error; + } + } + /* FIXME List arg: vg_show_with_pv_and_lv(vg_to); */ if (!archive(vg_from) || !archive(vg_to))