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
*/
2018-06-08 15:40:53 +03:00
# include "base/memory/zalloc.h"
2018-05-14 12:30:20 +03:00
# include "lib/misc/lib.h"
# include "lib/filters/filter.h"
# include "lib/activate/activate.h"
2015-01-29 16:24:06 +03:00
# ifdef UDEV_SYNC_SUPPORT
# include <libudev.h>
2018-05-14 12:30:20 +03:00
# include "lib/device/dev-ext-udev-constants.h"
2015-01-29 16:24:06 +03:00
# endif
2018-08-29 21:14:18 +03:00
struct filter_data {
filter_mode_t mode ;
int skip_lvs ;
} ;
2015-01-29 16:24:06 +03:00
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 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 :
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
2018-12-07 23:35:22 +03:00
static int _passes_usable_filter ( struct cmd_context * cmd , struct dev_filter * f , struct device * dev , const char * use_filter_name )
2014-09-23 14:49:01 +04:00
{
2018-08-29 21:14:18 +03:00
struct filter_data * data = f - > private ;
filter_mode_t mode = data - > mode ;
int skip_lvs = data - > skip_lvs ;
2014-10-02 15:21:24 +04:00
struct dev_usable_check_params ucp = { 0 } ;
2021-03-03 21:07:57 +03:00
int is_lv = 0 ;
2015-09-02 17:08:30 +03:00
int r = 1 ;
2015-01-29 16:24:06 +03:00
2020-07-20 20:48:36 +03:00
dev - > filtered_flags & = ~ DEV_FILTERED_MINSIZE ;
dev - > filtered_flags & = ~ DEV_FILTERED_UNUSABLE ;
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 ;
2018-08-29 21:14:18 +03:00
ucp . check_lv = skip_lvs ;
2014-09-23 14:49:01 +04:00
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 ;
2018-08-29 21:14:18 +03:00
ucp . check_lv = skip_lvs ;
2014-09-23 14:49:01 +04:00
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 ;
2018-08-29 21:14:18 +03:00
ucp . check_lv = skip_lvs ;
2014-09-23 14:49:01 +04:00
break ;
2015-09-02 17:08:30 +03:00
}
2021-03-03 21:07:57 +03:00
if ( ! ( r = device_is_usable ( dev , ucp , & is_lv ) ) ) {
if ( is_lv )
dev - > filtered_flags | = DEV_FILTERED_IS_LV ;
else
dev - > filtered_flags | = DEV_FILTERED_UNUSABLE ;
2015-09-02 17:08:30 +03:00
log_debug_devs ( " %s: Skipping unusable device. " , dev_name ( dev ) ) ;
2020-07-20 20:48:36 +03:00
}
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 ) ;
2020-07-20 20:48:36 +03:00
if ( ! r )
dev - > filtered_flags | = DEV_FILTERED_MINSIZE ;
2015-09-02 17:08:30 +03:00
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 ) ;
2018-06-08 15:40:53 +03:00
free ( f - > private ) ;
free ( f ) ;
2014-09-23 14:49:01 +04:00
}
2018-08-29 21:14:18 +03:00
struct dev_filter * usable_filter_create ( struct cmd_context * cmd , struct dev_types * dt __attribute__ ( ( unused ) ) , filter_mode_t mode )
2014-09-23 14:49:01 +04:00
{
2018-08-29 21:14:18 +03:00
struct filter_data * data ;
2014-09-23 14:49:01 +04:00
struct dev_filter * f ;
2018-06-08 15:40:53 +03:00
if ( ! ( f = zalloc ( sizeof ( struct dev_filter ) ) ) ) {
2014-09-23 14:49:01 +04:00
log_error ( " Usable device filter allocation failed " ) ;
return NULL ;
}
f - > passes_filter = _passes_usable_filter ;
f - > destroy = _usable_filter_destroy ;
f - > use_count = 0 ;
2018-12-07 23:35:22 +03:00
f - > name = " usable " ;
2018-08-29 21:14:18 +03:00
if ( ! ( data = zalloc ( sizeof ( struct filter_data ) ) ) ) {
2014-09-23 14:49:01 +04:00
log_error ( " Usable device filter mode allocation failed " ) ;
2018-06-08 15:40:53 +03:00
free ( f ) ;
2014-09-23 14:49:01 +04:00
return NULL ;
}
2018-08-29 21:14:18 +03:00
data - > mode = mode ;
data - > skip_lvs = ! find_config_tree_bool ( cmd , devices_scan_lvs_CFG , NULL ) ;
f - > private = data ;
log_debug_devs ( " Usable device filter initialised (scan_lvs %d). " , ! data - > skip_lvs ) ;
2014-09-23 14:49:01 +04:00
return f ;
}