2001-09-25 16:49:28 +04:00
/*
2013-06-12 14:08:56 +04:00
* Copyright ( C ) 2013 Red Hat , Inc . All rights reserved .
2001-09-25 16:49:28 +04:00
*
2004-03-30 23:35:44 +04:00
* This file is part of LVM2 .
2001-09-25 16:49:28 +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-09-25 16:49:28 +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-09-25 16:49:28 +04:00
*/
2004-11-23 14:44:04 +03:00
# include "lib.h"
2013-06-12 14:08:56 +04:00
# include "dev-type.h"
2004-11-28 01:07:41 +03:00
# include "xlate.h"
2013-06-12 14:08:56 +04:00
# include "config.h"
# include "metadata.h"
2004-11-23 14:44:04 +03:00
2013-06-12 14:08:56 +04:00
# include <libgen.h>
# include <ctype.h>
2010-12-15 15:49:55 +03:00
2013-06-12 14:08:56 +04:00
# include "device-types.h"
struct dev_types * create_dev_types ( const char * proc_dir ,
const struct dm_config_node * cn )
{
struct dev_types * dt ;
char line [ 80 ] ;
char proc_devices [ PATH_MAX ] ;
FILE * pd = NULL ;
int i , j = 0 ;
int line_maj = 0 ;
int blocksection = 0 ;
size_t dev_len = 0 ;
const struct dm_config_value * cv ;
const char * name ;
char * nl ;
if ( ! ( dt = dm_zalloc ( sizeof ( struct dev_types ) ) ) ) {
log_error ( " Failed to allocate device type register. " ) ;
return NULL ;
}
if ( ! * proc_dir ) {
log_verbose ( " No proc filesystem found: using all block device types " ) ;
for ( i = 0 ; i < NUMBER_OF_MAJORS ; i + + )
dt - > dev_type_array [ i ] . max_partitions = 1 ;
return dt ;
}
if ( dm_snprintf ( proc_devices , sizeof ( proc_devices ) ,
" %s/devices " , proc_dir ) < 0 ) {
log_error ( " Failed to create /proc/devices string " ) ;
goto bad ;
}
if ( ! ( pd = fopen ( proc_devices , " r " ) ) ) {
log_sys_error ( " fopen " , proc_devices ) ;
goto bad ;
}
while ( fgets ( line , sizeof ( line ) , pd ) ! = NULL ) {
i = 0 ;
while ( line [ i ] = = ' ' )
i + + ;
/* If it's not a number it may be name of section */
line_maj = atoi ( ( ( char * ) ( line + i ) ) ) ;
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 ) {
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 + + ;
while ( line [ i ] = = ' ' )
i + + ;
/* Look for md device */
if ( ! strncmp ( " md " , line + i , 2 ) & & isspace ( * ( line + i + 2 ) ) )
dt - > md_major = line_maj ;
/* Look for blkext device */
if ( ! strncmp ( " blkext " , line + i , 6 ) & & isspace ( * ( line + i + 6 ) ) )
dt - > blkext_major = line_maj ;
/* Look for drbd device */
if ( ! strncmp ( " drbd " , line + i , 4 ) & & isspace ( * ( line + i + 4 ) ) )
dt - > drbd_major = line_maj ;
/* Look for EMC powerpath */
if ( ! strncmp ( " emcpower " , line + i , 8 ) & & isspace ( * ( line + i + 8 ) ) )
dt - > emcpower_major = line_maj ;
if ( ! strncmp ( " power2 " , line + i , 6 ) & & isspace ( * ( line + i + 6 ) ) )
dt - > power2_major = line_maj ;
/* Look for device-mapper device */
/* FIXME Cope with multiple majors */
if ( ! strncmp ( " device-mapper " , line + i , 13 ) & & isspace ( * ( line + i + 13 ) ) )
dt - > device_mapper_major = line_maj ;
/* Major is SCSI device */
if ( ! strncmp ( " sd " , line + i , 2 ) & & isspace ( * ( line + i + 2 ) ) )
dt - > dev_type_array [ line_maj ] . flags | = PARTITION_SCSI_DEVICE ;
/* Go through the valid device names and if there is a
match store max number of partitions */
for ( j = 0 ; _dev_known_types [ j ] . name [ 0 ] ; j + + ) {
dev_len = strlen ( _dev_known_types [ j ] . name ) ;
if ( dev_len < = strlen ( line + i ) & &
! strncmp ( _dev_known_types [ j ] . name , line + i , dev_len ) & &
( line_maj < NUMBER_OF_MAJORS ) ) {
dt - > dev_type_array [ line_maj ] . max_partitions =
_dev_known_types [ j ] . max_partitions ;
break ;
}
}
if ( ! cn )
continue ;
/* Check devices/types for local variations */
for ( cv = cn - > v ; cv ; cv = cv - > next ) {
if ( cv - > type ! = DM_CFG_STRING ) {
log_error ( " Expecting string in devices/types "
" in config file " ) ;
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
goto bad ;
}
dev_len = strlen ( cv - > v . str ) ;
name = cv - > v . str ;
cv = cv - > next ;
if ( ! cv | | cv - > type ! = DM_CFG_INT ) {
log_error ( " Max partition count missing for %s "
" in devices/types in config file " ,
name ) ;
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
goto bad ;
}
if ( ! cv - > v . i ) {
log_error ( " Zero partition count invalid for "
" %s in devices/types in config file " ,
name ) ;
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
goto bad ;
}
if ( dev_len < = strlen ( line + i ) & &
! strncmp ( name , line + i , dev_len ) & &
( line_maj < NUMBER_OF_MAJORS ) ) {
dt - > dev_type_array [ line_maj ] . max_partitions = cv - > v . i ;
break ;
}
}
}
if ( fclose ( pd ) )
log_sys_error ( " fclose " , proc_devices ) ;
return dt ;
bad :
dm_free ( dt ) ;
return NULL ;
}
int dev_subsystem_part_major ( struct dev_types * dt , struct device * dev )
{
dev_t primary_dev ;
if ( MAJOR ( dev - > dev ) = = dt - > device_mapper_major )
return 1 ;
if ( MAJOR ( dev - > dev ) = = dt - > drbd_major )
return 1 ;
if ( MAJOR ( dev - > dev ) = = dt - > emcpower_major )
return 1 ;
if ( MAJOR ( dev - > dev ) = = dt - > power2_major )
return 1 ;
2004-12-21 19:10:25 +03:00
2013-06-12 14:08:56 +04:00
if ( ( MAJOR ( dev - > dev ) = = dt - > blkext_major ) & &
2013-06-12 16:33:28 +04:00
dev_get_primary_dev ( dt , dev , & primary_dev ) & &
2013-06-12 14:08:56 +04:00
( MAJOR ( primary_dev ) = = dt - > md_major ) )
return 1 ;
return 0 ;
}
const char * dev_subsystem_name ( struct dev_types * dt , struct device * dev )
{
if ( MAJOR ( dev - > dev ) = = dt - > md_major )
return " MD " ;
if ( MAJOR ( dev - > dev ) = = dt - > drbd_major )
return " DRBD " ;
if ( MAJOR ( dev - > dev ) = = dt - > emcpower_major )
return " EMCPOWER " ;
if ( MAJOR ( dev - > dev ) = = dt - > power2_major )
return " POWER2 " ;
if ( MAJOR ( dev - > dev ) = = dt - > blkext_major )
return " BLKEXT " ;
return " " ;
}
int major_max_partitions ( struct dev_types * dt , int major )
{
if ( major > = NUMBER_OF_MAJORS )
return 0 ;
return dt - > dev_type_array [ major ] . max_partitions ;
}
int major_is_scsi_device ( struct dev_types * dt , int major )
{
if ( major > = NUMBER_OF_MAJORS )
return 0 ;
return ( dt - > dev_type_array [ major ] . flags & PARTITION_SCSI_DEVICE ) ? 1 : 0 ;
}
/* See linux/genhd.h and fs/partitions/msdos */
2004-11-23 14:44:04 +03:00
# define PART_MAGIC 0xAA55
2004-12-21 19:10:25 +03:00
# define PART_MAGIC_OFFSET UINT64_C(0x1FE)
# define PART_OFFSET UINT64_C(0x1BE)
struct partition {
2008-01-30 17:00:02 +03:00
uint8_t boot_ind ;
uint8_t head ;
uint8_t sector ;
uint8_t cyl ;
uint8_t sys_ind ; /* partition type */
uint8_t end_head ;
uint8_t end_sector ;
uint8_t end_cyl ;
uint32_t start_sect ;
uint32_t nr_sects ;
2004-12-21 19:10:25 +03:00
} __attribute__ ( ( packed ) ) ;
2004-11-23 14:44:04 +03:00
2013-06-12 14:08:56 +04:00
static int _is_partitionable ( struct dev_types * dt , struct device * dev )
2004-11-23 14:44:04 +03:00
{
2013-06-12 14:08:56 +04:00
int parts = major_max_partitions ( dt , MAJOR ( dev - > dev ) ) ;
2004-11-23 14:44:04 +03:00
2009-07-10 02:50:45 +04:00
/* All MD devices are partitionable via blkext (as of 2.6.28) */
2013-06-12 14:08:56 +04:00
if ( MAJOR ( dev - > dev ) = = dt - > md_major )
2009-07-10 02:50:45 +04:00
return 1 ;
2004-12-10 19:01:35 +03:00
if ( ( parts < = 1 ) | | ( MINOR ( dev - > dev ) % parts ) )
2004-11-24 23:38:05 +03:00
return 0 ;
2004-11-23 14:44:04 +03:00
2004-11-24 23:38:05 +03:00
return 1 ;
2004-11-23 14:44:04 +03:00
}
static int _has_partition_table ( struct device * dev )
{
int ret = 0 ;
2004-12-21 19:10:25 +03:00
unsigned p ;
2010-10-20 19:07:30 +04:00
struct {
uint8_t skip [ PART_OFFSET ] ;
struct partition part [ 4 ] ;
uint16_t magic ;
} __attribute__ ( ( packed ) ) buf ; /* sizeof() == SECTOR_SIZE */
2004-11-23 14:44:04 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_read ( dev , UINT64_C ( 0 ) , sizeof ( buf ) , & buf ) )
2010-04-06 21:36:41 +04:00
return_0 ;
2004-12-21 19:10:25 +03:00
/* FIXME Check for other types of partition table too */
/* Check for msdos partition table */
2010-10-20 19:07:30 +04:00
if ( buf . magic = = xlate16 ( PART_MAGIC ) ) {
for ( p = 0 ; p < 4 ; + + p ) {
2004-12-21 19:10:25 +03:00
/* Table is invalid if boot indicator not 0 or 0x80 */
2010-10-20 19:07:30 +04:00
if ( buf . part [ p ] . boot_ind & 0x7f ) {
2004-12-21 19:10:25 +03:00
ret = 0 ;
break ;
}
/* Must have at least one non-empty partition */
2010-10-20 19:07:30 +04:00
if ( buf . part [ p ] . nr_sects )
2004-12-21 19:10:25 +03:00
ret = 1 ;
}
}
2004-11-23 14:44:04 +03:00
return ret ;
}
2013-06-12 14:08:56 +04:00
int dev_is_partitioned ( struct dev_types * dt , struct device * dev )
2004-11-23 14:44:04 +03:00
{
2013-06-12 14:08:56 +04:00
if ( ! _is_partitionable ( dt , dev ) )
2004-11-23 14:44:04 +03:00
return 0 ;
return _has_partition_table ( dev ) ;
}
2013-06-12 14:14:11 +04:00
/*
* Get primary dev for the dev supplied .
2013-06-12 16:33:28 +04:00
*
* We can get a primary device for a partition either by :
* A : knowing the number of partitions allowed for the dev and also
* which major : minor number represents the primary and partition device
* ( by using the dev_types - > dev_type_array )
* B : by the existence of the ' partition ' sysfs attribute
* ( / dev / block / < major > : < minor > / partition )
*
* Method A is tried first , then method B as a fallback if A fails .
*
* N . B . Method B can only do the decision based on the pure existence of
* the ' partition ' sysfs item . There ' s no direct scan for partition
* tables whatsoever !
*
2013-06-12 14:14:11 +04:00
* Returns :
2013-06-12 16:33:28 +04:00
* 0 on error
* 1 if the dev is already a primary dev , primary dev in ' result '
* 2 if the dev is a partition , primary dev in ' result '
2013-06-12 14:14:11 +04:00
*/
2013-06-12 14:08:56 +04:00
int dev_get_primary_dev ( struct dev_types * dt , struct device * dev , dev_t * result )
{
const char * sysfs_dir = dm_sysfs_dir ( ) ;
2013-06-12 14:14:11 +04:00
int major = ( int ) MAJOR ( dev - > dev ) ;
int minor = ( int ) MINOR ( dev - > dev ) ;
2013-06-12 14:08:56 +04:00
char path [ PATH_MAX + 1 ] ;
char temp_path [ PATH_MAX + 1 ] ;
char buffer [ 64 ] ;
struct stat info ;
2013-06-12 14:14:11 +04:00
FILE * fp = NULL ;
2013-07-19 17:26:53 +04:00
int parts , residue , size , ret = 0 ;
2013-06-12 14:14:11 +04:00
/*
* Try to get the primary dev out of the
* list of known device types first .
*/
if ( ( parts = dt - > dev_type_array [ major ] . max_partitions ) > 1 ) {
if ( ( residue = minor % parts ) ) {
* result = MKDEV ( ( dev_t ) major , ( minor - residue ) ) ;
2013-06-12 16:33:28 +04:00
ret = 2 ;
2013-06-12 14:14:11 +04:00
} else {
* result = dev - > dev ;
2013-06-12 16:33:28 +04:00
ret = 1 ; /* dev is not a partition! */
2013-06-12 14:14:11 +04:00
}
goto out ;
}
/*
* If we can ' t get the primary dev out of the list of known device
* types , try to look at sysfs directly then . This is more complex
* way and it also requires certain sysfs layout to be present
* which might not be there in old kernels !
*/
2013-06-12 14:08:56 +04:00
/* check if dev is a partition */
if ( dm_snprintf ( path , PATH_MAX , " %s/dev/block/%d:%d/partition " ,
2013-06-12 14:14:11 +04:00
sysfs_dir , major , minor ) < 0 ) {
2013-06-12 14:08:56 +04:00
log_error ( " dm_snprintf partition failed " ) ;
2013-06-12 14:14:11 +04:00
goto out ;
2013-06-12 14:08:56 +04:00
}
if ( stat ( path , & info ) = = - 1 ) {
if ( errno ! = ENOENT )
log_sys_error ( " stat " , path ) ;
2013-06-12 14:14:11 +04:00
* result = dev - > dev ;
2013-07-19 17:26:53 +04:00
ret = 1 ;
goto out ; /* dev is not a partition! */
2013-06-12 14:14:11 +04:00
2013-06-12 14:08:56 +04:00
}
/*
* extract parent ' s path from the partition ' s symlink , e . g . :
* - readlink / sys / dev / block / 259 : 0 = . . / . . / block / md0 / md0p1
* - dirname . . / . . / block / md0 / md0p1 = . . / . . / block / md0
* - basename . . / . . / block / md0 / md0 = md0
* Parent ' s ' dev ' sysfs attribute = / sys / block / md0 / dev
*/
if ( ( size = readlink ( dirname ( path ) , temp_path , PATH_MAX ) ) < 0 ) {
log_sys_error ( " readlink " , path ) ;
2013-06-12 14:14:11 +04:00
goto out ;
2013-06-12 14:08:56 +04:00
}
temp_path [ size ] = ' \0 ' ;
if ( dm_snprintf ( path , PATH_MAX , " %s/block/%s/dev " ,
sysfs_dir , basename ( dirname ( temp_path ) ) ) < 0 ) {
log_error ( " dm_snprintf dev failed " ) ;
2013-06-12 14:14:11 +04:00
goto out ;
2013-06-12 14:08:56 +04:00
}
/* finally, parse 'dev' attribute and create corresponding dev_t */
if ( stat ( path , & info ) = = - 1 ) {
if ( errno = = ENOENT )
log_error ( " sysfs file %s does not exist " , path ) ;
else
log_sys_error ( " stat " , path ) ;
2013-06-12 14:14:11 +04:00
goto out ;
2013-06-12 14:08:56 +04:00
}
fp = fopen ( path , " r " ) ;
if ( ! fp ) {
log_sys_error ( " fopen " , path ) ;
2013-06-12 14:14:11 +04:00
goto out ;
2013-06-12 14:08:56 +04:00
}
if ( ! fgets ( buffer , sizeof ( buffer ) , fp ) ) {
log_sys_error ( " fgets " , path ) ;
goto out ;
}
2013-06-12 14:14:11 +04:00
if ( sscanf ( buffer , " %d:%d " , & major , & minor ) ! = 2 ) {
2013-06-12 14:08:56 +04:00
log_error ( " sysfs file %s not in expected MAJ:MIN format: %s " ,
path , buffer ) ;
goto out ;
}
2013-06-12 14:14:11 +04:00
* result = MKDEV ( ( dev_t ) major , minor ) ;
2013-06-23 13:14:34 +04:00
ret = 2 ;
2013-06-12 14:08:56 +04:00
out :
2013-06-12 14:14:11 +04:00
if ( fp & & fclose ( fp ) )
2013-06-12 14:08:56 +04:00
log_sys_error ( " fclose " , path ) ;
return ret ;
}
2013-11-13 17:56:29 +04:00
# ifdef __linux__
2009-08-01 21:07:36 +04:00
2013-11-22 15:57:35 +04:00
static int _snprintf_attr ( char * buf , size_t buf_size , const char * sysfs_dir ,
const char * attribute , dev_t dev )
{
if ( dm_snprintf ( buf , buf_size , " %s/dev/block/%d:%d/%s " , sysfs_dir ,
( int ) MAJOR ( dev ) , ( int ) MINOR ( dev ) ,
attribute ) < 0 ) {
log_warn ( " dm_snprintf %s failed. " , attribute ) ;
return 0 ;
}
return 1 ;
}
2013-06-12 14:08:56 +04:00
static unsigned long _dev_topology_attribute ( struct dev_types * dt ,
const char * attribute ,
struct device * dev )
2009-08-01 21:07:36 +04:00
{
2013-06-12 13:38:48 +04:00
const char * sysfs_dir = dm_sysfs_dir ( ) ;
2013-11-22 15:57:35 +04:00
char path [ PATH_MAX ] , buffer [ 64 ] ;
2009-08-01 21:07:36 +04:00
FILE * fp ;
struct stat info ;
2009-08-01 21:08:43 +04:00
dev_t uninitialized_var ( primary ) ;
2009-08-01 21:07:36 +04:00
unsigned long result = 0UL ;
if ( ! attribute | | ! * attribute )
return_0 ;
if ( ! sysfs_dir | | ! * sysfs_dir )
return_0 ;
2013-11-22 15:57:35 +04:00
if ( ! _snprintf_attr ( path , sizeof ( path ) , sysfs_dir , attribute , dev - > dev ) )
return_0 ;
2009-08-01 21:07:36 +04:00
2009-08-01 21:08:43 +04:00
/*
* check if the desired sysfs attribute exists
* - if not : either the kernel doesn ' t have topology support
* or the device could be a partition
*/
2009-08-01 21:14:52 +04:00
if ( stat ( path , & info ) = = - 1 ) {
if ( errno ! = ENOENT ) {
log_sys_error ( " stat " , path ) ;
return 0 ;
}
2013-06-12 16:33:28 +04:00
if ( ! dev_get_primary_dev ( dt , dev , & primary ) )
2009-08-01 21:08:43 +04:00
return 0 ;
/* get attribute from partition's primary device */
2013-11-22 15:57:35 +04:00
if ( ! _snprintf_attr ( path , sizeof ( path ) , sysfs_dir , attribute , primary ) )
return_0 ;
2009-08-01 21:14:52 +04:00
if ( stat ( path , & info ) = = - 1 ) {
if ( errno ! = ENOENT )
log_sys_error ( " stat " , path ) ;
2009-08-01 21:08:43 +04:00
return 0 ;
2009-08-01 21:14:52 +04:00
}
2009-08-01 21:08:43 +04:00
}
2009-08-01 21:07:36 +04:00
if ( ! ( fp = fopen ( path , " r " ) ) ) {
log_sys_error ( " fopen " , path ) ;
return 0 ;
}
if ( ! fgets ( buffer , sizeof ( buffer ) , fp ) ) {
log_sys_error ( " fgets " , path ) ;
goto out ;
}
if ( sscanf ( buffer , " %lu " , & result ) ! = 1 ) {
log_error ( " sysfs file %s not in expected format: %s " , path ,
buffer ) ;
goto out ;
}
log_very_verbose ( " Device %s %s is %lu bytes. " ,
dev_name ( dev ) , attribute , result ) ;
out :
if ( fclose ( fp ) )
log_sys_error ( " fclose " , path ) ;
return result > > SECTOR_SHIFT ;
}
2013-06-12 14:08:56 +04:00
unsigned long dev_alignment_offset ( struct dev_types * dt , struct device * dev )
2009-08-01 21:07:36 +04:00
{
2013-06-12 14:08:56 +04:00
return _dev_topology_attribute ( dt , " alignment_offset " , dev ) ;
2009-08-01 21:07:36 +04:00
}
2013-06-12 14:08:56 +04:00
unsigned long dev_minimum_io_size ( struct dev_types * dt , struct device * dev )
2009-08-01 21:08:43 +04:00
{
2013-06-12 14:08:56 +04:00
return _dev_topology_attribute ( dt , " queue/minimum_io_size " , dev ) ;
2009-08-01 21:08:43 +04:00
}
2013-06-12 14:08:56 +04:00
unsigned long dev_optimal_io_size ( struct dev_types * dt , struct device * dev )
2009-08-01 21:08:43 +04:00
{
2013-06-12 14:08:56 +04:00
return _dev_topology_attribute ( dt , " queue/optimal_io_size " , dev ) ;
2009-08-01 21:08:43 +04:00
}
2013-06-12 14:08:56 +04:00
unsigned long dev_discard_max_bytes ( struct dev_types * dt , struct device * dev )
2011-04-13 01:59:01 +04:00
{
2013-06-12 14:08:56 +04:00
return _dev_topology_attribute ( dt , " queue/discard_max_bytes " , dev ) ;
2011-04-13 01:59:01 +04:00
}
2013-06-12 14:08:56 +04:00
unsigned long dev_discard_granularity ( struct dev_types * dt , struct device * dev )
2011-04-13 01:59:01 +04:00
{
2013-06-12 14:08:56 +04:00
return _dev_topology_attribute ( dt , " queue/discard_granularity " , dev ) ;
2011-04-13 01:59:01 +04:00
}
2009-08-01 21:07:36 +04:00
# else
2013-06-17 17:17:15 +04:00
int dev_get_primary_dev ( struct dev_types * dt , struct device * dev , dev_t * result )
2009-08-01 21:11:02 +04:00
{
return 0 ;
}
2013-06-12 14:08:56 +04:00
unsigned long dev_alignment_offset ( struct dev_types * dt , struct device * dev )
2009-08-01 21:07:36 +04:00
{
return 0UL ;
}
2013-06-12 14:08:56 +04:00
unsigned long dev_minimum_io_size ( struct dev_types * dt , struct device * dev )
2009-08-01 21:08:43 +04:00
{
return 0UL ;
}
2013-06-12 14:08:56 +04:00
unsigned long dev_optimal_io_size ( struct dev_types * dt , struct device * dev )
2009-08-01 21:08:43 +04:00
{
return 0UL ;
}
2013-06-12 14:08:56 +04:00
unsigned long dev_discard_max_bytes ( struct dev_types * dt , struct device * dev )
2011-04-13 01:59:01 +04:00
{
return 0UL ;
}
2013-06-12 14:08:56 +04:00
unsigned long dev_discard_granularity ( struct dev_types * dt , struct device * dev )
2011-04-13 01:59:01 +04:00
{
return 0UL ;
}
2009-08-01 21:07:36 +04:00
# endif