2001-10-22 14:14:00 +00:00
/*
2008-01-30 14:00:02 +00:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-20 20:55:30 +00:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-10-22 14:14:00 +00:00
*
2004-03-30 19:35:44 +00:00
* 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
2007-08-20 20:55:30 +00:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 19:35:44 +00:00
*
2007-08-20 20:55:30 +00:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 19:35:44 +00:00
* along with this program ; if not , write to the Free Software Foundation ,
2016-01-21 11:49:46 +01:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-10-22 14:14:00 +00:00
*/
2018-06-08 13:40:53 +01:00
# include "base/memory/zalloc.h"
2024-06-02 22:50:11 +02:00
# include "base/data-struct/radix-tree.h"
2018-05-14 10:30:20 +01:00
# include "lib/misc/lib.h"
# include "lib/filters/filter.h"
# include "lib/config/config.h"
2001-10-22 14:14:00 +00:00
struct pfilter {
2024-06-02 22:50:11 +02:00
struct radix_tree * devices ;
2001-10-23 12:24:55 +00:00
struct dev_filter * real ;
2013-06-12 12:08:56 +02:00
struct dev_types * dt ;
2001-10-22 14:14:00 +00:00
} ;
2018-05-03 17:12:07 -05:00
/*
* The persistent filter is filter layer that sits above the other filters and
* caches the final result of those other filters . When a device is first
* checked against filters , it will not be in this cache , so this filter will
* pass the device down to the other filters to check it . The other filters
* will run and either include the device ( good / pass ) or exclude the device
* ( bad / fail ) . That good or bad result propagates up through this filter which
* saves the result . The next time some code checks the filters against the
* device , this persistent / cache filter is checked first . This filter finds
* the previous result in its cache and returns it without reevaluating the
* other real filters .
*
* FIXME : a cache like this should not be needed . The fact it ' s needed is a
* symptom of code that should be fixed to not reevaluate filters multiple
* times . A device should be checked against the filter once , and then not
* need to be checked again . With scanning now controlled , we could probably
* do this .
*/
2018-06-21 10:52:35 -05:00
static int _good_device ;
static int _bad_device ;
2001-10-22 14:14:00 +00:00
/*
2006-11-04 03:34:10 +00:00
* The hash table holds one of these two states
* against each entry .
2001-10-22 14:14:00 +00:00
*/
2018-06-21 10:52:35 -05:00
# define PF_BAD_DEVICE ((void *) &_good_device)
# define PF_GOOD_DEVICE ((void *) &_bad_device)
2001-10-22 14:14:00 +00:00
2001-10-22 14:39:12 +00:00
static int _init_hash ( struct pfilter * pf )
2001-10-22 14:14:00 +00:00
{
if ( pf - > devices )
2024-06-02 22:50:11 +02:00
radix_tree_destroy ( pf - > devices ) ;
2001-10-22 14:14:00 +00:00
2024-06-02 22:50:11 +02:00
if ( ! ( pf - > devices = radix_tree_create ( NULL , NULL ) ) )
2008-01-30 13:19:47 +00:00
return_0 ;
2003-01-08 16:41:22 +00:00
return 1 ;
2001-10-22 14:14:00 +00:00
}
2020-10-20 15:17:56 -05:00
static void _persistent_filter_wipe ( struct cmd_context * cmd , struct dev_filter * f , struct device * dev , const char * use_filter_name )
2001-10-22 14:14:00 +00:00
{
2001-10-23 12:24:55 +00:00
struct pfilter * pf = ( struct pfilter * ) f - > private ;
2020-10-20 15:17:56 -05:00
struct dm_str_list * sl ;
2001-10-22 14:14:00 +00:00
2020-10-20 15:17:56 -05:00
if ( ! dev ) {
2024-06-02 22:50:11 +02:00
_init_hash ( pf ) ;
2020-10-20 15:17:56 -05:00
} else {
dm_list_iterate_items ( sl , & dev - > aliases )
2024-06-02 22:50:11 +02:00
radix_tree_remove ( pf - > devices , sl - > str , strlen ( sl - > str ) ) ;
2020-10-20 15:17:56 -05:00
}
2001-10-23 12:24:55 +00:00
}
2001-10-22 14:14:00 +00:00
2018-12-07 14:35:22 -06:00
static int _lookup_p ( struct cmd_context * cmd , struct dev_filter * f , struct device * dev , const char * use_filter_name )
2001-10-22 14:14:00 +00:00
{
struct pfilter * pf = ( struct pfilter * ) f - > private ;
2018-05-29 17:02:27 -05:00
void * l ;
2014-05-29 09:41:03 +02:00
struct dm_str_list * sl ;
2018-05-03 17:12:07 -05:00
int pass = 1 ;
2024-06-02 22:50:11 +02:00
const char * devname = dev_name ( dev ) ;
2001-10-22 14:14:00 +00:00
2018-12-07 14:35:22 -06:00
if ( use_filter_name & & strcmp ( f - > name , use_filter_name ) )
return pf - > real - > passes_filter ( cmd , pf - > real , dev , use_filter_name ) ;
2018-05-29 17:02:27 -05:00
if ( dm_list_empty ( & dev - > aliases ) ) {
2024-05-28 16:17:53 +02:00
log_debug_devs ( " %u:%u: filter cache skipping (no name). " ,
MAJOR ( dev - > dev ) , MINOR ( dev - > dev ) ) ;
2018-05-29 17:02:27 -05:00
return 0 ;
}
2024-06-02 22:50:11 +02:00
l = radix_tree_lookup_ptr ( pf - > devices , devname , strlen ( devname ) ) ;
2018-05-29 17:02:27 -05:00
2018-05-03 17:12:07 -05:00
/* Cached bad, skip dev */
2010-07-02 02:09:57 +00:00
if ( l = = PF_BAD_DEVICE ) {
2024-06-02 22:50:11 +02:00
log_debug_devs ( " %s: filter cache skipping (cached bad). " , devname ) ;
2010-07-02 02:09:57 +00:00
return 0 ;
}
2018-05-03 17:12:07 -05:00
/* Cached good, use dev */
if ( l = = PF_GOOD_DEVICE ) {
2024-06-02 22:50:11 +02:00
log_debug_devs ( " %s: filter cache using (cached good). " , devname ) ;
2018-05-03 17:12:07 -05:00
return 1 ;
2010-07-02 02:09:57 +00:00
}
2018-05-03 17:12:07 -05:00
/* Uncached, check filters and cache the result */
2001-10-23 12:24:55 +00:00
if ( ! l ) {
2018-12-07 14:35:22 -06:00
pass = pf - > real - > passes_filter ( cmd , pf - > real , dev , use_filter_name ) ;
2018-05-03 17:12:07 -05:00
if ( ! pass ) {
/*
* A device that does not pass one filter is excluded
* even if the result of another filter is deferred ,
* because the deferred result won ' t change the exclude .
*/
l = PF_BAD_DEVICE ;
2022-04-01 15:06:03 -05:00
} else if ( pass = = 1 ) {
l = PF_GOOD_DEVICE ;
} else {
2024-06-02 22:50:11 +02:00
log_error ( " Ignore invalid filter result %d %s. " , pass , devname ) ;
2018-05-03 17:12:07 -05:00
pass = 1 ;
2022-04-01 15:06:03 -05:00
/* don't cache invalid result */
2018-05-03 17:12:07 -05:00
goto out ;
}
2021-10-14 18:16:49 +02:00
if ( ! dev - > filtered_flags ) /* skipping reason already logged by filter */
2024-06-02 22:50:11 +02:00
log_debug_devs ( " filter caching %s %s. " , pass ? " good " : " bad " , devname ) ;
2001-10-22 14:14:00 +00:00
2008-11-03 22:14:30 +00:00
dm_list_iterate_items ( sl , & dev - > aliases )
2024-06-02 22:50:11 +02:00
if ( ! radix_tree_insert_ptr ( pf - > devices , sl - > str , strlen ( sl - > str ) , l ) ) {
2012-02-28 11:12:58 +00:00
log_error ( " Failed to hash alias to filter. " ) ;
return 0 ;
}
2010-07-02 02:09:57 +00:00
}
2018-05-03 17:12:07 -05:00
out :
return pass ;
2001-10-22 14:14:00 +00:00
}
2006-04-19 15:33:07 +00:00
static void _persistent_destroy ( struct dev_filter * f )
2001-10-22 14:14:00 +00:00
{
struct pfilter * pf = ( struct pfilter * ) f - > private ;
2010-09-22 01:36:13 +00:00
if ( f - > use_count )
log_error ( INTERNAL_ERROR " Destroying persistent filter while in use %u times. " , f - > use_count ) ;
2024-06-02 22:50:11 +02:00
radix_tree_destroy ( pf - > devices ) ;
2001-10-23 12:24:55 +00:00
pf - > real - > destroy ( pf - > real ) ;
2018-06-08 13:40:53 +01:00
free ( pf ) ;
free ( f ) ;
2001-10-22 14:14:00 +00:00
}
2018-06-13 14:00:47 -05:00
struct dev_filter * persistent_filter_create ( struct dev_types * dt , struct dev_filter * real )
2001-10-22 14:14:00 +00:00
{
struct pfilter * pf ;
struct dev_filter * f = NULL ;
2018-06-08 13:40:53 +01:00
if ( ! ( pf = zalloc ( sizeof ( * pf ) ) ) ) {
2011-01-06 15:29:24 +00:00
log_error ( " Allocation of persistent filter failed. " ) ;
return NULL ;
}
2001-10-22 14:14:00 +00:00
2013-06-12 12:08:56 +02:00
pf - > dt = dt ;
2001-10-23 12:24:55 +00:00
pf - > real = real ;
2001-10-22 14:14:00 +00:00
if ( ! ( _init_hash ( pf ) ) ) {
2001-10-23 18:20:27 +00:00
log_error ( " Couldn't create hash table for persistent filter. " ) ;
2001-10-22 14:14:00 +00:00
goto bad ;
}
2018-06-08 13:40:53 +01:00
if ( ! ( f = zalloc ( sizeof ( * f ) ) ) ) {
2011-01-06 15:29:24 +00:00
log_error ( " Allocation of device filter for persistent filter failed. " ) ;
goto bad ;
}
2001-10-22 14:14:00 +00:00
2001-10-23 12:24:55 +00:00
f - > passes_filter = _lookup_p ;
2006-04-19 15:33:07 +00:00
f - > destroy = _persistent_destroy ;
2010-09-22 01:36:13 +00:00
f - > use_count = 0 ;
2001-10-22 14:14:00 +00:00
f - > private = pf ;
2012-08-13 19:44:10 +02:00
f - > wipe = _persistent_filter_wipe ;
2018-12-07 14:35:22 -06:00
f - > name = " persistent " ;
2001-10-22 14:14:00 +00:00
2013-08-13 23:26:58 +01:00
log_debug_devs ( " Persistent filter initialised. " ) ;
2001-10-22 14:14:00 +00:00
return f ;
2002-04-24 18:20:51 +00:00
bad :
2001-10-22 14:14:00 +00:00
if ( pf - > devices )
2024-06-02 22:50:11 +02:00
radix_tree_destroy ( pf - > devices ) ;
2018-06-08 13:40:53 +01:00
free ( pf ) ;
free ( f ) ;
2001-10-22 14:14:00 +00:00
return NULL ;
}