2008-06-30 22:04:41 +04:00
/*
* bio - integrity . c - bio data integrity extensions
*
2009-06-26 17:37:49 +04:00
* Copyright ( C ) 2007 , 2008 , 2009 Oracle Corporation
2008-06-30 22:04:41 +04:00
* Written by : Martin K . Petersen < martin . petersen @ oracle . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation .
*
* This program 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 this program ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 ,
* USA .
*
*/
# include <linux/blkdev.h>
# include <linux/mempool.h>
# include <linux/bio.h>
# include <linux/workqueue.h>
2009-06-26 17:37:49 +04:00
struct integrity_slab {
struct kmem_cache * slab ;
unsigned short nr_vecs ;
char name [ 8 ] ;
} ;
# define IS(x) { .nr_vecs = x, .name = "bip-"__stringify(x) }
struct integrity_slab bip_slab [ BIOVEC_NR_POOLS ] __read_mostly = {
IS ( 1 ) , IS ( 4 ) , IS ( 16 ) , IS ( 64 ) , IS ( 128 ) , IS ( BIO_MAX_PAGES ) ,
} ;
# undef IS
2008-06-30 22:04:41 +04:00
static struct workqueue_struct * kintegrityd_wq ;
2009-06-26 17:37:49 +04:00
static inline unsigned int vecs_to_idx ( unsigned int nr )
{
switch ( nr ) {
case 1 :
return 0 ;
case 2 . . . 4 :
return 1 ;
case 5 . . . 16 :
return 2 ;
case 17 . . . 64 :
return 3 ;
case 65 . . . 128 :
return 4 ;
case 129 . . . BIO_MAX_PAGES :
return 5 ;
default :
BUG ( ) ;
}
}
static inline int use_bip_pool ( unsigned int idx )
{
if ( idx = = BIOVEC_NR_POOLS )
return 1 ;
return 0 ;
}
2008-06-30 22:04:41 +04:00
/**
2009-06-26 17:37:49 +04:00
* bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio
2008-06-30 22:04:41 +04:00
* @ bio : bio to attach integrity metadata to
* @ gfp_mask : Memory allocation mask
* @ nr_vecs : Number of integrity metadata scatter - gather elements
2009-06-26 17:37:49 +04:00
* @ bs : bio_set to allocate from
2008-06-30 22:04:41 +04:00
*
* Description : This function prepares a bio for attaching integrity
* metadata . nr_vecs specifies the maximum number of pages containing
* integrity metadata that can be attached .
*/
2009-06-26 17:37:49 +04:00
struct bio_integrity_payload * bio_integrity_alloc_bioset ( struct bio * bio ,
gfp_t gfp_mask ,
unsigned int nr_vecs ,
struct bio_set * bs )
2008-06-30 22:04:41 +04:00
{
struct bio_integrity_payload * bip ;
2009-06-26 17:37:49 +04:00
unsigned int idx = vecs_to_idx ( nr_vecs ) ;
2008-06-30 22:04:41 +04:00
BUG_ON ( bio = = NULL ) ;
2009-06-26 17:37:49 +04:00
bip = NULL ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
/* Lower order allocations come straight from slab */
if ( ! use_bip_pool ( idx ) )
bip = kmem_cache_alloc ( bip_slab [ idx ] . slab , gfp_mask ) ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
/* Use mempool if lower order alloc failed or max vecs were requested */
if ( bip = = NULL ) {
bip = mempool_alloc ( bs - > bio_integrity_pool , gfp_mask ) ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
if ( unlikely ( bip = = NULL ) ) {
printk ( KERN_ERR " %s: could not alloc bip \n " , __func__ ) ;
return NULL ;
}
2008-06-30 22:04:41 +04:00
}
2009-06-26 17:37:49 +04:00
memset ( bip , 0 , sizeof ( * bip ) ) ;
bip - > bip_slab = idx ;
2008-06-30 22:04:41 +04:00
bip - > bip_bio = bio ;
bio - > bi_integrity = bip ;
return bip ;
}
2009-06-26 17:37:49 +04:00
EXPORT_SYMBOL ( bio_integrity_alloc_bioset ) ;
/**
* bio_integrity_alloc - Allocate integrity payload and attach it to bio
* @ bio : bio to attach integrity metadata to
* @ gfp_mask : Memory allocation mask
* @ nr_vecs : Number of integrity metadata scatter - gather elements
*
* Description : This function prepares a bio for attaching integrity
* metadata . nr_vecs specifies the maximum number of pages containing
* integrity metadata that can be attached .
*/
struct bio_integrity_payload * bio_integrity_alloc ( struct bio * bio ,
gfp_t gfp_mask ,
unsigned int nr_vecs )
{
return bio_integrity_alloc_bioset ( bio , gfp_mask , nr_vecs , fs_bio_set ) ;
}
2008-06-30 22:04:41 +04:00
EXPORT_SYMBOL ( bio_integrity_alloc ) ;
/**
* bio_integrity_free - Free bio integrity payload
* @ bio : bio containing bip to be freed
2009-06-26 17:37:49 +04:00
* @ bs : bio_set this bio was allocated from
2008-06-30 22:04:41 +04:00
*
* Description : Used to free the integrity portion of a bio . Usually
* called from bio_free ( ) .
*/
2009-06-26 17:37:49 +04:00
void bio_integrity_free ( struct bio * bio , struct bio_set * bs )
2008-06-30 22:04:41 +04:00
{
struct bio_integrity_payload * bip = bio - > bi_integrity ;
BUG_ON ( bip = = NULL ) ;
/* A cloned bio doesn't own the integrity metadata */
2008-10-01 11:38:37 +04:00
if ( ! bio_flagged ( bio , BIO_CLONED ) & & ! bio_flagged ( bio , BIO_FS_INTEGRITY )
& & bip - > bip_buf ! = NULL )
2008-06-30 22:04:41 +04:00
kfree ( bip - > bip_buf ) ;
2009-06-26 17:37:49 +04:00
if ( use_bip_pool ( bip - > bip_slab ) )
mempool_free ( bip , bs - > bio_integrity_pool ) ;
else
kmem_cache_free ( bip_slab [ bip - > bip_slab ] . slab , bip ) ;
2008-06-30 22:04:41 +04:00
bio - > bi_integrity = NULL ;
}
EXPORT_SYMBOL ( bio_integrity_free ) ;
/**
* bio_integrity_add_page - Attach integrity metadata
* @ bio : bio to update
* @ page : page containing integrity metadata
* @ len : number of bytes of integrity metadata in page
* @ offset : start offset within page
*
* Description : Attach a page containing integrity metadata to bio .
*/
int bio_integrity_add_page ( struct bio * bio , struct page * page ,
unsigned int len , unsigned int offset )
{
struct bio_integrity_payload * bip = bio - > bi_integrity ;
struct bio_vec * iv ;
2009-06-26 17:37:49 +04:00
if ( bip - > bip_vcnt > = bvec_nr_vecs ( bip - > bip_slab ) ) {
2008-06-30 22:04:41 +04:00
printk ( KERN_ERR " %s: bip_vec full \n " , __func__ ) ;
return 0 ;
}
iv = bip_vec_idx ( bip , bip - > bip_vcnt ) ;
BUG_ON ( iv = = NULL ) ;
iv - > bv_page = page ;
iv - > bv_len = len ;
iv - > bv_offset = offset ;
bip - > bip_vcnt + + ;
return len ;
}
EXPORT_SYMBOL ( bio_integrity_add_page ) ;
2008-09-18 20:31:53 +04:00
static int bdev_integrity_enabled ( struct block_device * bdev , int rw )
{
struct blk_integrity * bi = bdev_get_integrity ( bdev ) ;
if ( bi = = NULL )
return 0 ;
if ( rw = = READ & & bi - > verify_fn ! = NULL & &
( bi - > flags & INTEGRITY_FLAG_READ ) )
return 1 ;
if ( rw = = WRITE & & bi - > generate_fn ! = NULL & &
( bi - > flags & INTEGRITY_FLAG_WRITE ) )
return 1 ;
return 0 ;
}
2008-06-30 22:04:41 +04:00
/**
* bio_integrity_enabled - Check whether integrity can be passed
* @ bio : bio to check
*
* Description : Determines whether bio_integrity_prep ( ) can be called
* on this bio or not . bio data direction and target device must be
* set prior to calling . The functions honors the write_generate and
* read_verify flags in sysfs .
*/
int bio_integrity_enabled ( struct bio * bio )
{
/* Already protected? */
if ( bio_integrity ( bio ) )
return 0 ;
return bdev_integrity_enabled ( bio - > bi_bdev , bio_data_dir ( bio ) ) ;
}
EXPORT_SYMBOL ( bio_integrity_enabled ) ;
/**
* bio_integrity_hw_sectors - Convert 512 b sectors to hardware ditto
* @ bi : blk_integrity profile for device
* @ sectors : Number of 512 sectors to convert
*
* Description : The block layer calculates everything in 512 byte
* sectors but integrity metadata is done in terms of the hardware
* sector size of the storage device . Convert the block layer sectors
* to physical sectors .
*/
2008-06-17 21:05:48 +04:00
static inline unsigned int bio_integrity_hw_sectors ( struct blk_integrity * bi ,
unsigned int sectors )
2008-06-30 22:04:41 +04:00
{
/* At this point there are only 512b or 4096b DIF/EPP devices */
if ( bi - > sector_size = = 4096 )
return sectors > > = 3 ;
return sectors ;
}
/**
* bio_integrity_tag_size - Retrieve integrity tag space
* @ bio : bio to inspect
*
* Description : Returns the maximum number of tag bytes that can be
* attached to this bio . Filesystems can use this to determine how
* much metadata to attach to an I / O .
*/
unsigned int bio_integrity_tag_size ( struct bio * bio )
{
struct blk_integrity * bi = bdev_get_integrity ( bio - > bi_bdev ) ;
BUG_ON ( bio - > bi_size = = 0 ) ;
return bi - > tag_size * ( bio - > bi_size / bi - > sector_size ) ;
}
EXPORT_SYMBOL ( bio_integrity_tag_size ) ;
int bio_integrity_tag ( struct bio * bio , void * tag_buf , unsigned int len , int set )
{
struct bio_integrity_payload * bip = bio - > bi_integrity ;
struct blk_integrity * bi = bdev_get_integrity ( bio - > bi_bdev ) ;
unsigned int nr_sectors ;
BUG_ON ( bip - > bip_buf = = NULL ) ;
if ( bi - > tag_size = = 0 )
return - 1 ;
2008-06-17 21:05:48 +04:00
nr_sectors = bio_integrity_hw_sectors ( bi ,
DIV_ROUND_UP ( len , bi - > tag_size ) ) ;
2008-06-30 22:04:41 +04:00
if ( nr_sectors * bi - > tuple_size > bip - > bip_size ) {
printk ( KERN_ERR " %s: tag too big for bio: %u > %u \n " ,
__func__ , nr_sectors * bi - > tuple_size , bip - > bip_size ) ;
return - 1 ;
}
if ( set )
bi - > set_tag_fn ( bip - > bip_buf , tag_buf , nr_sectors ) ;
else
bi - > get_tag_fn ( bip - > bip_buf , tag_buf , nr_sectors ) ;
return 0 ;
}
/**
* bio_integrity_set_tag - Attach a tag buffer to a bio
* @ bio : bio to attach buffer to
* @ tag_buf : Pointer to a buffer containing tag data
* @ len : Length of the included buffer
*
* Description : Use this function to tag a bio by leveraging the extra
* space provided by devices formatted with integrity protection . The
* size of the integrity buffer must be < = to the size reported by
* bio_integrity_tag_size ( ) .
*/
int bio_integrity_set_tag ( struct bio * bio , void * tag_buf , unsigned int len )
{
BUG_ON ( bio_data_dir ( bio ) ! = WRITE ) ;
return bio_integrity_tag ( bio , tag_buf , len , 1 ) ;
}
EXPORT_SYMBOL ( bio_integrity_set_tag ) ;
/**
* bio_integrity_get_tag - Retrieve a tag buffer from a bio
* @ bio : bio to retrieve buffer from
* @ tag_buf : Pointer to a buffer for the tag data
* @ len : Length of the target buffer
*
* Description : Use this function to retrieve the tag buffer from a
* completed I / O . The size of the integrity buffer must be < = to the
* size reported by bio_integrity_tag_size ( ) .
*/
int bio_integrity_get_tag ( struct bio * bio , void * tag_buf , unsigned int len )
{
BUG_ON ( bio_data_dir ( bio ) ! = READ ) ;
return bio_integrity_tag ( bio , tag_buf , len , 0 ) ;
}
EXPORT_SYMBOL ( bio_integrity_get_tag ) ;
/**
* bio_integrity_generate - Generate integrity metadata for a bio
* @ bio : bio to generate integrity metadata for
*
* Description : Generates integrity metadata for a bio by calling the
* block device ' s generation callback function . The bio must have a
* bip attached with enough room to accommodate the generated
* integrity metadata .
*/
static void bio_integrity_generate ( struct bio * bio )
{
struct blk_integrity * bi = bdev_get_integrity ( bio - > bi_bdev ) ;
struct blk_integrity_exchg bix ;
struct bio_vec * bv ;
sector_t sector = bio - > bi_sector ;
unsigned int i , sectors , total ;
void * prot_buf = bio - > bi_integrity - > bip_buf ;
total = 0 ;
bix . disk_name = bio - > bi_bdev - > bd_disk - > disk_name ;
bix . sector_size = bi - > sector_size ;
bio_for_each_segment ( bv , bio , i ) {
void * kaddr = kmap_atomic ( bv - > bv_page , KM_USER0 ) ;
bix . data_buf = kaddr + bv - > bv_offset ;
bix . data_size = bv - > bv_len ;
bix . prot_buf = prot_buf ;
bix . sector = sector ;
bi - > generate_fn ( & bix ) ;
sectors = bv - > bv_len / bi - > sector_size ;
sector + = sectors ;
prot_buf + = sectors * bi - > tuple_size ;
total + = sectors * bi - > tuple_size ;
BUG_ON ( total > bio - > bi_integrity - > bip_size ) ;
kunmap_atomic ( kaddr , KM_USER0 ) ;
}
}
2008-09-18 20:31:53 +04:00
static inline unsigned short blk_integrity_tuple_size ( struct blk_integrity * bi )
{
if ( bi )
return bi - > tuple_size ;
return 0 ;
}
2008-06-30 22:04:41 +04:00
/**
* bio_integrity_prep - Prepare bio for integrity I / O
* @ bio : bio to prepare
*
* Description : Allocates a buffer for integrity metadata , maps the
* pages and attaches them to a bio . The bio must have data
* direction , target device and start sector set priot to calling . In
* the WRITE case , integrity metadata will be generated using the
* block device ' s integrity function . In the READ case , the buffer
* will be prepared for DMA and a suitable end_io handler set up .
*/
int bio_integrity_prep ( struct bio * bio )
{
struct bio_integrity_payload * bip ;
struct blk_integrity * bi ;
struct request_queue * q ;
void * buf ;
unsigned long start , end ;
unsigned int len , nr_pages ;
unsigned int bytes , offset , i ;
unsigned int sectors ;
bi = bdev_get_integrity ( bio - > bi_bdev ) ;
q = bdev_get_queue ( bio - > bi_bdev ) ;
BUG_ON ( bi = = NULL ) ;
BUG_ON ( bio_integrity ( bio ) ) ;
sectors = bio_integrity_hw_sectors ( bi , bio_sectors ( bio ) ) ;
/* Allocate kernel buffer for protection data */
len = sectors * blk_integrity_tuple_size ( bi ) ;
buf = kmalloc ( len , GFP_NOIO | __GFP_NOFAIL | q - > bounce_gfp ) ;
if ( unlikely ( buf = = NULL ) ) {
printk ( KERN_ERR " could not allocate integrity buffer \n " ) ;
return - EIO ;
}
end = ( ( ( unsigned long ) buf ) + len + PAGE_SIZE - 1 ) > > PAGE_SHIFT ;
start = ( ( unsigned long ) buf ) > > PAGE_SHIFT ;
nr_pages = end - start ;
/* Allocate bio integrity payload and integrity vectors */
bip = bio_integrity_alloc ( bio , GFP_NOIO , nr_pages ) ;
if ( unlikely ( bip = = NULL ) ) {
printk ( KERN_ERR " could not allocate data integrity bioset \n " ) ;
kfree ( buf ) ;
return - EIO ;
}
bip - > bip_buf = buf ;
bip - > bip_size = len ;
bip - > bip_sector = bio - > bi_sector ;
/* Map it */
offset = offset_in_page ( buf ) ;
for ( i = 0 ; i < nr_pages ; i + + ) {
int ret ;
bytes = PAGE_SIZE - offset ;
if ( len < = 0 )
break ;
if ( bytes > len )
bytes = len ;
ret = bio_integrity_add_page ( bio , virt_to_page ( buf ) ,
bytes , offset ) ;
if ( ret = = 0 )
return 0 ;
if ( ret < bytes )
break ;
buf + = bytes ;
len - = bytes ;
offset = 0 ;
}
/* Install custom I/O completion handler if read verify is enabled */
if ( bio_data_dir ( bio ) = = READ ) {
bip - > bip_end_io = bio - > bi_end_io ;
bio - > bi_end_io = bio_integrity_endio ;
}
/* Auto-generate integrity metadata if this is a write */
if ( bio_data_dir ( bio ) = = WRITE )
bio_integrity_generate ( bio ) ;
return 0 ;
}
EXPORT_SYMBOL ( bio_integrity_prep ) ;
/**
* bio_integrity_verify - Verify integrity metadata for a bio
* @ bio : bio to verify
*
* Description : This function is called to verify the integrity of a
* bio . The data in the bio io_vec is compared to the integrity
* metadata returned by the HBA .
*/
static int bio_integrity_verify ( struct bio * bio )
{
struct blk_integrity * bi = bdev_get_integrity ( bio - > bi_bdev ) ;
struct blk_integrity_exchg bix ;
struct bio_vec * bv ;
sector_t sector = bio - > bi_integrity - > bip_sector ;
unsigned int i , sectors , total , ret ;
void * prot_buf = bio - > bi_integrity - > bip_buf ;
ret = total = 0 ;
bix . disk_name = bio - > bi_bdev - > bd_disk - > disk_name ;
bix . sector_size = bi - > sector_size ;
bio_for_each_segment ( bv , bio , i ) {
void * kaddr = kmap_atomic ( bv - > bv_page , KM_USER0 ) ;
bix . data_buf = kaddr + bv - > bv_offset ;
bix . data_size = bv - > bv_len ;
bix . prot_buf = prot_buf ;
bix . sector = sector ;
ret = bi - > verify_fn ( & bix ) ;
if ( ret ) {
kunmap_atomic ( kaddr , KM_USER0 ) ;
2009-01-04 10:43:38 +03:00
return ret ;
2008-06-30 22:04:41 +04:00
}
sectors = bv - > bv_len / bi - > sector_size ;
sector + = sectors ;
prot_buf + = sectors * bi - > tuple_size ;
total + = sectors * bi - > tuple_size ;
BUG_ON ( total > bio - > bi_integrity - > bip_size ) ;
kunmap_atomic ( kaddr , KM_USER0 ) ;
}
return ret ;
}
/**
* bio_integrity_verify_fn - Integrity I / O completion worker
* @ work : Work struct stored in bio to be verified
*
* Description : This workqueue function is called to complete a READ
* request . The function verifies the transferred integrity metadata
* and then calls the original bio end_io function .
*/
static void bio_integrity_verify_fn ( struct work_struct * work )
{
2008-06-17 21:05:48 +04:00
struct bio_integrity_payload * bip =
2008-06-30 22:04:41 +04:00
container_of ( work , struct bio_integrity_payload , bip_work ) ;
struct bio * bio = bip - > bip_bio ;
2009-01-04 10:43:38 +03:00
int error ;
2008-06-30 22:04:41 +04:00
2009-01-04 10:43:38 +03:00
error = bio_integrity_verify ( bio ) ;
2008-06-30 22:04:41 +04:00
/* Restore original bio completion handler */
bio - > bi_end_io = bip - > bip_end_io ;
2009-01-04 10:43:38 +03:00
bio_endio ( bio , error ) ;
2008-06-30 22:04:41 +04:00
}
/**
* bio_integrity_endio - Integrity I / O completion function
* @ bio : Protected bio
* @ error : Pointer to errno
*
* Description : Completion for integrity I / O
*
* Normally I / O completion is done in interrupt context . However ,
* verifying I / O integrity is a time - consuming task which must be run
* in process context . This function postpones completion
* accordingly .
*/
void bio_integrity_endio ( struct bio * bio , int error )
{
struct bio_integrity_payload * bip = bio - > bi_integrity ;
BUG_ON ( bip - > bip_bio ! = bio ) ;
2009-01-04 10:43:38 +03:00
/* In case of an I/O error there is no point in verifying the
* integrity metadata . Restore original bio end_io handler
* and run it .
*/
if ( error ) {
bio - > bi_end_io = bip - > bip_end_io ;
bio_endio ( bio , error ) ;
return ;
}
2008-06-30 22:04:41 +04:00
INIT_WORK ( & bip - > bip_work , bio_integrity_verify_fn ) ;
queue_work ( kintegrityd_wq , & bip - > bip_work ) ;
}
EXPORT_SYMBOL ( bio_integrity_endio ) ;
/**
* bio_integrity_mark_head - Advance bip_vec skip bytes
* @ bip : Integrity vector to advance
* @ skip : Number of bytes to advance it
*/
2008-06-17 21:05:48 +04:00
void bio_integrity_mark_head ( struct bio_integrity_payload * bip ,
unsigned int skip )
2008-06-30 22:04:41 +04:00
{
struct bio_vec * iv ;
unsigned int i ;
bip_for_each_vec ( iv , bip , i ) {
if ( skip = = 0 ) {
bip - > bip_idx = i ;
return ;
} else if ( skip > = iv - > bv_len ) {
skip - = iv - > bv_len ;
} else { /* skip < iv->bv_len) */
iv - > bv_offset + = skip ;
iv - > bv_len - = skip ;
bip - > bip_idx = i ;
return ;
}
}
}
/**
* bio_integrity_mark_tail - Truncate bip_vec to be len bytes long
* @ bip : Integrity vector to truncate
* @ len : New length of integrity vector
*/
2008-06-17 21:05:48 +04:00
void bio_integrity_mark_tail ( struct bio_integrity_payload * bip ,
unsigned int len )
2008-06-30 22:04:41 +04:00
{
struct bio_vec * iv ;
unsigned int i ;
bip_for_each_vec ( iv , bip , i ) {
if ( len = = 0 ) {
bip - > bip_vcnt = i ;
return ;
} else if ( len > = iv - > bv_len ) {
len - = iv - > bv_len ;
} else { /* len < iv->bv_len) */
iv - > bv_len = len ;
len = 0 ;
}
}
}
/**
* bio_integrity_advance - Advance integrity vector
* @ bio : bio whose integrity vector to update
* @ bytes_done : number of data bytes that have been completed
*
* Description : This function calculates how many integrity bytes the
* number of completed data bytes correspond to and advances the
* integrity vector accordingly .
*/
void bio_integrity_advance ( struct bio * bio , unsigned int bytes_done )
{
struct bio_integrity_payload * bip = bio - > bi_integrity ;
struct blk_integrity * bi = bdev_get_integrity ( bio - > bi_bdev ) ;
unsigned int nr_sectors ;
BUG_ON ( bip = = NULL ) ;
BUG_ON ( bi = = NULL ) ;
nr_sectors = bio_integrity_hw_sectors ( bi , bytes_done > > 9 ) ;
bio_integrity_mark_head ( bip , nr_sectors * bi - > tuple_size ) ;
}
EXPORT_SYMBOL ( bio_integrity_advance ) ;
/**
* bio_integrity_trim - Trim integrity vector
* @ bio : bio whose integrity vector to update
* @ offset : offset to first data sector
* @ sectors : number of data sectors
*
* Description : Used to trim the integrity vector in a cloned bio .
* The ivec will be advanced corresponding to ' offset ' data sectors
* and the length will be truncated corresponding to ' len ' data
* sectors .
*/
2008-06-17 21:05:48 +04:00
void bio_integrity_trim ( struct bio * bio , unsigned int offset ,
unsigned int sectors )
2008-06-30 22:04:41 +04:00
{
struct bio_integrity_payload * bip = bio - > bi_integrity ;
struct blk_integrity * bi = bdev_get_integrity ( bio - > bi_bdev ) ;
unsigned int nr_sectors ;
BUG_ON ( bip = = NULL ) ;
BUG_ON ( bi = = NULL ) ;
BUG_ON ( ! bio_flagged ( bio , BIO_CLONED ) ) ;
nr_sectors = bio_integrity_hw_sectors ( bi , sectors ) ;
bip - > bip_sector = bip - > bip_sector + offset ;
bio_integrity_mark_head ( bip , offset * bi - > tuple_size ) ;
bio_integrity_mark_tail ( bip , sectors * bi - > tuple_size ) ;
}
EXPORT_SYMBOL ( bio_integrity_trim ) ;
/**
* bio_integrity_split - Split integrity metadata
* @ bio : Protected bio
* @ bp : Resulting bio_pair
* @ sectors : Offset
*
* Description : Splits an integrity page into a bio_pair .
*/
void bio_integrity_split ( struct bio * bio , struct bio_pair * bp , int sectors )
{
struct blk_integrity * bi ;
struct bio_integrity_payload * bip = bio - > bi_integrity ;
unsigned int nr_sectors ;
if ( bio_integrity ( bio ) = = 0 )
return ;
bi = bdev_get_integrity ( bio - > bi_bdev ) ;
BUG_ON ( bi = = NULL ) ;
BUG_ON ( bip - > bip_vcnt ! = 1 ) ;
nr_sectors = bio_integrity_hw_sectors ( bi , sectors ) ;
bp - > bio1 . bi_integrity = & bp - > bip1 ;
bp - > bio2 . bi_integrity = & bp - > bip2 ;
bp - > iv1 = bip - > bip_vec [ 0 ] ;
bp - > iv2 = bip - > bip_vec [ 0 ] ;
2009-06-26 17:37:49 +04:00
bp - > bip1 . bip_vec [ 0 ] = bp - > iv1 ;
bp - > bip2 . bip_vec [ 0 ] = bp - > iv2 ;
2008-06-30 22:04:41 +04:00
bp - > iv1 . bv_len = sectors * bi - > tuple_size ;
bp - > iv2 . bv_offset + = sectors * bi - > tuple_size ;
bp - > iv2 . bv_len - = sectors * bi - > tuple_size ;
bp - > bip1 . bip_sector = bio - > bi_integrity - > bip_sector ;
bp - > bip2 . bip_sector = bio - > bi_integrity - > bip_sector + nr_sectors ;
bp - > bip1 . bip_vcnt = bp - > bip2 . bip_vcnt = 1 ;
bp - > bip1 . bip_idx = bp - > bip2 . bip_idx = 0 ;
}
EXPORT_SYMBOL ( bio_integrity_split ) ;
/**
* bio_integrity_clone - Callback for cloning bios with integrity metadata
* @ bio : New bio
* @ bio_src : Original bio
2009-03-09 12:40:52 +03:00
* @ gfp_mask : Memory allocation mask
2009-06-26 17:37:49 +04:00
* @ bs : bio_set to allocate bip from
2008-06-30 22:04:41 +04:00
*
* Description : Called to allocate a bip when cloning a bio
*/
2009-06-26 17:37:49 +04:00
int bio_integrity_clone ( struct bio * bio , struct bio * bio_src ,
gfp_t gfp_mask , struct bio_set * bs )
2008-06-30 22:04:41 +04:00
{
struct bio_integrity_payload * bip_src = bio_src - > bi_integrity ;
struct bio_integrity_payload * bip ;
BUG_ON ( bip_src = = NULL ) ;
2009-06-26 17:37:49 +04:00
bip = bio_integrity_alloc_bioset ( bio , gfp_mask , bip_src - > bip_vcnt , bs ) ;
2008-06-30 22:04:41 +04:00
if ( bip = = NULL )
return - EIO ;
memcpy ( bip - > bip_vec , bip_src - > bip_vec ,
bip_src - > bip_vcnt * sizeof ( struct bio_vec ) ) ;
bip - > bip_sector = bip_src - > bip_sector ;
bip - > bip_vcnt = bip_src - > bip_vcnt ;
bip - > bip_idx = bip_src - > bip_idx ;
return 0 ;
}
EXPORT_SYMBOL ( bio_integrity_clone ) ;
2009-06-26 17:37:49 +04:00
int bioset_integrity_create ( struct bio_set * bs , int pool_size )
2008-06-30 22:04:41 +04:00
{
2009-06-26 17:37:49 +04:00
unsigned int max_slab = vecs_to_idx ( BIO_MAX_PAGES ) ;
bs - > bio_integrity_pool =
mempool_create_slab_pool ( pool_size , bip_slab [ max_slab ] . slab ) ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
if ( ! bs - > bio_integrity_pool )
return - 1 ;
return 0 ;
}
EXPORT_SYMBOL ( bioset_integrity_create ) ;
void bioset_integrity_free ( struct bio_set * bs )
{
if ( bs - > bio_integrity_pool )
mempool_destroy ( bs - > bio_integrity_pool ) ;
}
EXPORT_SYMBOL ( bioset_integrity_free ) ;
void __init bio_integrity_init ( void )
{
unsigned int i ;
kintegrityd_wq = create_workqueue ( " kintegrityd " ) ;
2009-03-10 10:27:39 +03:00
if ( ! kintegrityd_wq )
panic ( " Failed to create kintegrityd \n " ) ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
for ( i = 0 ; i < BIOVEC_NR_POOLS ; i + + ) {
unsigned int size ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
size = sizeof ( struct bio_integrity_payload )
+ bip_slab [ i ] . nr_vecs * sizeof ( struct bio_vec ) ;
2008-06-30 22:04:41 +04:00
2009-06-26 17:37:49 +04:00
bip_slab [ i ] . slab =
kmem_cache_create ( bip_slab [ i ] . name , size , 0 ,
SLAB_HWCACHE_ALIGN | SLAB_PANIC , NULL ) ;
}
2008-06-30 22:04:41 +04:00
}