2001-09-13 22:30:05 +04:00
/*
* dm - linear . c
*
* Copyright ( C ) 2001 Sistina Software
*
* This software is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 , or ( at
* your option ) any later version .
*
* This software is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with GNU CC ; see the file COPYING . If not , write to
* the Free Software Foundation , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
*/
# include <linux/config.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/fs.h>
2001-09-14 13:45:35 +04:00
# include <linux/blkdev.h>
2001-09-13 22:30:05 +04:00
# include <linux/device-mapper.h>
2001-09-14 13:45:35 +04:00
# include "dm.h"
2001-09-13 22:30:05 +04:00
/*
* linear : maps a linear range of a device .
*/
struct linear_c {
2001-09-14 13:45:35 +04:00
kdev_t rdev ;
2001-09-13 22:30:05 +04:00
long delta ; /* FIXME: we need a signed offset type */
2001-09-14 15:25:51 +04:00
struct block_device * bdev ;
2001-09-13 22:30:05 +04:00
} ;
/*
* construct a linear mapping .
* < dev_path > < offset >
*/
2001-09-20 23:25:58 +04:00
static void * linear_ctr ( struct dm_table * t , offset_t b , offset_t l ,
struct text_region * args )
2001-09-13 22:30:05 +04:00
{
struct linear_c * lc ;
unsigned int start ;
char path [ 256 ] ;
struct text_region word ;
2001-09-14 15:25:51 +04:00
struct block_device * bdev ;
2001-09-14 13:45:35 +04:00
int rv = 0 ;
int hardsect_size ;
2001-09-13 22:30:05 +04:00
if ( ! dm_get_word ( args , & word ) ) {
2001-09-20 01:27:15 +04:00
t - > err_msg = " couldn't get device path " ;
2001-09-20 23:25:58 +04:00
return ERR_PTR ( - EINVAL ) ;
2001-09-13 22:30:05 +04:00
}
dm_txt_copy ( path , sizeof ( path ) - 1 , & word ) ;
2001-09-14 13:45:35 +04:00
bdev = dm_blkdev_get ( path ) ;
if ( IS_ERR ( bdev ) ) {
2001-09-18 01:17:30 +04:00
switch ( PTR_ERR ( bdev ) ) {
case - ENOTBLK :
2001-09-20 01:27:15 +04:00
t - > err_msg = " not a block device " ;
2001-09-18 01:17:30 +04:00
break ;
case - EACCES :
2001-09-20 01:27:15 +04:00
t - > err_msg = " nodev mount option " ;
2001-09-18 01:17:30 +04:00
break ;
case - ENOENT :
default :
2001-09-20 01:27:15 +04:00
t - > err_msg = " no such device " ;
2001-09-18 01:17:30 +04:00
}
2001-09-20 23:25:58 +04:00
return bdev ;
2001-09-13 22:30:05 +04:00
}
if ( ! dm_get_number ( args , & start ) ) {
2001-09-20 01:27:15 +04:00
t - > err_msg = " destination start not given " ;
2001-09-14 13:45:35 +04:00
rv = - EINVAL ;
goto out_bdev_put ;
2001-09-13 22:30:05 +04:00
}
if ( ! ( lc = kmalloc ( sizeof ( lc ) , GFP_KERNEL ) ) ) {
2001-09-20 01:27:15 +04:00
t - > err_msg = " couldn't allocate memory for linear context \n " ;
2001-09-14 13:45:35 +04:00
rv = - ENOMEM ;
goto out_bdev_put ;
2001-09-13 22:30:05 +04:00
}
2001-09-14 15:25:51 +04:00
lc - > rdev = to_kdev_t ( bdev - > bd_dev ) ;
2001-09-14 13:45:35 +04:00
lc - > bdev = bdev ;
2001-09-13 22:30:05 +04:00
lc - > delta = ( int ) start - ( int ) b ;
2001-09-14 13:45:35 +04:00
hardsect_size = get_hardsect_size ( lc - > rdev ) ;
2001-09-19 21:46:27 +04:00
if ( t - > hardsect_size > hardsect_size )
2001-09-14 13:45:35 +04:00
t - > hardsect_size = hardsect_size ;
2001-09-13 22:30:05 +04:00
2001-09-20 23:25:58 +04:00
return lc ;
2001-09-14 13:45:35 +04:00
out_bdev_put :
dm_blkdev_put ( bdev ) ;
2001-09-20 23:25:58 +04:00
return ERR_PTR ( rv ) ;
2001-09-13 22:30:05 +04:00
}
static void linear_dtr ( struct dm_table * t , void * c )
{
struct linear_c * lc = ( struct linear_c * ) c ;
2001-09-14 13:45:35 +04:00
dm_blkdev_put ( lc - > bdev ) ;
2001-09-13 22:30:05 +04:00
kfree ( c ) ;
}
2001-09-14 20:22:02 +04:00
static int linear_map ( struct buffer_head * bh , int rw , void * context )
2001-09-13 22:30:05 +04:00
{
struct linear_c * lc = ( struct linear_c * ) context ;
2001-09-14 13:45:35 +04:00
bh - > b_rdev = lc - > rdev ;
2001-09-13 22:30:05 +04:00
bh - > b_rsector = bh - > b_rsector + lc - > delta ;
return 1 ;
}
static struct target_type linear_target = {
name : " linear " ,
2001-09-14 00:10:14 +04:00
module : THIS_MODULE ,
2001-09-13 22:30:05 +04:00
ctr : linear_ctr ,
dtr : linear_dtr ,
map : linear_map ,
2001-09-14 17:45:40 +04:00
flags : TF_BMAP ,
2001-09-13 22:30:05 +04:00
} ;
static int __init linear_init ( void )
{
int rv ;
rv = dm_register_target ( & linear_target ) ;
if ( rv < 0 ) {
printk ( KERN_ERR " Device mapper: Linear: register failed %d \n " , rv ) ;
}
return rv ;
}
static void __exit linear_exit ( void )
{
int rv ;
rv = dm_unregister_target ( & linear_target ) ;
if ( rv < 0 ) {
printk ( KERN_ERR " Device mapper: Linear: unregister failed %d \n " , rv ) ;
}
}
module_init ( linear_init ) ;
module_exit ( linear_exit ) ;
MODULE_AUTHOR ( " Joe Thornber <thornber@uk.sistina.com> " ) ;
MODULE_DESCRIPTION ( " Device Mapper: Linear mapping " ) ;
2001-09-14 17:27:58 +04:00
# ifdef MODULE_LICENSE
2001-09-14 13:45:35 +04:00
MODULE_LICENSE ( " GPL " ) ;
2001-09-14 17:27:58 +04:00
# endif
2001-09-13 22:30:05 +04:00