mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
b8779e706e
The udev_device_get_is_initialized is available since libudev version 165. Older versions are still used somewhere (e.g. RHEL6). So better check for this fn and use it only if it's available.
173 lines
3.9 KiB
C
173 lines
3.9 KiB
C
/*
|
|
* Copyright (C) 2014 Red Hat, Inc. All rights reserved.
|
|
*
|
|
* This file is part of LVM2.
|
|
*
|
|
* This copyrighted material is made available to anyone wishing to use,
|
|
* modify, copy, or redistribute it subject to the terms and conditions
|
|
* of the GNU Lesser General Public License v.2.1.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "lib.h"
|
|
#include "device.h"
|
|
|
|
#ifdef UDEV_SYNC_SUPPORT
|
|
#include <libudev.h>
|
|
#endif
|
|
|
|
struct ext_registry_item {
|
|
const char *name;
|
|
struct dev_ext *(* dev_ext_get) (struct device *dev);
|
|
int (*dev_ext_release) (struct device *dev);
|
|
};
|
|
|
|
#define EXT_REGISTER(id,name) [id] = { #name, &_dev_ext_get_ ## name, &_dev_ext_release_ ## name }
|
|
|
|
/*
|
|
* DEV_EXT_NONE
|
|
*/
|
|
static struct dev_ext *_dev_ext_get_none(struct device *dev)
|
|
{
|
|
dev->ext.handle = NULL;
|
|
return &dev->ext;
|
|
}
|
|
|
|
static int _dev_ext_release_none(struct device *dev)
|
|
{
|
|
dev->ext.handle = NULL;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* DEV_EXT_UDEV
|
|
*/
|
|
static struct dev_ext *_dev_ext_get_udev(struct device *dev)
|
|
{
|
|
#ifdef UDEV_SYNC_SUPPORT
|
|
struct udev *udev;
|
|
struct udev_device *udev_device;
|
|
|
|
if (dev->ext.handle)
|
|
return &dev->ext;
|
|
|
|
if (!(udev = udev_get_library_context()))
|
|
return_NULL;
|
|
|
|
if (!(udev_device = udev_device_new_from_devnum(udev, 'b', dev->dev)))
|
|
return_NULL;
|
|
|
|
#ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
|
|
if (!udev_device_get_is_initialized(udev_device)) {
|
|
/* Timeout or some other udev db inconsistency! */
|
|
log_error("Udev database has incomplete information about device %s.", dev_name(dev));
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
dev->ext.handle = (void *) udev_device;
|
|
return &dev->ext;
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
static int _dev_ext_release_udev(struct device *dev)
|
|
{
|
|
#ifdef UDEV_SYNC_SUPPORT
|
|
if (!dev->ext.handle)
|
|
return 1;
|
|
|
|
/* udev_device_unref can't fail - it has no return value */
|
|
udev_device_unref((struct udev_device *) dev->ext.handle);
|
|
dev->ext.handle = NULL;
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static struct ext_registry_item _ext_registry[DEV_EXT_NUM] = {
|
|
EXT_REGISTER(DEV_EXT_NONE, none),
|
|
EXT_REGISTER(DEV_EXT_UDEV, udev)
|
|
};
|
|
|
|
const char *dev_ext_name(struct device *dev)
|
|
{
|
|
return _ext_registry[dev->ext.src].name;
|
|
}
|
|
|
|
static const char *_ext_attached_msg = "External handle attached to device";
|
|
|
|
struct dev_ext *dev_ext_get(struct device *dev)
|
|
{
|
|
struct dev_ext *ext;
|
|
void *handle_ptr;
|
|
|
|
handle_ptr = dev->ext.handle;
|
|
|
|
if (!(ext = _ext_registry[dev->ext.src].dev_ext_get(dev)))
|
|
log_error("Failed to get external handle for device %s [%s].",
|
|
dev_name(dev), dev_ext_name(dev));
|
|
else if (handle_ptr != dev->ext.handle)
|
|
log_debug_devs("%s %s [%s:%p]", _ext_attached_msg, dev_name(dev),
|
|
dev_ext_name(dev), dev->ext.handle);
|
|
|
|
return ext;
|
|
}
|
|
|
|
int dev_ext_release(struct device *dev)
|
|
{
|
|
int r;
|
|
void *handle_ptr;
|
|
|
|
if (!dev->ext.enabled ||
|
|
!dev->ext.handle)
|
|
return 1;
|
|
|
|
handle_ptr = dev->ext.handle;
|
|
|
|
if (!(r = _ext_registry[dev->ext.src].dev_ext_release(dev)))
|
|
log_error("Failed to release external handle for device %s [%s:%p].",
|
|
dev_name(dev), dev_ext_name(dev), dev->ext.handle);
|
|
else
|
|
log_debug_devs("External handle detached from device %s [%s:%p]",
|
|
dev_name(dev), dev_ext_name(dev), handle_ptr);
|
|
|
|
return r;
|
|
}
|
|
|
|
int dev_ext_enable(struct device *dev, dev_ext_t src)
|
|
{
|
|
if (dev->ext.enabled && (dev->ext.src != src) && !dev_ext_release(dev)) {
|
|
log_error("Failed to enable external handle for device %s [%s].",
|
|
dev_name(dev), _ext_registry[src].name);
|
|
return 0;
|
|
}
|
|
|
|
dev->ext.src = src;
|
|
dev->ext.enabled = 1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int dev_ext_disable(struct device *dev)
|
|
{
|
|
if (!dev->ext.enabled)
|
|
return 1;
|
|
|
|
if (!dev_ext_release(dev)) {
|
|
log_error("Failed to disable external handle for device %s [%s].",
|
|
dev_name(dev), dev_ext_name(dev));
|
|
return 0;
|
|
}
|
|
|
|
dev->ext.enabled = 0;
|
|
dev->ext.src = DEV_EXT_NONE;
|
|
|
|
return 1;
|
|
}
|