diff options
author | David Teigland <teigland@redhat.com> | 2022-02-22 15:03:11 -0600 |
---|---|---|
committer | David Teigland <teigland@redhat.com> | 2022-02-24 15:37:53 -0600 |
commit | 07338325e552bb692f2422f42750e70c9d31152c (patch) | |
tree | 46016e2027141fa85b7e5aae58c1ce6c14bb41b3 | |
parent | ac1f4bbbfd4c5f1387c3e0607f7d556409e7a4b4 (diff) | |
download | lvm2-dev-dct-devs3.tar.gz |
devices: fix name handlingdev-dct-devs3
- Fix cases where incorrect device paths were left
on the dev->aliases list. Leaving incorrect paths
on dev->aliases could result in using the wrong device.
- Fix a widespread incorrect assumption that dev_name()
always returns a valid path (or NULL). dev_name()
returns "[unknown]" when there are no paths to a
device, and is mainly meant to be used in messages.
- Check for valid dev paths in cases that want to use
the from dev_name() for things other than a message.
-rw-r--r-- | lib/activate/dev_manager.c | 9 | ||||
-rw-r--r-- | lib/device/dev-cache.c | 279 | ||||
-rw-r--r-- | lib/device/dev-cache.h | 4 | ||||
-rw-r--r-- | lib/device/dev-io.c | 34 | ||||
-rw-r--r-- | lib/device/dev-type.c | 3 | ||||
-rw-r--r-- | lib/device/device.h | 3 | ||||
-rw-r--r-- | lib/device/device_id.c | 17 | ||||
-rw-r--r-- | lib/label/hints.c | 2 | ||||
-rw-r--r-- | lib/label/label.c | 29 | ||||
-rw-r--r-- | lib/locking/lvmlockd.c | 4 | ||||
-rw-r--r-- | lib/metadata/mirror.c | 17 | ||||
-rw-r--r-- | lib/metadata/pv_list.c | 5 | ||||
-rw-r--r-- | lib/metadata/vg.c | 5 | ||||
-rw-r--r-- | test/shell/losetup-partscan.sh | 2 | ||||
-rw-r--r-- | tools/toollib.c | 6 |
15 files changed, 251 insertions, 168 deletions
diff --git a/lib/activate/dev_manager.c b/lib/activate/dev_manager.c index 63bfd9b74..2cae3bed1 100644 --- a/lib/activate/dev_manager.c +++ b/lib/activate/dev_manager.c @@ -2947,6 +2947,10 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, /* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */ for (s = start_area; s < areas; s++) { + + /* FIXME: dev_name() does not return NULL! It needs to check if dm_list_empty(&dev->aliases) + but this knot of logic is too complex to pull apart without careful deconstruction. */ + if ((seg_type(seg, s) == AREA_PV && (!seg_pvseg(seg, s) || !seg_pv(seg, s) || !seg_dev(seg, s) || !(name = dev_name(seg_dev(seg, s))) || !*name || @@ -2965,7 +2969,10 @@ int add_areas_line(struct dev_manager *dm, struct lv_segment *seg, return_0; num_error_areas++; } else if (seg_type(seg, s) == AREA_PV) { - if (!dm_tree_node_add_target_area(node, dev_name(seg_dev(seg, s)), NULL, + struct device *dev = seg_dev(seg, s); + name = dm_list_empty(&dev->aliases) ? NULL : dev_name(dev); + + if (!dm_tree_node_add_target_area(node, name, NULL, (seg_pv(seg, s)->pe_start + (extent_size * seg_pe(seg, s))))) return_0; num_existing_areas++; diff --git a/lib/device/dev-cache.c b/lib/device/dev-cache.c index d3fae4948..8db28bd84 100644 --- a/lib/device/dev-cache.c +++ b/lib/device/dev-cache.c @@ -351,7 +351,7 @@ static int _add_alias(struct device *dev, const char *path, enum add_hash hash) goto out; } - if (!(path = dm_pool_strdup(_cache.mem, path)) || + if (!(path = _strdup(path)) || !(sl = _zalloc(sizeof(*sl)))) { log_error("Failed to add allias to dev cache."); return 0; @@ -1162,6 +1162,17 @@ static int _insert(const char *path, const struct stat *info, return 1; } +static void _drop_all_aliases(struct device *dev) +{ + struct dm_str_list *strl, *strl2; + + dm_list_iterate_items_safe(strl, strl2, &dev->aliases) { + log_debug("Drop alias for %d:%d %s.", (int)MAJOR(dev->dev), (int)MINOR(dev->dev), strl->str); + dm_hash_remove(_cache.names, strl->str); + dm_list_del(&strl->list); + } +} + void dev_cache_scan(struct cmd_context *cmd) { log_debug_devs("Creating list of system devices."); @@ -1371,59 +1382,6 @@ int dev_cache_add_dir(const char *path) return 1; } -/* Check cached device name is still valid before returning it */ -/* This should be a rare occurrence */ -/* set quiet if the cache is expected to be out-of-date */ -/* FIXME Make rest of code pass/cache struct device instead of dev_name */ -const char *dev_name_confirmed(struct device *dev, int quiet) -{ - struct stat buf; - const char *name; - int r; - - if ((dev->flags & DEV_REGULAR)) - return dev_name(dev); - - while ((r = stat(name = dm_list_item(dev->aliases.n, - struct dm_str_list)->str, &buf)) || - (buf.st_rdev != dev->dev)) { - if (r < 0) { - if (quiet) - log_sys_debug("stat", name); - else - log_sys_error("stat", name); - } - if (quiet) - log_debug_devs("Path %s no longer valid for device(%d,%d)", - name, (int) MAJOR(dev->dev), - (int) MINOR(dev->dev)); - else - log_warn("Path %s no longer valid for device(%d,%d)", - name, (int) MAJOR(dev->dev), - (int) MINOR(dev->dev)); - - /* Remove the incorrect hash entry */ - dm_hash_remove(_cache.names, name); - - /* Leave list alone if there isn't an alternative name */ - /* so dev_name will always find something to return. */ - /* Otherwise add the name to the correct device. */ - if (dm_list_size(&dev->aliases) > 1) { - dm_list_del(dev->aliases.n); - if (!r) - _insert(name, &buf, 0, obtain_device_list_from_udev()); - continue; - } - - /* Scanning issues this inappropriately sometimes. */ - log_debug_devs("Aborting - please provide new pathname for what " - "used to be %s", name); - return NULL; - } - - return dev_name(dev); -} - struct device *dev_hash_get(const char *name) { return (struct device *) dm_hash_lookup(_cache.names, name); @@ -1452,26 +1410,23 @@ static void _remove_alias(struct device *dev, const char *name) * deactivated LV. Those old paths are all invalid and are dropped here. */ -static void _verify_aliases(struct device *dev, const char *newname) +static void _verify_aliases(struct device *dev) { struct dm_str_list *strl, *strl2; struct stat st; dm_list_iterate_items_safe(strl, strl2, &dev->aliases) { - /* newname was just stat'd and added by caller */ - if (newname && !strcmp(strl->str, newname)) - continue; - if (stat(strl->str, &st) || (st.st_rdev != dev->dev)) { - log_debug("Drop invalid path %s for %d:%d (new path %s).", - strl->str, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), newname ?: ""); + log_debug("Drop alias for %d:%d invalid path %s %d:%d.", + (int)MAJOR(dev->dev), (int)MINOR(dev->dev), strl->str, + (int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev)); dm_hash_remove(_cache.names, strl->str); dm_list_del(&strl->list); } } } -struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f) +static struct device *_dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f, int existing) { struct device *dev = (struct device *) dm_hash_lookup(_cache.names, name); struct stat st; @@ -1485,13 +1440,18 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d if (dev && (dev->flags & DEV_REGULAR)) return dev; + if (dev && dm_list_empty(&dev->aliases)) { + /* shouldn't happen */ + log_warn("Ignoring dev with no valid paths for %s.", name); + return NULL; + } + /* - * The requested path is invalid, remove any dev-cache - * info for it. + * The requested path is invalid, remove any dev-cache info for it. */ if (stat(name, &st)) { if (dev) { - log_print("Device path %s is invalid for %d:%d %s.", + log_debug("Device path %s is invalid for %d:%d %s.", name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev)); dm_hash_remove(_cache.names, name); @@ -1499,11 +1459,17 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d _remove_alias(dev, name); /* Remove any other names in dev->aliases that are incorrect. */ - _verify_aliases(dev, NULL); + _verify_aliases(dev); } return NULL; } + if (dev && dm_list_empty(&dev->aliases)) { + /* shouldn't happen */ + log_warn("Ignoring dev with no valid paths for %s.", name); + return NULL; + } + if (!S_ISBLK(st.st_mode)) { log_debug("Not a block device %s.", name); return NULL; @@ -1514,26 +1480,110 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d * Remove incorrect info and then add new dev-cache entry. */ if (dev && (st.st_rdev != dev->dev)) { - log_debug("Device path %s does not match %d:%d %s.", - name, (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev)); + struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev); + + /* + * lvm commands create this condition when they + * activate/deactivate LVs combined with creating new LVs. + * The command does not purge dev structs when deactivating + * an LV (which it probably should do), but the better + * approach would be not using dev-cache at all for LVs. + */ + + log_debug("Dropping aliases for device entry %d:%d %s for new device %d:%d %s.", + (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev_name(dev), + (int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev), name); + + _drop_all_aliases(dev); - dm_hash_remove(_cache.names, name); + if (dev_by_devt) { + log_debug("Dropping aliases for device entry %d:%d %s for new device %d:%d %s.", + (int)MAJOR(dev_by_devt->dev), (int)MINOR(dev_by_devt->dev), dev_name(dev_by_devt), + (int)MAJOR(st.st_rdev), (int)MINOR(st.st_rdev), name); + + _drop_all_aliases(dev_by_devt); + } + +#if 0 + /* + * I think only lvm's own dm devs should be added here, so use + * a warning to look for any other unknown cases. + */ + if (MAJOR(st.st_rdev) != cmd->dev_types->device_mapper_major) { + log_warn("WARNING: new device appeared %d:%d %s", + (int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name); + } +#endif + + if (!_insert_dev(name, st.st_rdev)) + return_NULL; + + /* Get the struct dev that was just added. */ + dev = (struct device *) dm_hash_lookup(_cache.names, name); - _remove_alias(dev, name); + if (!dev) { + log_error("Failed to get device %s", name); + return NULL; + } - /* Remove any other names in dev->aliases that are incorrect. */ - _verify_aliases(dev, NULL); + goto out; + } - /* Add new dev-cache entry next. */ - dev = NULL; + if (dev && dm_list_empty(&dev->aliases)) { + /* shouldn't happen */ + log_warn("Ignoring dev with no valid paths for %s.", name); + return NULL; } + if (!dev && existing) + return_NULL; + /* - * Either add a new struct dev for st_rdev and name, - * or add name as a new alias for an existing struct dev - * for st_rdev. + * This case should never be hit for a PV. It should only + * happen when the command is opening a new LV it has created. + * Add an arg to all callers indicating when the arg should be + * new (for an LV) and not existing. + * FIXME: fix this further by not using dev-cache struct devs + * at all for new dm devs (LVs) that lvm uses. Make the + * dev-cache contain only devs for PVs. + * Places to fix that use a dev for LVs include: + * . lv_resize opening lv to discard + * . wipe_lv opening lv to zero it + * . _extend_sanlock_lv opening lv to extend it + * . _write_log_header opening lv to write header + * Also, io to LVs should not go through bcache. + * bcache should contain only labels and metadata + * scanned from PVs. */ if (!dev) { + /* + * This case should only be used for new devices created by this + * command (opening LVs it's created), so if a dev exists for the + * dev_t referenced by the name, then drop all aliases for before + * _insert_dev adds the new name. lvm commands actually hit this + * fairly often when it uses some LV, deactivates the LV, then + * creates some new LV which ends up with the same major:minor. + * Without dropping the aliases, it's plausible that lvm commands + * could end up using the wrong dm device. + */ + struct device *dev_by_devt = (struct device *) btree_lookup(_cache.devices, (uint32_t) st.st_rdev); + if (dev_by_devt) { + log_debug("Dropping aliases for %d:%d before adding new path %s.", + (int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name); + _drop_all_aliases(dev_by_devt); + } + +#if 0 + /* + * I think only lvm's own dm devs should be added here, so use + * a warning to look for any other unknown cases. + */ + if (MAJOR(st.st_rdev) != cmd->dev_types->device_mapper_major) { + log_warn("WARNING: new device appeared %d:%d %s", + (int)MAJOR(st.st_rdev), (int)(MINOR(st.st_rdev)), name); + } +#endif + if (!_insert_dev(name, st.st_rdev)) return_NULL; @@ -1544,10 +1594,9 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d log_error("Failed to get device %s", name); return NULL; } - - _verify_aliases(dev, name); } + out: /* * The caller passed a filter if they only want the dev if it * passes filters. @@ -1577,63 +1626,23 @@ struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct d return dev; } -struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t dev, struct dev_filter *f, int *filtered) +struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f) { - char path[PATH_MAX]; - const char *sysfs_dir; - struct stat info; - struct device *d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev); - int ret; - - if (filtered) - *filtered = 0; - - if (!d) { - sysfs_dir = dm_sysfs_dir(); - if (sysfs_dir && *sysfs_dir) { - /* First check if dev is sysfs to avoid useless scan */ - if (dm_snprintf(path, sizeof(path), "%sdev/block/%d:%d", - sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev)) < 0) { - log_error("dm_snprintf partition failed."); - return NULL; - } - - if (lstat(path, &info)) { - log_debug("No sysfs entry for %d:%d errno %d at %s.", - (int)MAJOR(dev), (int)MINOR(dev), errno, path); - return NULL; - } - } - - log_debug_devs("Device num not found in dev_cache repeat dev_cache_scan for %d:%d", - (int)MAJOR(dev), (int)MINOR(dev)); - dev_cache_scan(cmd); - d = (struct device *) btree_lookup(_cache.devices, (uint32_t) dev); - - if (!d) - return NULL; - } - - if (d->flags & DEV_REGULAR) - return d; - - if (!f) - return d; - - ret = f->passes_filter(cmd, f, d, NULL); - - if (ret == -EAGAIN) { - log_debug_devs("get device by number defer filter %s", dev_name(d)); - d->flags |= DEV_FILTER_AFTER_SCAN; - ret = 1; - } + return _dev_cache_get(cmd, name, f, 1); +} - if (ret) - return d; +struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f) +{ + return _dev_cache_get(cmd, name, f, 0); +} - if (filtered) - *filtered = 1; +struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt) +{ + struct device *dev = (struct device *) btree_lookup(_cache.devices, (uint32_t) devt); + if (dev) + return dev; + log_debug_devs("No devno %d:%d in dev cache.", (int)MAJOR(devt), (int)MINOR(devt)); return NULL; } @@ -1703,8 +1712,10 @@ int dev_fd(struct device *dev) const char *dev_name(const struct device *dev) { - return (dev && dev->aliases.n) ? dm_list_item(dev->aliases.n, struct dm_str_list)->str : - unknown_device_name(); + if (dev && dev->aliases.n && !dm_list_empty(&dev->aliases)) + return dm_list_item(dev->aliases.n, struct dm_str_list)->str; + else + return unknown_device_name(); } bool dev_cache_has_md_with_end_superblock(struct dev_types *dt) diff --git a/lib/device/dev-cache.h b/lib/device/dev-cache.h index 449bfeb75..622335982 100644 --- a/lib/device/dev-cache.h +++ b/lib/device/dev-cache.h @@ -53,8 +53,8 @@ int dev_cache_has_scanned(void); int dev_cache_add_dir(const char *path); struct device *dev_cache_get(struct cmd_context *cmd, const char *name, struct dev_filter *f); - -struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t device, struct dev_filter *f, int *filtered); +struct device *dev_cache_get_existing(struct cmd_context *cmd, const char *name, struct dev_filter *f); +struct device *dev_cache_get_by_devt(struct cmd_context *cmd, dev_t devt); struct device *dev_hash_get(const char *name); diff --git a/lib/device/dev-io.c b/lib/device/dev-io.c index b4f1930b1..811ad8978 100644 --- a/lib/device/dev-io.c +++ b/lib/device/dev-io.c @@ -58,6 +58,9 @@ static int _dev_get_size_file(struct device *dev, uint64_t *size) const char *name = dev_name(dev); struct stat info; + if (dm_list_empty(&dev->aliases)) + return_0; + if (dev->size_seqno == _dev_size_seqno) { log_very_verbose("%s: using cached size %" PRIu64 " sectors", name, dev->size); @@ -87,7 +90,7 @@ static int _dev_get_size_dev(struct device *dev, uint64_t *size) int do_close = 0; if (dm_list_empty(&dev->aliases)) - return 0; + return_0; if (dev->size_seqno == _dev_size_seqno) { log_very_verbose("%s: using cached size %" PRIu64 " sectors", @@ -305,6 +308,13 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) if ((flags & O_EXCL)) need_excl = 1; + if (dm_list_empty(&dev->aliases)) { + /* shouldn't happen */ + log_print("Cannot open device %d:%d with no valid paths.", (int)MAJOR(dev->dev), (int)MINOR(dev->dev)); + return 0; + } + name = dev_name(dev); + if (dev->fd >= 0) { if (((dev->flags & DEV_OPENED_RW) || !need_rw) && ((dev->flags & DEV_OPENED_EXCL) || !need_excl)) { @@ -314,7 +324,7 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) if (dev->open_count && !need_excl) log_debug_devs("%s: Already opened read-only. Upgrading " - "to read-write.", dev_name(dev)); + "to read-write.", name); /* dev_close_immediate will decrement this */ dev->open_count++; @@ -327,11 +337,7 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) if (critical_section()) /* FIXME Make this log_error */ - log_verbose("dev_open(%s) called while suspended", - dev_name(dev)); - - if (!(name = dev_name_confirmed(dev, quiet))) - return_0; + log_verbose("dev_open(%s) called while suspended", name); #ifdef O_DIRECT_SUPPORT if (direct) { @@ -372,9 +378,9 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) } #endif if (quiet) - log_sys_debug("open", name); + log_debug("Failed to open device path %s (%d).", name, errno); else - log_sys_error("open", name); + log_error("Failed to open device path %s (%d).", name, errno); dev->flags |= DEV_OPEN_FAILURE; return 0; @@ -415,10 +421,12 @@ int dev_open_flags(struct device *dev, int flags, int direct, int quiet) if ((flags & O_CREAT) && !(flags & O_TRUNC)) dev->end = lseek(dev->fd, (off_t) 0, SEEK_END); - log_debug_devs("Opened %s %s%s%s", dev_name(dev), - dev->flags & DEV_OPENED_RW ? "RW" : "RO", - dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "", - dev->flags & DEV_O_DIRECT ? " O_DIRECT" : ""); + if (!quiet) { + log_debug_devs("Opened %s %s%s%s", name, + dev->flags & DEV_OPENED_RW ? "RW" : "RO", + dev->flags & DEV_OPENED_EXCL ? " O_EXCL" : "", + dev->flags & DEV_O_DIRECT ? " O_DIRECT" : ""); + } dev->flags &= ~DEV_OPEN_FAILURE; return 1; diff --git a/lib/device/dev-type.c b/lib/device/dev-type.c index 0e77a009d..c67a86fa3 100644 --- a/lib/device/dev-type.c +++ b/lib/device/dev-type.c @@ -966,6 +966,9 @@ static int _wipe_known_signatures_with_blkid(struct device *dev, const char *nam /* TODO: Should we check for valid dev - _dev_is_valid(dev)? */ + if (dm_list_empty(&dev->aliases)) + goto_out; + if (!(probe = blkid_new_probe_from_filename(dev_name(dev)))) { log_error("Failed to create a new blkid probe for device %s.", dev_name(dev)); goto out; diff --git a/lib/device/device.h b/lib/device/device.h index 8c3a8c30e..572994bb9 100644 --- a/lib/device/device.h +++ b/lib/device/device.h @@ -204,9 +204,6 @@ struct device *dev_create_file(const char *filename, struct device *dev, struct dm_str_list *alias, int use_malloc); void dev_destroy_file(struct device *dev); -/* Return a valid device name from the alias list; NULL otherwise */ -const char *dev_name_confirmed(struct device *dev, int quiet); - int dev_mpath_init(const char *config_wwids_file); void dev_mpath_exit(void); diff --git a/lib/device/device_id.c b/lib/device/device_id.c index 003f10a96..7ce955b11 100644 --- a/lib/device/device_id.c +++ b/lib/device/device_id.c @@ -347,6 +347,8 @@ const char *device_id_system_read(struct cmd_context *cmd, struct device *dev, u } else if (idtype == DEV_ID_TYPE_DEVNAME) { + if (dm_list_empty(&dev->aliases)) + goto_bad; if (!(idname = strdup(dev_name(dev)))) goto_bad; return idname; @@ -955,6 +957,10 @@ int device_id_add(struct cmd_context *cmd, struct device *dev, const char *pvid_ if (!dev_get_partition_number(dev, &part)) return_0; + /* Ensure valid dev_name(dev) below. */ + if (dm_list_empty(&dev->aliases)) + return_0; + /* * When enable_devices_file=0 and pending_devices_file=1 we let * pvcreate/vgcreate add new du's to cmd->use_devices. These du's may @@ -1577,7 +1583,7 @@ void device_ids_match_device_list(struct cmd_context *cmd) dm_list_iterate_items(du, &cmd->use_devices) { if (du->dev) continue; - if (!(du->dev = dev_cache_get(cmd, du->devname, NULL))) { + if (!(du->dev = dev_cache_get_existing(cmd, du->devname, NULL))) { log_warn("Device not found for %s.", du->devname); } else { /* Should we set dev->id? Which idtype? Use --deviceidtype? */ @@ -1625,7 +1631,7 @@ void device_ids_match(struct cmd_context *cmd) * the du/dev pairs in preparation for using the filters. */ if (du->devname && - (dev = dev_cache_get(cmd, du->devname, NULL))) { + (dev = dev_cache_get_existing(cmd, du->devname, NULL))) { /* On successful match, du, dev, and id are linked. */ if (_match_du_to_dev(cmd, du, dev)) continue; @@ -1842,6 +1848,9 @@ void device_ids_validate(struct cmd_context *cmd, struct dm_list *scanned_devs, if (dev->flags & DEV_SCAN_NOT_READ) continue; + if (dm_list_empty(&dev->aliases)) + continue; + if (!cmd->filter->passes_filter(cmd, cmd->filter, dev, "persistent")) { log_warn("Devices file %s is excluded by filter: %s.", dev_name(dev), dev_filtered_reason(dev)); @@ -2225,14 +2234,14 @@ void device_ids_find_renamed_devs(struct cmd_context *cmd, struct dm_list *dev_l dm_list_iterate_items(dil, &search_pvids) { char *dup_devname1, *dup_devname2, *dup_devname3; - if (!dil->dev) { + if (!dil->dev || dm_list_empty(&dil->dev->aliases)) { not_found++; continue; } - found++; dev = dil->dev; devname = dev_name(dev); + found++; if (!(du = get_du_for_pvid(cmd, dil->pvid))) { /* shouldn't happen */ diff --git a/lib/label/hints.c b/lib/label/hints.c index 35ae7f5cc..edce6f517 100644 --- a/lib/label/hints.c +++ b/lib/label/hints.c @@ -500,6 +500,8 @@ int validate_hints(struct cmd_context *cmd, struct dm_list *hints) if (!(iter = dev_iter_create(NULL, 0))) return 0; while ((dev = dev_iter_get(cmd, iter))) { + if (dm_list_empty(&dev->aliases)) + continue; if (!(hint = _find_hint_name(hints, dev_name(dev)))) continue; diff --git a/lib/label/label.c b/lib/label/label.c index fe2bc8fec..ffb393891 100644 --- a/lib/label/label.c +++ b/lib/label/label.c @@ -1130,11 +1130,12 @@ int label_scan_vg_online(struct cmd_context *cmd, const char *vgname, * sure to find the device. */ if (try_dev_scan) { + log_debug("Repeat dev cache scan to translate devnos."); dev_cache_scan(cmd); dm_list_iterate_items(po, &pvs_online) { if (po->dev) continue; - if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno, NULL, NULL))) { + if (!(po->dev = dev_cache_get_by_devt(cmd, po->devno))) { log_error("No device found for %d:%d PVID %s", (int)MAJOR(po->devno), (int)MINOR(po->devno), po->pvid); goto bad; @@ -1722,7 +1723,7 @@ void label_scan_invalidate_lv(struct cmd_context *cmd, struct logical_volume *lv if (lv_info(cmd, lv, 0, &lvinfo, 0, 0) && lvinfo.exists) { /* FIXME: Still unclear what is it supposed to find */ devt = MKDEV(lvinfo.major, lvinfo.minor); - if ((dev = dev_cache_get_by_devt(cmd, devt, NULL, NULL))) + if ((dev = dev_cache_get_by_devt(cmd, devt))) label_scan_invalidate(dev); } } @@ -1736,13 +1737,19 @@ void label_scan_invalidate_lvs(struct cmd_context *cmd, struct dm_list *lvs) struct lv_list *lvl; dev_t devt; + /* + * FIXME: this is all unnecessary unless there are PVs stacked on LVs, + * so we can skip all of this if scan_lvs=0. + */ + log_debug("invalidating devs for any pvs on lvs"); + if (get_device_list(NULL, &devs, &devs_features)) { if (devs_features & DM_DEVICE_LIST_HAS_UUID) { dm_list_iterate_items(dm_dev, devs) if (dm_dev->uuid && strncmp(dm_dev->uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) == 0) { devt = MKDEV(dm_dev->major, dm_dev->minor); - if ((dev = dev_cache_get_by_devt(cmd, devt, NULL, NULL))) + if ((dev = dev_cache_get_by_devt(cmd, devt))) label_scan_invalidate(dev); } /* ATM no further caching for any lvconvert command @@ -1879,10 +1886,24 @@ int label_scan_open_rw(struct device *dev) int label_scan_reopen_rw(struct device *dev) { + const char *name; int flags = 0; int prev_fd = dev->bcache_fd; int fd; + if (dm_list_empty(&dev->aliases)) { + log_error("Cannot reopen rw device %d:%d with no valid paths di %d fd %d.", + (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev->bcache_di, dev->bcache_fd); + return 0; + } + + name = dev_name(dev); + if (!name || name[0] != '/') { + log_error("Cannot reopen rw device %d:%d with no valid name di %d fd %d.", + (int)MAJOR(dev->dev), (int)MINOR(dev->dev), dev->bcache_di, dev->bcache_fd); + return 0; + } + if (!(dev->flags & DEV_IN_BCACHE)) { if ((dev->bcache_fd != -1) || (dev->bcache_di != -1)) { /* shouldn't happen */ @@ -1912,7 +1933,7 @@ int label_scan_reopen_rw(struct device *dev) flags |= O_NOATIME; flags |= O_RDWR; - fd = open(dev_name(dev), flags, 0777); + fd = open(name, flags, 0777); if (fd < 0) { log_error("Failed to open rw %s errno %d di %d fd %d.", dev_name(dev), errno, dev->bcache_di, dev->bcache_fd); diff --git a/lib/locking/lvmlockd.c b/lib/locking/lvmlockd.c index b598df3d6..60c80f1b1 100644 --- a/lib/locking/lvmlockd.c +++ b/lib/locking/lvmlockd.c @@ -272,6 +272,8 @@ static void _lockd_retrive_vg_pv_list(struct volume_group *vg, i = 0; dm_list_iterate_items(pvl, &vg->pvs) { + if (!pvl->pv->dev || dm_list_empty(&pvl->pv->dev->aliases)) + continue; lock_pvs->path[i] = strdup(pv_dev_name(pvl->pv)); if (!lock_pvs->path[i]) { log_error("Fail to allocate PV path for VG %s", vg->name); @@ -341,6 +343,8 @@ static void _lockd_retrive_lv_pv_list(struct volume_group *vg, dm_list_iterate_items(pvl, &vg->pvs) { if (lv_is_on_pv(lv, pvl->pv)) { + if (!pvl->pv->dev || dm_list_empty(&pvl->pv->dev->aliases)) + continue; lock_pvs->path[i] = strdup(pv_dev_name(pvl->pv)); if (!lock_pvs->path[i]) { log_error("Fail to allocate PV path for LV %s/%s", diff --git a/lib/metadata/mirror.c b/lib/metadata/mirror.c index e2bf191a1..46da57948 100644 --- a/lib/metadata/mirror.c +++ b/lib/metadata/mirror.c @@ -1231,14 +1231,23 @@ int remove_mirrors_from_segments(struct logical_volume *lv, const char *get_pvmove_pvname_from_lv_mirr(const struct logical_volume *lv_mirr) { struct lv_segment *seg; + struct device *dev; dm_list_iterate_items(seg, &lv_mirr->segments) { if (!seg_is_mirrored(seg)) continue; - if (seg_type(seg, 0) == AREA_PV) - return dev_name(seg_dev(seg, 0)); - if (seg_type(seg, 0) == AREA_LV) - return dev_name(seg_dev(first_seg(seg_lv(seg, 0)), 0)); + if (seg_type(seg, 0) == AREA_PV) { + dev = seg_dev(seg, 0); + if (!dev || dm_list_empty(&dev->aliases)) + return NULL; + return dev_name(dev); + } + if (seg_type(seg, 0) == AREA_LV) { + dev = seg_dev(first_seg(seg_lv(seg, 0)), 0); + if (!dev || dm_list_empty(&dev->aliases)) + return NULL; + return dev_name(dev); + } } return NULL; diff --git a/lib/metadata/pv_list.c b/lib/metadata/pv_list.c index 813e8e525..fc3667db0 100644 --- a/lib/metadata/pv_list.c +++ b/lib/metadata/pv_list.c @@ -152,6 +152,11 @@ static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl, struct pv_list *new_pvl = NULL, *pvl2; struct dm_list *pe_ranges; + if (!pvl->pv->dev || dm_list_empty(&pvl->pv->dev->aliases)) { + log_error("Failed to create PV entry for missing device."); + return 0; + } + pvname = pv_dev_name(pvl->pv); if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) { log_warn("WARNING: Physical volume %s not allocatable.", pvname); diff --git a/lib/metadata/vg.c b/lib/metadata/vg.c index 85482552a..adc954bab 100644 --- a/lib/metadata/vg.c +++ b/lib/metadata/vg.c @@ -679,6 +679,11 @@ int vgreduce_single(struct cmd_context *cmd, struct volume_group *vg, return r; } + if (!pv->dev || dm_list_empty(&pv->dev->aliases)) { + log_error("No device found for PV."); + return r; + } + log_debug("vgreduce_single VG %s PV %s", vg->name, pv_dev_name(pv)); if (pv_pe_alloc_count(pv)) { diff --git a/test/shell/losetup-partscan.sh b/test/shell/losetup-partscan.sh index 99f552ad1..670568945 100644 --- a/test/shell/losetup-partscan.sh +++ b/test/shell/losetup-partscan.sh @@ -33,6 +33,8 @@ aux udev_wait ls -la "${LOOP}"* test -e "${LOOP}p1" +aux lvmconf 'devices/scan = "/dev"' + aux extend_filter "a|$LOOP|" aux extend_devices "$LOOP" diff --git a/tools/toollib.c b/tools/toollib.c index b08c044fa..897adec34 100644 --- a/tools/toollib.c +++ b/tools/toollib.c @@ -1488,7 +1488,7 @@ int process_each_label(struct cmd_context *cmd, int argc, char **argv, goto out; } - if (!(dev = dev_cache_get(cmd, argv[opt], cmd->filter))) { + if (!(dev = dev_cache_get_existing(cmd, argv[opt], cmd->filter))) { log_error("Failed to find device " "\"%s\".", argv[opt]); ret_max = ECMD_FAILED; @@ -3925,7 +3925,7 @@ static int _get_arg_devices(struct cmd_context *cmd, return ECMD_FAILED; } - if (!(dil->dev = dev_cache_get(cmd, sl->str, cmd->filter))) { + if (!(dil->dev = dev_cache_get_existing(cmd, sl->str, cmd->filter))) { log_error("Cannot use %s: %s", sl->str, devname_error_reason(sl->str)); ret_max = EINIT_FAILED; } else { @@ -5261,7 +5261,7 @@ int pvcreate_each_device(struct cmd_context *cmd, struct device *dev; /* No filter used here */ - if (!(dev = dev_cache_get(cmd, pd->name, NULL))) { + if (!(dev = dev_cache_get_existing(cmd, pd->name, NULL))) { log_error("No device found for %s.", pd->name); dm_list_del(&pd->list); dm_list_add(&pp->arg_fail, &pd->list); |