2014-09-23 14:49:01 +04: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-09-23 14:49:01 +04:00
*/
# include "lib.h"
# include "filter.h"
# include "activate.h" /* device_is_usable */
2015-01-29 16:24:06 +03:00
# ifdef UDEV_SYNC_SUPPORT
# include <libudev.h>
2015-01-29 18:44:34 +03:00
# include "dev-ext-udev-constants.h"
2015-01-29 16:24:06 +03:00
# endif
static const char * _too_small_to_hold_pv_msg = " Too small to hold a PV " ;
static int _native_check_pv_min_size ( struct device * dev )
{
uint64_t size ;
int ret = 0 ;
/* Check it's accessible */
if ( ! dev_open_readonly_quiet ( dev ) ) {
2015-09-03 15:19:48 +03:00
log_debug_devs ( " %s: Skipping: open failed " , dev_name ( dev ) ) ;
2015-01-29 16:24:06 +03:00
return 0 ;
}
/* Check it's not too small */
if ( ! dev_get_size ( dev , & size ) ) {
2015-09-03 15:19:48 +03:00
log_debug_devs ( " %s: Skipping: dev_get_size failed " , dev_name ( dev ) ) ;
2015-01-29 16:24:06 +03:00
goto out ;
}
if ( size < pv_min_size ( ) ) {
2015-09-03 15:19:48 +03:00
log_debug_devs ( " %s: Skipping: %s " , dev_name ( dev ) ,
_too_small_to_hold_pv_msg ) ;
2015-01-29 16:24:06 +03:00
goto out ;
}
ret = 1 ;
out :
if ( ! dev_close ( dev ) )
stack ;
return ret ;
}
# ifdef UDEV_SYNC_SUPPORT
static int _udev_check_pv_min_size ( struct device * dev )
{
struct dev_ext * ext ;
const char * size_str ;
char * endp ;
uint64_t size ;
if ( ! ( ext = dev_ext_get ( dev ) ) )
return_0 ;
2015-01-29 18:44:34 +03:00
if ( ! ( size_str = udev_device_get_sysattr_value ( ( struct udev_device * ) ext - > handle , DEV_EXT_UDEV_SYSFS_ATTR_SIZE ) ) ) {
2015-01-29 16:24:06 +03:00
log_debug_devs ( " %s: Skipping: failed to get size from sysfs [%s:%p] " ,
dev_name ( dev ) , dev_ext_name ( dev ) , dev - > ext . handle ) ;
return 0 ;
}
errno = 0 ;
size = strtoull ( size_str , & endp , 10 ) ;
if ( errno | | ! endp | | * endp ) {
log_debug_devs ( " %s: Skipping: failed to parse size from sysfs [%s:%p] " ,
dev_name ( dev ) , dev_ext_name ( dev ) , dev - > ext . handle ) ;
return 0 ;
}
if ( size < pv_min_size ( ) ) {
log_debug_devs ( " %s: Skipping: %s [%s:%p] " , dev_name ( dev ) ,
_too_small_to_hold_pv_msg ,
dev_ext_name ( dev ) , dev - > ext . handle ) ;
return 0 ;
}
return 1 ;
}
# else
static int _udev_check_pv_min_size ( struct device * dev )
{
return 1 ;
}
# endif
static int _check_pv_min_size ( struct device * dev )
{
if ( dev - > ext . src = = DEV_EXT_NONE )
return _native_check_pv_min_size ( dev ) ;
if ( dev - > ext . src = = DEV_EXT_UDEV )
return _udev_check_pv_min_size ( dev ) ;
log_error ( INTERNAL_ERROR " Missing hook for PV min size check "
" using external device info source %s " , dev_ext_name ( dev ) ) ;
return 0 ;
}
2014-09-23 14:49:01 +04:00
static int _passes_usable_filter ( struct dev_filter * f , struct device * dev )
{
filter_mode_t mode = * ( ( filter_mode_t * ) f - > private ) ;
2014-10-02 15:21:24 +04:00
struct dev_usable_check_params ucp = { 0 } ;
2015-09-02 17:08:30 +03:00
int r = 1 ;
2015-01-29 16:24:06 +03:00
/* further checks are done on dm devices only */
2015-09-02 17:08:30 +03:00
if ( dm_is_dm_major ( MAJOR ( dev - > dev ) ) ) {
switch ( mode ) {
2014-09-23 14:49:01 +04:00
case FILTER_MODE_NO_LVMETAD :
ucp . check_empty = 1 ;
ucp . check_blocked = 1 ;
ucp . check_suspended = ignore_suspended_devices ( ) ;
ucp . check_error_target = 1 ;
ucp . check_reserved = 1 ;
break ;
case FILTER_MODE_PRE_LVMETAD :
ucp . check_empty = 1 ;
2014-10-08 12:57:44 +04:00
ucp . check_blocked = 1 ;
2016-02-03 16:40:52 +03:00
ucp . check_suspended = 0 ;
2014-09-23 14:49:01 +04:00
ucp . check_error_target = 1 ;
ucp . check_reserved = 1 ;
break ;
case FILTER_MODE_POST_LVMETAD :
ucp . check_empty = 0 ;
ucp . check_blocked = 1 ;
ucp . check_suspended = ignore_suspended_devices ( ) ;
ucp . check_error_target = 0 ;
ucp . check_reserved = 0 ;
break ;
2015-09-02 17:08:30 +03:00
}
if ( ! ( r = device_is_usable ( dev , ucp ) ) )
log_debug_devs ( " %s: Skipping unusable device. " , dev_name ( dev ) ) ;
2014-09-23 14:49:01 +04:00
}
2015-09-02 17:08:30 +03:00
if ( r ) {
/* check if the device is not too small to hold a PV */
switch ( mode ) {
case FILTER_MODE_NO_LVMETAD :
/* fall through */
case FILTER_MODE_PRE_LVMETAD :
r = _check_pv_min_size ( dev ) ;
break ;
case FILTER_MODE_POST_LVMETAD :
/* nothing to do here */
break ;
}
}
2014-09-23 14:49:01 +04:00
return r ;
}
static void _usable_filter_destroy ( struct dev_filter * f )
{
if ( f - > use_count )
log_error ( INTERNAL_ERROR " Destroying usable device filter while in use %u times. " , f - > use_count ) ;
dm_free ( f - > private ) ;
dm_free ( f ) ;
}
struct dev_filter * usable_filter_create ( struct dev_types * dt __attribute__ ( ( unused ) ) , filter_mode_t mode )
{
struct dev_filter * f ;
if ( ! ( f = dm_zalloc ( sizeof ( struct dev_filter ) ) ) ) {
log_error ( " Usable device filter allocation failed " ) ;
return NULL ;
}
f - > passes_filter = _passes_usable_filter ;
f - > destroy = _usable_filter_destroy ;
f - > use_count = 0 ;
if ( ! ( f - > private = dm_zalloc ( sizeof ( filter_mode_t ) ) ) ) {
log_error ( " Usable device filter mode allocation failed " ) ;
2014-11-12 11:18:55 +03:00
dm_free ( f ) ;
2014-09-23 14:49:01 +04:00
return NULL ;
}
* ( ( filter_mode_t * ) f - > private ) = mode ;
log_debug_devs ( " Usable device filter initialised. " ) ;
return f ;
}