2001-10-01 23:29:52 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2012-03-12 18:40:41 +04:00
* Copyright ( C ) 2004 - 2012 Red Hat , Inc . All rights reserved .
2001-10-01 23:29:52 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2001-10-01 23:29:52 +04:00
*
2004-03-30 23:35:44 +04:00
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2001-10-01 23:29:52 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2001-10-01 23:29:52 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-10-01 23:29:52 +04:00
# include "dev-cache.h"
# include "filter.h"
2002-01-16 02:34:13 +03:00
# include "lvm-string.h"
2002-12-03 19:20:38 +03:00
# include "config.h"
2004-12-21 20:54:52 +03:00
# include "metadata.h"
2007-01-26 00:22:30 +03:00
# include "activate.h"
2001-10-01 23:29:52 +04:00
2001-10-09 21:20:02 +04:00
# include <dirent.h>
# include <unistd.h>
2002-01-24 16:36:33 +03:00
# include <ctype.h>
2001-10-23 16:33:57 +04:00
# include <fcntl.h>
2003-04-15 17:21:38 +04:00
# include <limits.h>
2001-10-09 21:20:02 +04:00
2012-07-26 15:22:55 +04:00
# include "device-types.h"
2004-07-01 19:14:29 +04:00
# define NUMBER_OF_MAJORS 4096
2001-10-09 21:20:02 +04:00
2011-11-11 19:11:08 +04:00
# define PARTITION_SCSI_DEVICE (1 << 0)
static struct {
int max_partitions ; /* 0 means LVM won't use this major number. */
int flags ;
} _partitions [ NUMBER_OF_MAJORS ] ;
2004-11-23 14:44:04 +03:00
2002-01-24 16:36:33 +03:00
static int _md_major = - 1 ;
2009-08-19 19:34:33 +04:00
static int _blkext_major = - 1 ;
2009-10-27 20:00:44 +03:00
static int _drbd_major = - 1 ;
2007-01-26 00:22:30 +03:00
static int _device_mapper_major = - 1 ;
2012-01-12 00:38:42 +04:00
static int _emcpower_major = - 1 ;
2002-01-24 16:36:33 +03:00
2010-07-02 06:09:57 +04:00
int dm_major ( void )
{
return _device_mapper_major ;
}
2002-12-03 19:20:38 +03:00
int md_major ( void )
{
return _md_major ;
}
2009-08-19 19:34:33 +04:00
int blkext_major ( void )
{
return _blkext_major ;
}
2009-10-27 20:00:44 +03:00
int dev_subsystem_part_major ( const struct device * dev )
{
2010-08-11 16:14:23 +04:00
dev_t primary_dev ;
2009-10-27 20:00:44 +03:00
if ( MAJOR ( dev - > dev ) = = _md_major )
return 1 ;
if ( MAJOR ( dev - > dev ) = = _drbd_major )
return 1 ;
2012-01-12 00:38:42 +04:00
if ( MAJOR ( dev - > dev ) = = _emcpower_major )
return 1 ;
2010-08-11 16:14:23 +04:00
if ( ( MAJOR ( dev - > dev ) = = _blkext_major ) & &
( get_primary_dev ( sysfs_dir_path ( ) , dev , & primary_dev ) ) & &
( MAJOR ( primary_dev ) = = _md_major ) )
return 1 ;
2009-10-27 20:00:44 +03:00
return 0 ;
}
const char * dev_subsystem_name ( const struct device * dev )
{
if ( MAJOR ( dev - > dev ) = = _md_major )
return " MD " ;
if ( MAJOR ( dev - > dev ) = = _drbd_major )
return " DRBD " ;
2012-01-12 00:38:42 +04:00
if ( MAJOR ( dev - > dev ) = = _emcpower_major )
return " EMCPOWER " ;
2010-08-11 16:14:23 +04:00
if ( MAJOR ( dev - > dev ) = = _blkext_major )
return " BLKEXT " ;
2009-10-27 20:00:44 +03:00
return " " ;
}
2010-07-09 19:34:40 +04:00
static int _passes_lvm_type_device_filter ( struct dev_filter * f __attribute__ ( ( unused ) ) ,
2002-12-03 19:20:38 +03:00
struct device * dev )
2001-10-01 23:29:52 +04:00
{
2001-10-25 18:04:18 +04:00
const char * name = dev_name ( dev ) ;
2004-12-21 20:54:52 +03:00
int ret = 0 ;
uint64_t size ;
2001-10-23 16:33:57 +04:00
2001-10-09 21:20:02 +04:00
/* Is this a recognised device type? */
2011-11-11 19:11:08 +04:00
if ( ! _partitions [ MAJOR ( dev - > dev ) ] . max_partitions ) {
2003-01-08 19:41:22 +03:00
log_debug ( " %s: Skipping: Unrecognised LVM device type % "
PRIu64 , name , ( uint64_t ) MAJOR ( dev - > dev ) ) ;
2001-10-09 21:20:02 +04:00
return 0 ;
2003-01-08 19:41:22 +03:00
}
2001-10-23 16:33:57 +04:00
/* Check it's accessible */
2011-05-24 17:36:57 +04:00
if ( ! dev_open_readonly_quiet ( dev ) ) {
2004-11-23 14:44:04 +03:00
log_debug ( " %s: Skipping: open failed " , name ) ;
2001-10-23 16:33:57 +04:00
return 0 ;
}
2011-11-11 20:59:30 +04:00
2004-12-21 20:54:52 +03:00
/* Check it's not too small */
if ( ! dev_get_size ( dev , & size ) ) {
log_debug ( " %s: Skipping: dev_get_size failed " , name ) ;
goto out ;
}
2011-02-18 17:11:22 +03:00
if ( size < pv_min_size ( ) ) {
2004-12-21 20:54:52 +03:00
log_debug ( " %s: Skipping: Too small to hold a PV " , name ) ;
goto out ;
}
2004-11-23 14:44:04 +03:00
if ( is_partitioned_dev ( dev ) ) {
2004-12-21 20:54:52 +03:00
log_debug ( " %s: Skipping: Partition table signature found " ,
2004-11-23 14:44:04 +03:00
name ) ;
2004-12-21 20:54:52 +03:00
goto out ;
2004-11-23 14:44:04 +03:00
}
2001-10-23 16:33:57 +04:00
2004-12-21 20:54:52 +03:00
ret = 1 ;
out :
2012-02-28 14:11:35 +04:00
if ( ! dev_close ( dev ) )
stack ;
2001-10-23 16:33:57 +04:00
2004-11-23 14:44:04 +03:00
return ret ;
2001-10-01 23:29:52 +04:00
}
2011-08-30 18:55:15 +04:00
static int _scan_proc_dev ( const char * proc , const struct dm_config_node * cn )
2001-10-09 21:20:02 +04:00
{
char line [ 80 ] ;
2002-01-16 02:34:13 +03:00
char proc_devices [ PATH_MAX ] ;
FILE * pd = NULL ;
2001-10-09 21:20:02 +04:00
int i , j = 0 ;
int line_maj = 0 ;
int blocksection = 0 ;
2002-12-20 02:25:55 +03:00
size_t dev_len = 0 ;
2011-08-30 18:55:15 +04:00
const struct dm_config_value * cv ;
2010-12-20 16:12:55 +03:00
const char * name ;
2012-03-20 14:47:02 +04:00
char * nl ;
2004-12-10 19:01:35 +03:00
2003-04-15 17:21:38 +04:00
if ( ! * proc ) {
log_verbose ( " No proc filesystem found: using all block device "
" types " ) ;
for ( i = 0 ; i < NUMBER_OF_MAJORS ; i + + )
2011-11-11 19:11:08 +04:00
_partitions [ i ] . max_partitions = 1 ;
2004-11-23 14:44:04 +03:00
return 1 ;
2003-04-15 17:21:38 +04:00
}
2004-12-10 19:01:35 +03:00
/* All types unrecognised initially */
2011-11-11 19:11:08 +04:00
memset ( _partitions , 0 , sizeof ( _partitions ) ) ;
2004-11-23 14:44:04 +03:00
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( proc_devices , sizeof ( proc_devices ) ,
2002-01-16 02:34:13 +03:00
" %s/devices " , proc ) < 0 ) {
log_error ( " Failed to create /proc/devices string " ) ;
2004-11-23 14:44:04 +03:00
return 0 ;
2002-01-16 02:34:13 +03:00
}
if ( ! ( pd = fopen ( proc_devices , " r " ) ) ) {
log_sys_error ( " fopen " , proc_devices ) ;
2004-11-23 14:44:04 +03:00
return 0 ;
2001-10-09 21:20:02 +04:00
}
2012-03-12 18:40:41 +04:00
while ( fgets ( line , sizeof ( line ) , pd ) ! = NULL ) {
2001-10-09 21:20:02 +04:00
i = 0 ;
2012-02-13 14:45:26 +04:00
while ( line [ i ] = = ' ' )
2001-10-09 21:20:02 +04:00
i + + ;
/* If it's not a number it may be name of section */
line_maj = atoi ( ( ( char * ) ( line + i ) ) ) ;
2012-03-20 14:47:02 +04:00
if ( line_maj < 0 | | line_maj > = NUMBER_OF_MAJORS ) {
/*
* Device numbers shown in / proc / devices are actually direct
* numbers passed to registering function , however the kernel
* uses only 12 bits , so use just 12 bits for major .
*/
if ( ( nl = strchr ( line , ' \n ' ) ) ) * nl = ' \0 ' ;
log_warn ( " WARNING: /proc/devices line: %s, replacing major with %d. " ,
line , line_maj & ( NUMBER_OF_MAJORS - 1 ) ) ;
line_maj & = ( NUMBER_OF_MAJORS - 1 ) ;
}
if ( ! line_maj ) {
2001-10-09 21:20:02 +04:00
blocksection = ( line [ i ] = = ' B ' ) ? 1 : 0 ;
continue ;
}
/* We only want block devices ... */
if ( ! blocksection )
continue ;
/* Find the start of the device major name */
while ( line [ i ] ! = ' ' & & line [ i ] ! = ' \0 ' )
i + + ;
2012-02-13 14:45:26 +04:00
while ( line [ i ] = = ' ' )
2001-10-09 21:20:02 +04:00
i + + ;
2002-01-24 16:36:33 +03:00
/* Look for md device */
if ( ! strncmp ( " md " , line + i , 2 ) & & isspace ( * ( line + i + 2 ) ) )
_md_major = line_maj ;
2009-08-19 19:34:33 +04:00
/* Look for blkext device */
if ( ! strncmp ( " blkext " , line + i , 6 ) & & isspace ( * ( line + i + 6 ) ) )
_blkext_major = line_maj ;
2009-10-27 20:00:44 +03:00
/* Look for drbd device */
if ( ! strncmp ( " drbd " , line + i , 4 ) & & isspace ( * ( line + i + 4 ) ) )
_drbd_major = line_maj ;
2012-01-12 00:38:42 +04:00
/* Look for EMC powerpath */
if ( ! strncmp ( " emcpower " , line + i , 8 ) & & isspace ( * ( line + i + 8 ) ) )
_emcpower_major = line_maj ;
2007-01-26 00:22:30 +03:00
/* Look for device-mapper device */
/* FIXME Cope with multiple majors */
if ( ! strncmp ( " device-mapper " , line + i , 13 ) & & isspace ( * ( line + i + 13 ) ) )
_device_mapper_major = line_maj ;
2011-11-11 19:11:08 +04:00
/* Major is SCSI device */
if ( ! strncmp ( " sd " , line + i , 2 ) & & isspace ( * ( line + i + 2 ) ) )
_partitions [ line_maj ] . flags | = PARTITION_SCSI_DEVICE ;
2001-10-09 21:20:02 +04:00
/* Go through the valid device names and if there is a
2002-04-24 22:20:51 +04:00
match store max number of partitions */
2012-03-12 18:40:41 +04:00
for ( j = 0 ; _device_info [ j ] . name [ 0 ] ; j + + ) {
dev_len = strlen ( _device_info [ j ] . name ) ;
2002-12-03 19:20:38 +03:00
if ( dev_len < = strlen ( line + i ) & &
2012-03-12 18:40:41 +04:00
! strncmp ( _device_info [ j ] . name , line + i , dev_len ) & &
2002-12-03 19:20:38 +03:00
( line_maj < NUMBER_OF_MAJORS ) ) {
2011-11-11 19:11:08 +04:00
_partitions [ line_maj ] . max_partitions =
2012-03-12 18:40:41 +04:00
_device_info [ j ] . max_partitions ;
2002-12-03 19:20:38 +03:00
break ;
}
}
2004-12-10 19:01:35 +03:00
if ( ! cn )
2002-12-03 19:20:38 +03:00
continue ;
/* Check devices/types for local variations */
for ( cv = cn - > v ; cv ; cv = cv - > next ) {
2011-08-30 18:55:15 +04:00
if ( cv - > type ! = DM_CFG_STRING ) {
2002-12-03 19:20:38 +03:00
log_error ( " Expecting string in devices/types "
" in config file " ) ;
2007-01-25 17:37:48 +03:00
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
2004-11-23 14:44:04 +03:00
return 0 ;
2002-12-03 19:20:38 +03:00
}
dev_len = strlen ( cv - > v . str ) ;
name = cv - > v . str ;
cv = cv - > next ;
2011-08-30 18:55:15 +04:00
if ( ! cv | | cv - > type ! = DM_CFG_INT ) {
2002-12-03 19:20:38 +03:00
log_error ( " Max partition count missing for %s "
" in devices/types in config file " ,
name ) ;
2007-01-25 17:37:48 +03:00
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
2004-11-23 14:44:04 +03:00
return 0 ;
2002-12-03 19:20:38 +03:00
}
if ( ! cv - > v . i ) {
log_error ( " Zero partition count invalid for "
" %s in devices/types in config file " ,
name ) ;
2007-01-25 17:37:48 +03:00
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
2004-11-23 14:44:04 +03:00
return 0 ;
2002-12-03 19:20:38 +03:00
}
if ( dev_len < = strlen ( line + i ) & &
! strncmp ( name , line + i , dev_len ) & &
( line_maj < NUMBER_OF_MAJORS ) ) {
2011-11-11 19:11:08 +04:00
_partitions [ line_maj ] . max_partitions = cv - > v . i ;
2001-10-09 21:20:02 +04:00
break ;
}
}
}
2007-01-25 17:37:48 +03:00
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
2004-11-23 14:44:04 +03:00
return 1 ;
}
int max_partitions ( int major )
{
2011-11-11 20:59:30 +04:00
if ( major > = NUMBER_OF_MAJORS )
2011-11-11 19:11:08 +04:00
return 0 ;
return _partitions [ major ] . max_partitions ;
}
int major_is_scsi_device ( int major )
{
2011-11-11 20:59:30 +04:00
if ( major > = NUMBER_OF_MAJORS )
2011-11-11 19:11:08 +04:00
return 0 ;
return ( _partitions [ major ] . flags & PARTITION_SCSI_DEVICE ) ? 1 : 0 ;
2001-10-09 21:20:02 +04:00
}
2002-12-03 19:20:38 +03:00
2012-03-12 18:40:41 +04:00
static void _lvm_type_filter_destroy ( struct dev_filter * f )
{
if ( f - > use_count )
log_error ( INTERNAL_ERROR " Destroying lvm_type filter while in use %u times. " , f - > use_count ) ;
dm_free ( f ) ;
}
2002-12-03 19:20:38 +03:00
struct dev_filter * lvm_type_filter_create ( const char * proc ,
2011-08-30 18:55:15 +04:00
const struct dm_config_node * cn )
2002-12-03 19:20:38 +03:00
{
struct dev_filter * f ;
2012-08-18 20:59:07 +04:00
if ( ! ( f = dm_zalloc ( sizeof ( struct dev_filter ) ) ) ) {
2002-12-03 19:20:38 +03:00
log_error ( " LVM type filter allocation failed " ) ;
return NULL ;
}
f - > passes_filter = _passes_lvm_type_device_filter ;
2012-03-12 18:40:41 +04:00
f - > destroy = _lvm_type_filter_destroy ;
2010-09-22 05:36:13 +04:00
f - > use_count = 0 ;
2004-11-23 14:44:04 +03:00
f - > private = NULL ;
2002-12-03 19:20:38 +03:00
2004-11-23 14:44:04 +03:00
if ( ! _scan_proc_dev ( proc , cn ) ) {
2006-05-10 01:23:51 +04:00
dm_free ( f ) ;
2008-01-30 16:19:47 +03:00
return_NULL ;
2003-01-08 19:41:22 +03:00
}
2002-12-03 19:20:38 +03:00
return f ;
}