2014-12-12 14:55:41 +03:00
/*
* 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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2014-12-12 14:55:41 +03:00
*/
# 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 ;
2015-11-11 17:15:34 +03:00
# ifdef HAVE_LIBUDEV_UDEV_DEVICE_GET_IS_INITIALIZED
2015-11-11 15:13:54 +03:00
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 ;
}
2015-11-11 17:15:34 +03:00
# endif
2015-11-11 15:13:54 +03:00
2014-12-12 14:55:41 +03:00
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 ;
}