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 <unistd.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <linux/kdev_t.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: really need to seperate names from the devices since
|
* FIXME: really need to seperate names from the devices since
|
||||||
@ -303,10 +304,56 @@ int dev_cache_add_dir(const char *path)
|
|||||||
return 1;
|
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 device *dev_cache_get(const char *name, struct dev_filter *f)
|
||||||
{
|
{
|
||||||
|
struct stat buf;
|
||||||
struct device *d = (struct device *) hash_lookup(_cache.names, name);
|
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) {
|
if (!d) {
|
||||||
_insert(name, 0);
|
_insert(name, 0);
|
||||||
d = (struct device *) hash_lookup(_cache.names, name);
|
d = (struct device *) hash_lookup(_cache.names, name);
|
||||||
@ -353,5 +400,3 @@ struct device *dev_iter_get(struct dev_iter *iter)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,12 @@ int dev_get_sectsize(struct device *dev, uint32_t *size)
|
|||||||
int dev_open(struct device *dev, int flags)
|
int dev_open(struct device *dev, int flags)
|
||||||
{
|
{
|
||||||
struct stat buf;
|
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) {
|
if (dev->fd >= 0) {
|
||||||
log_error("Device '%s' has already been opened", name);
|
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 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) {
|
static inline int is_lvm_partition(const char *name) {
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user