2005-04-17 02:20:36 +04:00
/*
* Copyright ( C ) 2001 - 2003 Sistina Software ( UK ) Limited .
*
* This file is released under the GPL .
*/
# include "dm.h"
# include <linux/module.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/bio.h>
# include <linux/slab.h>
2006-06-26 11:27:35 +04:00
# define DM_MSG_PREFIX "linear"
2005-04-17 02:20:36 +04:00
/*
* Linear : maps a linear range of a device .
*/
struct linear_c {
struct dm_dev * dev ;
sector_t start ;
} ;
/*
* Construct a linear mapping : < dev_path > < offset >
*/
static int linear_ctr ( struct dm_target * ti , unsigned int argc , char * * argv )
{
struct linear_c * lc ;
2006-03-27 13:17:48 +04:00
unsigned long long tmp ;
2005-04-17 02:20:36 +04:00
if ( argc ! = 2 ) {
2006-06-26 11:27:35 +04:00
ti - > error = " Invalid argument count " ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
lc = kmalloc ( sizeof ( * lc ) , GFP_KERNEL ) ;
if ( lc = = NULL ) {
ti - > error = " dm-linear: Cannot allocate linear context " ;
return - ENOMEM ;
}
2006-03-27 13:17:48 +04:00
if ( sscanf ( argv [ 1 ] , " %llu " , & tmp ) ! = 1 ) {
2005-04-17 02:20:36 +04:00
ti - > error = " dm-linear: Invalid device sector " ;
goto bad ;
}
2006-03-27 13:17:48 +04:00
lc - > start = tmp ;
2005-04-17 02:20:36 +04:00
if ( dm_get_device ( ti , argv [ 0 ] , lc - > start , ti - > len ,
dm_table_get_mode ( ti - > table ) , & lc - > dev ) ) {
ti - > error = " dm-linear: Device lookup failed " ;
goto bad ;
}
ti - > private = lc ;
return 0 ;
bad :
kfree ( lc ) ;
return - EINVAL ;
}
static void linear_dtr ( struct dm_target * ti )
{
struct linear_c * lc = ( struct linear_c * ) ti - > private ;
dm_put_device ( ti , lc - > dev ) ;
kfree ( lc ) ;
}
static int linear_map ( struct dm_target * ti , struct bio * bio ,
union map_info * map_context )
{
struct linear_c * lc = ( struct linear_c * ) ti - > private ;
bio - > bi_bdev = lc - > dev - > bdev ;
bio - > bi_sector = lc - > start + ( bio - > bi_sector - ti - > begin ) ;
2006-12-08 13:41:06 +03:00
return DM_MAPIO_REMAPPED ;
2005-04-17 02:20:36 +04:00
}
static int linear_status ( struct dm_target * ti , status_type_t type ,
char * result , unsigned int maxlen )
{
struct linear_c * lc = ( struct linear_c * ) ti - > private ;
switch ( type ) {
case STATUSTYPE_INFO :
result [ 0 ] = ' \0 ' ;
break ;
case STATUSTYPE_TABLE :
2006-03-27 13:17:48 +04:00
snprintf ( result , maxlen , " %s %llu " , lc - > dev - > name ,
( unsigned long long ) lc - > start ) ;
2005-04-17 02:20:36 +04:00
break ;
}
return 0 ;
}
2006-10-03 12:15:18 +04:00
static int linear_ioctl ( struct dm_target * ti , struct inode * inode ,
struct file * filp , unsigned int cmd ,
unsigned long arg )
{
struct linear_c * lc = ( struct linear_c * ) ti - > private ;
struct block_device * bdev = lc - > dev - > bdev ;
2006-10-03 12:15:22 +04:00
struct file fake_file = { } ;
struct dentry fake_dentry = { } ;
2006-10-03 12:15:18 +04:00
2006-10-03 12:15:22 +04:00
fake_file . f_mode = lc - > dev - > mode ;
2006-12-08 13:37:19 +03:00
fake_file . f_path . dentry = & fake_dentry ;
2006-10-03 12:15:22 +04:00
fake_dentry . d_inode = bdev - > bd_inode ;
return blkdev_driver_ioctl ( bdev - > bd_inode , & fake_file , bdev - > bd_disk , cmd , arg ) ;
2006-10-03 12:15:18 +04:00
}
2005-04-17 02:20:36 +04:00
static struct target_type linear_target = {
. name = " linear " ,
2006-10-03 12:15:18 +04:00
. version = { 1 , 0 , 2 } ,
2005-04-17 02:20:36 +04:00
. module = THIS_MODULE ,
. ctr = linear_ctr ,
. dtr = linear_dtr ,
. map = linear_map ,
. status = linear_status ,
2006-10-03 12:15:18 +04:00
. ioctl = linear_ioctl ,
2005-04-17 02:20:36 +04:00
} ;
int __init dm_linear_init ( void )
{
int r = dm_register_target ( & linear_target ) ;
if ( r < 0 )
2006-06-26 11:27:35 +04:00
DMERR ( " register failed %d " , r ) ;
2005-04-17 02:20:36 +04:00
return r ;
}
void dm_linear_exit ( void )
{
int r = dm_unregister_target ( & linear_target ) ;
if ( r < 0 )
2006-06-26 11:27:35 +04:00
DMERR ( " unregister failed %d " , r ) ;
2005-04-17 02:20:36 +04:00
}