mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-02 01:18:26 +03:00
Fix the device cache to cope reasonably safely with device name changes.
This should be a rare occurrence so the aim is to recover if it's straightforward to do so, otherwise just to abort the operation. If people *knowingly* change device names, they should always run vgscan afterwards. A few bytes of memory gets leaked inside a pool each time an alias has to be discarded - it's not worth restructuring the code to reuse it. More of LVM2 needs updating to pass device objects (or uuids) about instead of pathnames so that resolution of pathname->object only happens once per operation. dev_cache_get() should now always return the *current* device at the path given dev_name_confirmed() replaces dev_name() whenever it's important to know that name for the device is still current (ie when opening it). If the cache doesn't know a current name, the function fails. dev_open() guarantees that the file descriptor returned is for the dev_t of the device structure it was passed.
This commit is contained in:
parent
7743c8685e
commit
b849de1d18
@ -19,6 +19,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <dirent.h>
|
||||
#include <linux/kdev_t.h>
|
||||
|
||||
/*
|
||||
* FIXME: really need to seperate names from the devices since
|
||||
@ -303,10 +304,56 @@ 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 */
|
||||
/* FIXME Make rest of code pass/cache struct device instead of dev_name */
|
||||
const char *dev_name_confirmed(struct device *dev)
|
||||
{
|
||||
struct stat buf;
|
||||
char *name;
|
||||
int r;
|
||||
|
||||
while ((r = stat(name = list_item(dev->aliases.n,
|
||||
struct str_list)->str, &buf)) ||
|
||||
(buf.st_rdev != dev->dev)) {
|
||||
if (r < 0)
|
||||
log_sys_error("stat", name);
|
||||
log_error("Path %s no longer valid for device(%d,%d)",
|
||||
name, (int) MAJOR(dev->dev), (int) MINOR(dev->dev));
|
||||
|
||||
/* Remove the incorrect hash entry */
|
||||
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 (list_size(&dev->aliases) > 1) {
|
||||
list_del(dev->aliases.n);
|
||||
if (!r)
|
||||
_insert(name, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_error("Aborting - please provide new pathname for what "
|
||||
"used to be %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dev_name(dev);
|
||||
}
|
||||
|
||||
|
||||
struct device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||
{
|
||||
struct stat buf;
|
||||
struct device *d = (struct device *) hash_lookup(_cache.names, name);
|
||||
|
||||
/* If the entry's wrong, remove it */
|
||||
if (d && (stat(name, &buf) || (buf.st_rdev != d->dev))) {
|
||||
hash_remove(_cache.names, name);
|
||||
d = NULL;
|
||||
}
|
||||
|
||||
if (!d) {
|
||||
_insert(name, 0);
|
||||
d = (struct device *) hash_lookup(_cache.names, name);
|
||||
@ -353,5 +400,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -65,7 +65,12 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
|
||||
int dev_open(struct device *dev, int flags)
|
||||
{
|
||||
struct stat buf;
|
||||
const char *name = dev_name(dev);
|
||||
const char *name = dev_name_confirmed(dev);
|
||||
|
||||
if (!name) {
|
||||
stack;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->fd >= 0) {
|
||||
log_error("Device '%s' has already been opened", name);
|
||||
|
@ -47,6 +47,8 @@ static inline const char *dev_name(struct device *dev) {
|
||||
return list_item(dev->aliases.n, struct str_list)->str;
|
||||
}
|
||||
|
||||
/* Return a valid device name from the alias list; NULL otherwise */
|
||||
const char *dev_name_confirmed(struct device *dev);
|
||||
|
||||
static inline int is_lvm_partition(const char *name) {
|
||||
return 1;
|
||||
|
Loading…
Reference in New Issue
Block a user