2005-04-17 02:20:36 +04:00
/*
* fs / partitions / check . c
*
* Code extracted from drivers / block / genhd . c
* Copyright ( C ) 1991 - 1998 Linus Torvalds
* Re - organised Feb 1998 Russell King
*
* We now have independent partition support from the
* block drivers , which allows all the partition code to
* be grouped in one location , and it to be mostly self
* contained .
*
* Added needed MAJORS for new pairs , { hdi , hdj } , { hdk , hdl }
*/
# include <linux/init.h>
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/kmod.h>
# include <linux/ctype.h>
2008-02-08 13:04:35 +03:00
# include <linux/genhd.h>
2005-04-17 02:20:36 +04:00
# include "check.h"
# include "acorn.h"
# include "amiga.h"
# include "atari.h"
# include "ldm.h"
# include "mac.h"
# include "msdos.h"
# include "osf.h"
# include "sgi.h"
# include "sun.h"
# include "ibm.h"
# include "ultrix.h"
# include "efi.h"
2006-01-17 09:14:20 +03:00
# include "karma.h"
2007-05-08 11:29:15 +04:00
# include "sysv68.h"
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_BLK_DEV_MD
extern void md_autodetect_dev ( dev_t dev ) ;
# endif
int warn_no_part = 1 ; /*This is ugly: should make genhd removable media aware*/
static int ( * check_part [ ] ) ( struct parsed_partitions * , struct block_device * ) = {
/*
* Probe partition formats with tables at disk address 0
* that also have an ADFS boot block at 0xdc0 .
*/
# ifdef CONFIG_ACORN_PARTITION_ICS
adfspart_check_ICS ,
# endif
# ifdef CONFIG_ACORN_PARTITION_POWERTEC
adfspart_check_POWERTEC ,
# endif
# ifdef CONFIG_ACORN_PARTITION_EESOX
adfspart_check_EESOX ,
# endif
/*
* Now move on to formats that only have partition info at
* disk address 0xdc0 . Since these may also have stale
* PC / BIOS partition tables , they need to come before
* the msdos entry .
*/
# ifdef CONFIG_ACORN_PARTITION_CUMANA
adfspart_check_CUMANA ,
# endif
# ifdef CONFIG_ACORN_PARTITION_ADFS
adfspart_check_ADFS ,
# endif
# ifdef CONFIG_EFI_PARTITION
efi_partition , /* this must come before msdos */
# endif
# ifdef CONFIG_SGI_PARTITION
sgi_partition ,
# endif
# ifdef CONFIG_LDM_PARTITION
ldm_partition , /* this must come before msdos */
# endif
# ifdef CONFIG_MSDOS_PARTITION
msdos_partition ,
# endif
# ifdef CONFIG_OSF_PARTITION
osf_partition ,
# endif
# ifdef CONFIG_SUN_PARTITION
sun_partition ,
# endif
# ifdef CONFIG_AMIGA_PARTITION
amiga_partition ,
# endif
# ifdef CONFIG_ATARI_PARTITION
atari_partition ,
# endif
# ifdef CONFIG_MAC_PARTITION
mac_partition ,
# endif
# ifdef CONFIG_ULTRIX_PARTITION
ultrix_partition ,
# endif
# ifdef CONFIG_IBM_PARTITION
ibm_partition ,
2006-01-17 09:14:20 +03:00
# endif
# ifdef CONFIG_KARMA_PARTITION
karma_partition ,
2007-05-08 11:29:15 +04:00
# endif
# ifdef CONFIG_SYSV68_PARTITION
sysv68_partition ,
2005-04-17 02:20:36 +04:00
# endif
NULL
} ;
/*
* disk_name ( ) is used by partition check code and the genhd driver .
* It formats the devicename of the indicated disk into
* the supplied buffer ( of size at least 32 ) , and returns
* a pointer to that same buffer ( for convenience ) .
*/
2008-09-03 11:01:09 +04:00
char * disk_name ( struct gendisk * hd , int partno , char * buf )
2005-04-17 02:20:36 +04:00
{
2008-09-03 11:01:09 +04:00
if ( ! partno )
2005-04-17 02:20:36 +04:00
snprintf ( buf , BDEVNAME_SIZE , " %s " , hd - > disk_name ) ;
else if ( isdigit ( hd - > disk_name [ strlen ( hd - > disk_name ) - 1 ] ) )
2008-09-03 11:01:09 +04:00
snprintf ( buf , BDEVNAME_SIZE , " %sp%d " , hd - > disk_name , partno ) ;
2005-04-17 02:20:36 +04:00
else
2008-09-03 11:01:09 +04:00
snprintf ( buf , BDEVNAME_SIZE , " %s%d " , hd - > disk_name , partno ) ;
2005-04-17 02:20:36 +04:00
return buf ;
}
const char * bdevname ( struct block_device * bdev , char * buf )
{
2008-09-03 11:01:48 +04:00
int partno = 0 ;
if ( bdev - > bd_part )
partno = bdev - > bd_part - > partno ;
2008-09-03 11:01:09 +04:00
return disk_name ( bdev - > bd_disk , partno , buf ) ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( bdevname ) ;
/*
* There ' s very little reason to use this , you should really
* have a struct block_device just about everywhere and use
* bdevname ( ) instead .
*/
const char * __bdevname ( dev_t dev , char * buffer )
{
scnprintf ( buffer , BDEVNAME_SIZE , " unknown-block(%u,%u) " ,
MAJOR ( dev ) , MINOR ( dev ) ) ;
return buffer ;
}
EXPORT_SYMBOL ( __bdevname ) ;
static struct parsed_partitions *
check_partition ( struct gendisk * hd , struct block_device * bdev )
{
struct parsed_partitions * state ;
2006-12-07 07:35:16 +03:00
int i , res , err ;
2005-04-17 02:20:36 +04:00
state = kmalloc ( sizeof ( struct parsed_partitions ) , GFP_KERNEL ) ;
if ( ! state )
return NULL ;
2005-06-21 08:15:16 +04:00
disk_name ( hd , 0 , state - > name ) ;
printk ( KERN_INFO " %s: " , state - > name ) ;
if ( isdigit ( state - > name [ strlen ( state - > name ) - 1 ] ) )
2005-04-17 02:20:36 +04:00
sprintf ( state - > name , " p " ) ;
2005-06-21 08:15:16 +04:00
2008-09-03 11:01:48 +04:00
state - > limit = disk_max_parts ( hd ) + 1 ;
2006-12-07 07:35:16 +03:00
i = res = err = 0 ;
2005-04-17 02:20:36 +04:00
while ( ! res & & check_part [ i ] ) {
memset ( & state - > parts , 0 , sizeof ( state - > parts ) ) ;
res = check_part [ i + + ] ( state , bdev ) ;
2006-12-07 07:35:16 +03:00
if ( res < 0 ) {
/* We have hit an I/O error which we don't report now.
* But record it , and let the others do their job .
*/
err = res ;
res = 0 ;
}
2005-04-17 02:20:36 +04:00
}
if ( res > 0 )
return state ;
2007-03-08 07:41:24 +03:00
if ( err )
2006-12-07 07:35:16 +03:00
/* The partition is unrecognized. So report I/O errors if there were any */
res = err ;
2005-04-17 02:20:36 +04:00
if ( ! res )
printk ( " unknown partition table \n " ) ;
else if ( warn_no_part )
printk ( " unable to read partition table \n " ) ;
kfree ( state ) ;
2006-12-07 07:35:14 +03:00
return ERR_PTR ( res ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 00:08:01 +04:00
static ssize_t part_start_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-05-22 00:08:01 +04:00
struct hd_struct * p = dev_to_part ( dev ) ;
2005-10-01 16:49:43 +04:00
2007-05-22 00:08:01 +04:00
return sprintf ( buf , " %llu \n " , ( unsigned long long ) p - > start_sect ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 00:08:01 +04:00
static ssize_t part_size_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-10-01 16:49:43 +04:00
{
2007-05-22 00:08:01 +04:00
struct hd_struct * p = dev_to_part ( dev ) ;
return sprintf ( buf , " %llu \n " , ( unsigned long long ) p - > nr_sects ) ;
2005-10-01 16:49:43 +04:00
}
2007-05-22 00:08:01 +04:00
static ssize_t part_stat_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
2005-04-17 02:20:36 +04:00
{
2007-05-22 00:08:01 +04:00
struct hd_struct * p = dev_to_part ( dev ) ;
2008-08-25 14:47:21 +04:00
int cpu ;
2007-05-22 00:08:01 +04:00
2008-08-25 14:47:21 +04:00
cpu = disk_stat_lock ( ) ;
part_round_stats ( cpu , p ) ;
disk_stat_unlock ( ) ;
2008-02-08 13:04:55 +03:00
return sprintf ( buf ,
" %8lu %8lu %8llu %8u "
" %8lu %8lu %8llu %8u "
" %8u %8u %8u "
" \n " ,
part_stat_read ( p , ios [ READ ] ) ,
part_stat_read ( p , merges [ READ ] ) ,
( unsigned long long ) part_stat_read ( p , sectors [ READ ] ) ,
jiffies_to_msecs ( part_stat_read ( p , ticks [ READ ] ) ) ,
part_stat_read ( p , ios [ WRITE ] ) ,
part_stat_read ( p , merges [ WRITE ] ) ,
( unsigned long long ) part_stat_read ( p , sectors [ WRITE ] ) ,
jiffies_to_msecs ( part_stat_read ( p , ticks [ WRITE ] ) ) ,
p - > in_flight ,
jiffies_to_msecs ( part_stat_read ( p , io_ticks ) ) ,
jiffies_to_msecs ( part_stat_read ( p , time_in_queue ) ) ) ;
2005-04-17 02:20:36 +04:00
}
2006-12-08 13:39:46 +03:00
# ifdef CONFIG_FAIL_MAKE_REQUEST
2007-05-22 00:08:01 +04:00
static ssize_t part_fail_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
struct hd_struct * p = dev_to_part ( dev ) ;
2006-12-08 13:39:46 +03:00
2007-05-22 00:08:01 +04:00
return sprintf ( buf , " %d \n " , p - > make_it_fail ) ;
}
static ssize_t part_fail_store ( struct device * dev ,
struct device_attribute * attr ,
2006-12-08 13:39:46 +03:00
const char * buf , size_t count )
{
2007-05-22 00:08:01 +04:00
struct hd_struct * p = dev_to_part ( dev ) ;
2006-12-08 13:39:46 +03:00
int i ;
if ( count > 0 & & sscanf ( buf , " %d " , & i ) > 0 )
p - > make_it_fail = ( i = = 0 ) ? 0 : 1 ;
return count ;
}
2007-05-22 00:08:01 +04:00
# endif
2006-12-08 13:39:46 +03:00
2007-05-22 00:08:01 +04:00
static DEVICE_ATTR ( start , S_IRUGO , part_start_show , NULL ) ;
static DEVICE_ATTR ( size , S_IRUGO , part_size_show , NULL ) ;
static DEVICE_ATTR ( stat , S_IRUGO , part_stat_show , NULL ) ;
# ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
__ATTR ( make - it - fail , S_IRUGO | S_IWUSR , part_fail_show , part_fail_store ) ;
2006-12-08 13:39:46 +03:00
# endif
2007-05-22 00:08:01 +04:00
static struct attribute * part_attrs [ ] = {
& dev_attr_start . attr ,
& dev_attr_size . attr ,
& dev_attr_stat . attr ,
2006-12-08 13:39:46 +03:00
# ifdef CONFIG_FAIL_MAKE_REQUEST
2007-05-22 00:08:01 +04:00
& dev_attr_fail . attr ,
2006-12-08 13:39:46 +03:00
# endif
2007-05-22 00:08:01 +04:00
NULL
2005-04-17 02:20:36 +04:00
} ;
2007-05-22 00:08:01 +04:00
static struct attribute_group part_attr_group = {
. attrs = part_attrs ,
} ;
2005-04-17 02:20:36 +04:00
2007-05-22 00:08:01 +04:00
static struct attribute_group * part_attr_groups [ ] = {
& part_attr_group ,
NULL
} ;
static void part_release ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2007-05-22 00:08:01 +04:00
struct hd_struct * p = dev_to_part ( dev ) ;
2008-02-08 13:04:35 +03:00
free_part_stats ( p ) ;
2005-04-17 02:20:36 +04:00
kfree ( p ) ;
}
2007-05-22 00:08:01 +04:00
struct device_type part_type = {
. name = " partition " ,
. groups = part_attr_groups ,
2005-04-17 02:20:36 +04:00
. release = part_release ,
} ;
2006-03-27 13:17:55 +04:00
static inline void disk_sysfs_add_subdirs ( struct gendisk * disk )
{
struct kobject * k ;
2008-08-25 14:56:05 +04:00
k = kobject_get ( & disk_to_dev ( disk ) - > kobj ) ;
2007-11-06 09:24:43 +03:00
disk - > holder_dir = kobject_create_and_add ( " holders " , k ) ;
disk - > slave_dir = kobject_create_and_add ( " slaves " , k ) ;
2006-03-27 13:17:55 +04:00
kobject_put ( k ) ;
}
2008-09-03 11:03:02 +04:00
static void delete_partition_rcu_cb ( struct rcu_head * head )
{
struct hd_struct * part = container_of ( head , struct hd_struct , rcu_head ) ;
part - > start_sect = 0 ;
part - > nr_sects = 0 ;
part_stat_set_all ( part , 0 ) ;
2008-08-25 14:56:05 +04:00
put_device ( part_to_dev ( part ) ) ;
2008-09-03 11:03:02 +04:00
}
2008-09-03 11:01:09 +04:00
void delete_partition ( struct gendisk * disk , int partno )
2005-04-17 02:20:36 +04:00
{
2008-09-03 11:03:02 +04:00
struct hd_struct * part ;
2007-05-22 00:08:01 +04:00
2008-09-03 11:03:02 +04:00
part = disk - > __part [ partno - 1 ] ;
if ( ! part )
2005-04-17 02:20:36 +04:00
return ;
2008-09-03 11:03:02 +04:00
2008-08-25 14:47:22 +04:00
blk_free_devt ( part_devt ( part ) ) ;
2008-09-03 11:03:02 +04:00
rcu_assign_pointer ( disk - > __part [ partno - 1 ] , NULL ) ;
kobject_put ( part - > holder_dir ) ;
2008-08-25 14:56:05 +04:00
device_del ( part_to_dev ( part ) ) ;
2008-09-03 11:03:02 +04:00
call_rcu ( & part - > rcu_head , delete_partition_rcu_cb ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-07 10:33:39 +03:00
static ssize_t whole_disk_show ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
return 0 ;
}
static DEVICE_ATTR ( whole_disk , S_IRUSR | S_IRGRP | S_IROTH ,
whole_disk_show , NULL ) ;
2008-09-03 11:01:09 +04:00
int add_partition ( struct gendisk * disk , int partno ,
sector_t start , sector_t len , int flags )
2005-04-17 02:20:36 +04:00
{
struct hd_struct * p ;
2008-08-25 14:47:22 +04:00
dev_t devt = MKDEV ( 0 , 0 ) ;
2008-08-25 14:56:05 +04:00
struct device * ddev = disk_to_dev ( disk ) ;
struct device * pdev ;
const char * dname ;
2007-05-22 00:08:01 +04:00
int err ;
2005-04-17 02:20:36 +04:00
2008-09-03 11:03:02 +04:00
if ( disk - > __part [ partno - 1 ] )
2008-08-25 14:30:16 +04:00
return - EBUSY ;
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
p = kzalloc ( sizeof ( * p ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! p )
2008-07-25 12:48:25 +04:00
return - ENOMEM ;
2007-05-22 00:08:01 +04:00
2008-02-08 13:04:35 +03:00
if ( ! init_part_stats ( p ) ) {
2008-07-25 12:48:25 +04:00
err = - ENOMEM ;
2008-08-25 14:30:16 +04:00
goto out_free ;
2008-02-08 13:04:35 +03:00
}
2008-08-25 14:56:05 +04:00
pdev = part_to_dev ( p ) ;
2005-04-17 02:20:36 +04:00
p - > start_sect = start ;
p - > nr_sects = len ;
2008-09-03 11:01:09 +04:00
p - > partno = partno ;
2006-07-10 15:44:00 +04:00
p - > policy = disk - > policy ;
2005-04-17 02:20:36 +04:00
2008-08-25 14:56:05 +04:00
dname = dev_name ( ddev ) ;
if ( isdigit ( dname [ strlen ( dname ) - 1 ] ) )
snprintf ( pdev - > bus_id , BUS_ID_SIZE , " %sp%d " , dname , partno ) ;
2005-04-17 02:20:36 +04:00
else
2008-08-25 14:56:05 +04:00
snprintf ( pdev - > bus_id , BUS_ID_SIZE , " %s%d " , dname , partno ) ;
2007-05-22 00:08:01 +04:00
2008-08-25 14:56:05 +04:00
device_initialize ( pdev ) ;
pdev - > class = & block_class ;
pdev - > type = & part_type ;
pdev - > parent = ddev ;
2007-05-22 00:08:01 +04:00
2008-08-25 14:47:22 +04:00
err = blk_alloc_devt ( p , & devt ) ;
if ( err )
2008-08-25 14:56:05 +04:00
goto out_free ;
pdev - > devt = devt ;
2008-08-25 14:47:22 +04:00
2007-05-22 00:08:01 +04:00
/* delay uevent until 'holders' subdir is created */
2008-08-25 14:56:05 +04:00
pdev - > uevent_suppress = 1 ;
err = device_add ( pdev ) ;
2008-07-25 12:48:25 +04:00
if ( err )
2008-08-25 14:30:16 +04:00
goto out_put ;
err = - ENOMEM ;
2008-08-25 14:56:05 +04:00
p - > holder_dir = kobject_create_and_add ( " holders " , & pdev - > kobj ) ;
2008-08-25 14:30:16 +04:00
if ( ! p - > holder_dir )
goto out_del ;
2008-08-25 14:56:05 +04:00
pdev - > uevent_suppress = 0 ;
2008-07-25 12:48:25 +04:00
if ( flags & ADDPART_FLAG_WHOLEDISK ) {
2008-08-25 14:56:05 +04:00
err = device_create_file ( pdev , & dev_attr_whole_disk ) ;
2008-07-25 12:48:25 +04:00
if ( err )
2008-08-25 14:30:16 +04:00
goto out_del ;
2008-07-25 12:48:25 +04:00
}
2005-04-17 02:20:36 +04:00
2008-08-25 14:30:16 +04:00
/* everything is up and running, commence */
2008-09-03 11:03:02 +04:00
INIT_RCU_HEAD ( & p - > rcu_head ) ;
rcu_assign_pointer ( disk - > __part [ partno - 1 ] , p ) ;
2008-08-25 14:30:16 +04:00
2007-05-22 00:08:01 +04:00
/* suppress uevent if the disk supresses it */
2008-08-25 14:56:05 +04:00
if ( ! ddev - > uevent_suppress )
kobject_uevent ( & pdev - > kobj , KOBJ_ADD ) ;
2008-07-25 12:48:25 +04:00
return 0 ;
2008-08-25 14:30:16 +04:00
out_free :
kfree ( p ) ;
return err ;
out_del :
kobject_put ( p - > holder_dir ) ;
2008-08-25 14:56:05 +04:00
device_del ( pdev ) ;
2008-08-25 14:30:16 +04:00
out_put :
2008-08-25 14:56:05 +04:00
put_device ( pdev ) ;
2008-08-25 14:47:22 +04:00
blk_free_devt ( devt ) ;
2008-07-25 12:48:25 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
/* Not exported, helper to add_disk(). */
void register_disk ( struct gendisk * disk )
{
2008-08-25 14:56:05 +04:00
struct device * ddev = disk_to_dev ( disk ) ;
2005-04-17 02:20:36 +04:00
struct block_device * bdev ;
2008-09-03 11:03:02 +04:00
struct disk_part_iter piter ;
struct hd_struct * part ;
2005-04-17 02:20:36 +04:00
char * s ;
int err ;
2008-08-25 14:56:05 +04:00
ddev - > parent = disk - > driverfs_dev ;
2007-05-22 00:08:01 +04:00
2008-08-25 14:56:05 +04:00
strlcpy ( ddev - > bus_id , disk - > disk_name , BUS_ID_SIZE ) ;
2007-05-22 00:08:01 +04:00
/* ewww... some of these buggers have / in the name... */
2008-08-25 14:56:05 +04:00
s = strchr ( ddev - > bus_id , ' / ' ) ;
2005-04-17 02:20:36 +04:00
if ( s )
* s = ' ! ' ;
2007-05-22 00:08:01 +04:00
/* delay uevents, until we scanned partition table */
2008-08-25 14:56:05 +04:00
ddev - > uevent_suppress = 1 ;
2007-05-22 00:08:01 +04:00
2008-08-25 14:56:05 +04:00
if ( device_add ( ddev ) )
2005-04-17 02:20:36 +04:00
return ;
2007-05-22 00:08:01 +04:00
# ifndef CONFIG_SYSFS_DEPRECATED
2008-08-25 14:56:05 +04:00
err = sysfs_create_link ( block_depr , & ddev - > kobj ,
kobject_name ( & ddev - > kobj ) ) ;
2006-10-17 11:10:23 +04:00
if ( err ) {
2008-08-25 14:56:05 +04:00
device_del ( ddev ) ;
2006-10-17 11:10:23 +04:00
return ;
}
2007-05-22 00:08:01 +04:00
# endif
disk_sysfs_add_subdirs ( disk ) ;
2005-04-17 02:20:36 +04:00
/* No minors to use for partitions */
2008-09-03 11:01:48 +04:00
if ( ! disk_max_parts ( disk ) )
2006-03-24 22:45:35 +03:00
goto exit ;
2005-04-17 02:20:36 +04:00
/* No such device (e.g., media were just removed) */
if ( ! get_capacity ( disk ) )
2006-03-24 22:45:35 +03:00
goto exit ;
2005-04-17 02:20:36 +04:00
bdev = bdget_disk ( disk , 0 ) ;
if ( ! bdev )
2006-03-24 22:45:35 +03:00
goto exit ;
2005-04-17 02:20:36 +04:00
bdev - > bd_invalidated = 1 ;
2006-03-24 22:45:35 +03:00
err = blkdev_get ( bdev , FMODE_READ , 0 ) ;
if ( err < 0 )
goto exit ;
2005-04-17 02:20:36 +04:00
blkdev_put ( bdev ) ;
2006-03-24 22:45:35 +03:00
exit :
2007-05-22 00:08:01 +04:00
/* announce disk after possible partitions are created */
2008-08-25 14:56:05 +04:00
ddev - > uevent_suppress = 0 ;
kobject_uevent ( & ddev - > kobj , KOBJ_ADD ) ;
2006-03-24 22:45:35 +03:00
/* announce possible partitions */
2008-09-03 11:03:02 +04:00
disk_part_iter_init ( & piter , disk , 0 ) ;
while ( ( part = disk_part_iter_next ( & piter ) ) )
2008-08-25 14:56:05 +04:00
kobject_uevent ( & part_to_dev ( part ) - > kobj , KOBJ_ADD ) ;
2008-09-03 11:03:02 +04:00
disk_part_iter_exit ( & piter ) ;
2005-04-17 02:20:36 +04:00
}
int rescan_partitions ( struct gendisk * disk , struct block_device * bdev )
{
2008-09-03 11:03:02 +04:00
struct disk_part_iter piter ;
struct hd_struct * part ;
2005-04-17 02:20:36 +04:00
struct parsed_partitions * state ;
int p , res ;
if ( bdev - > bd_part_count )
return - EBUSY ;
res = invalidate_partition ( disk , 0 ) ;
if ( res )
return res ;
bdev - > bd_invalidated = 0 ;
2008-09-03 11:03:02 +04:00
disk_part_iter_init ( & piter , disk , DISK_PITER_INCL_EMPTY ) ;
while ( ( part = disk_part_iter_next ( & piter ) ) )
delete_partition ( disk , part - > partno ) ;
disk_part_iter_exit ( & piter ) ;
2005-04-17 02:20:36 +04:00
if ( disk - > fops - > revalidate_disk )
disk - > fops - > revalidate_disk ( disk ) ;
if ( ! get_capacity ( disk ) | | ! ( state = check_partition ( disk , bdev ) ) )
return 0 ;
2006-12-07 07:35:14 +03:00
if ( IS_ERR ( state ) ) /* I/O error reading the partition table */
2007-03-17 00:38:25 +03:00
return - EIO ;
2008-03-09 23:26:02 +03:00
/* tell userspace that the media / partition table may have changed */
2008-08-25 14:56:05 +04:00
kobject_uevent ( & disk_to_dev ( disk ) - > kobj , KOBJ_CHANGE ) ;
2008-03-09 23:26:02 +03:00
2005-04-17 02:20:36 +04:00
for ( p = 1 ; p < state - > limit ; p + + ) {
sector_t size = state - > parts [ p ] . size ;
sector_t from = state - > parts [ p ] . from ;
if ( ! size )
continue ;
2006-06-23 13:06:07 +04:00
if ( from + size > get_capacity ( disk ) ) {
2008-09-13 13:33:25 +04:00
printk ( KERN_WARNING
" %s: p%d exceeds device capacity \n " ,
2006-06-23 13:06:07 +04:00
disk - > disk_name , p ) ;
2008-07-25 12:48:26 +04:00
}
res = add_partition ( disk , p , from , size , state - > parts [ p ] . flags ) ;
if ( res ) {
printk ( KERN_ERR " %s: p%d could not be added: %d \n " ,
disk - > disk_name , p , - res ) ;
continue ;
2006-06-23 13:06:07 +04:00
}
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_BLK_DEV_MD
2007-02-11 10:50:00 +03:00
if ( state - > parts [ p ] . flags & ADDPART_FLAG_RAID )
2005-04-17 02:20:36 +04:00
md_autodetect_dev ( bdev - > bd_dev + p ) ;
# endif
}
kfree ( state ) ;
return 0 ;
}
unsigned char * read_dev_sector ( struct block_device * bdev , sector_t n , Sector * p )
{
struct address_space * mapping = bdev - > bd_inode - > i_mapping ;
struct page * page ;
2006-06-23 13:05:08 +04:00
page = read_mapping_page ( mapping , ( pgoff_t ) ( n > > ( PAGE_CACHE_SHIFT - 9 ) ) ,
NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! IS_ERR ( page ) ) {
if ( PageError ( page ) )
goto fail ;
p - > v = page ;
return ( unsigned char * ) page_address ( page ) + ( ( n & ( ( 1 < < ( PAGE_CACHE_SHIFT - 9 ) ) - 1 ) ) < < 9 ) ;
fail :
page_cache_release ( page ) ;
}
p - > v = NULL ;
return NULL ;
}
EXPORT_SYMBOL ( read_dev_sector ) ;
void del_gendisk ( struct gendisk * disk )
{
2008-09-03 11:03:02 +04:00
struct disk_part_iter piter ;
struct hd_struct * part ;
2005-04-17 02:20:36 +04:00
/* invalidate stuff */
2008-09-03 11:03:02 +04:00
disk_part_iter_init ( & piter , disk ,
DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE ) ;
while ( ( part = disk_part_iter_next ( & piter ) ) ) {
invalidate_partition ( disk , part - > partno ) ;
delete_partition ( disk , part - > partno ) ;
2005-04-17 02:20:36 +04:00
}
2008-09-03 11:03:02 +04:00
disk_part_iter_exit ( & piter ) ;
2005-04-17 02:20:36 +04:00
invalidate_partition ( disk , 0 ) ;
disk - > capacity = 0 ;
disk - > flags & = ~ GENHD_FL_UP ;
unlink_gendisk ( disk ) ;
disk_stat_set_all ( disk , 0 ) ;
2005-10-13 23:48:42 +04:00
disk - > stamp = 0 ;
2005-04-17 02:20:36 +04:00
2007-12-20 19:13:05 +03:00
kobject_put ( disk - > holder_dir ) ;
kobject_put ( disk - > slave_dir ) ;
2007-05-22 00:08:01 +04:00
disk - > driverfs_dev = NULL ;
# ifndef CONFIG_SYSFS_DEPRECATED
2008-08-25 14:56:05 +04:00
sysfs_remove_link ( block_depr , dev_name ( disk_to_dev ( disk ) ) ) ;
2007-05-22 00:08:01 +04:00
# endif
2008-08-25 14:56:05 +04:00
device_del ( disk_to_dev ( disk ) ) ;
2005-04-17 02:20:36 +04:00
}