2007-06-12 17:07:21 +04:00
/*
* Copyright ( C ) 2007 Oracle . All rights reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public
* License v2 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 ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 021110 - 1307 , USA .
*/
2008-02-20 20:07:25 +03:00
# include <linux/bio.h>
# include <linux/pagemap.h>
# include <linux/highmem.h>
2007-03-16 02:03:33 +03:00
# include "ctree.h"
2007-03-27 00:00:06 +04:00
# include "disk-io.h"
2007-03-20 21:38:32 +03:00
# include "transaction.h"
2007-05-29 23:17:08 +04:00
# include "print-tree.h"
2007-03-16 02:03:33 +03:00
2007-04-16 17:22:45 +04:00
# define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \
2007-05-10 20:36:17 +04:00
sizeof ( struct btrfs_item ) * 2 ) / \
BTRFS_CRC32_SIZE ) - 1 ) )
2007-04-17 21:26:50 +04:00
int btrfs_insert_file_extent ( struct btrfs_trans_handle * trans ,
2008-05-02 22:43:14 +04:00
struct btrfs_root * root ,
u64 objectid , u64 pos ,
u64 disk_offset , u64 disk_num_bytes ,
u64 num_bytes , u64 offset )
2007-03-20 21:38:32 +03:00
{
2007-03-27 00:00:06 +04:00
int ret = 0 ;
struct btrfs_file_extent_item * item ;
struct btrfs_key file_key ;
2007-04-02 19:20:42 +04:00
struct btrfs_path * path ;
2007-10-16 00:14:19 +04:00
struct extent_buffer * leaf ;
2007-03-27 00:00:06 +04:00
2007-04-02 19:20:42 +04:00
path = btrfs_alloc_path ( ) ;
BUG_ON ( ! path ) ;
2007-03-27 00:00:06 +04:00
file_key . objectid = objectid ;
2007-04-17 21:26:50 +04:00
file_key . offset = pos ;
2007-03-27 00:00:06 +04:00
btrfs_set_key_type ( & file_key , BTRFS_EXTENT_DATA_KEY ) ;
2007-04-02 19:20:42 +04:00
ret = btrfs_insert_empty_item ( trans , root , path , & file_key ,
2007-03-27 00:00:06 +04:00
sizeof ( * item ) ) ;
2007-06-22 22:16:25 +04:00
if ( ret < 0 )
goto out ;
2007-03-27 19:26:26 +04:00
BUG_ON ( ret ) ;
2007-10-16 00:14:19 +04:00
leaf = path - > nodes [ 0 ] ;
item = btrfs_item_ptr ( leaf , path - > slots [ 0 ] ,
2007-03-27 00:00:06 +04:00
struct btrfs_file_extent_item ) ;
2008-05-02 22:43:14 +04:00
btrfs_set_file_extent_disk_bytenr ( leaf , item , disk_offset ) ;
2007-10-16 00:15:53 +04:00
btrfs_set_file_extent_disk_num_bytes ( leaf , item , disk_num_bytes ) ;
2008-05-02 22:43:14 +04:00
btrfs_set_file_extent_offset ( leaf , item , offset ) ;
2007-10-16 00:15:53 +04:00
btrfs_set_file_extent_num_bytes ( leaf , item , num_bytes ) ;
2007-10-16 00:14:19 +04:00
btrfs_set_file_extent_generation ( leaf , item , trans - > transid ) ;
btrfs_set_file_extent_type ( leaf , item , BTRFS_FILE_EXTENT_REG ) ;
btrfs_mark_buffer_dirty ( leaf ) ;
2007-06-22 22:16:25 +04:00
out :
2007-04-02 19:20:42 +04:00
btrfs_free_path ( path ) ;
2007-06-22 22:16:25 +04:00
return ret ;
2007-03-20 21:38:32 +03:00
}
2007-03-27 00:00:06 +04:00
2007-04-17 21:26:50 +04:00
struct btrfs_csum_item * btrfs_lookup_csum ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root ,
struct btrfs_path * path ,
u64 objectid , u64 offset ,
int cow )
2007-04-16 17:22:45 +04:00
{
int ret ;
struct btrfs_key file_key ;
struct btrfs_key found_key ;
struct btrfs_csum_item * item ;
2007-10-16 00:14:19 +04:00
struct extent_buffer * leaf ;
2007-04-16 17:22:45 +04:00
u64 csum_offset = 0 ;
2007-04-19 00:15:28 +04:00
int csums_in_item ;
2007-04-16 17:22:45 +04:00
file_key . objectid = objectid ;
file_key . offset = offset ;
btrfs_set_key_type ( & file_key , BTRFS_CSUM_ITEM_KEY ) ;
2007-04-17 21:26:50 +04:00
ret = btrfs_search_slot ( trans , root , & file_key , path , 0 , cow ) ;
2007-04-16 17:22:45 +04:00
if ( ret < 0 )
goto fail ;
2007-10-16 00:14:19 +04:00
leaf = path - > nodes [ 0 ] ;
2007-04-16 17:22:45 +04:00
if ( ret > 0 ) {
ret = 1 ;
2007-04-17 23:39:32 +04:00
if ( path - > slots [ 0 ] = = 0 )
2007-04-16 17:22:45 +04:00
goto fail ;
path - > slots [ 0 ] - - ;
2007-10-16 00:14:19 +04:00
btrfs_item_key_to_cpu ( leaf , & found_key , path - > slots [ 0 ] ) ;
2007-04-16 17:22:45 +04:00
if ( btrfs_key_type ( & found_key ) ! = BTRFS_CSUM_ITEM_KEY | |
found_key . objectid ! = objectid ) {
goto fail ;
}
csum_offset = ( offset - found_key . offset ) > >
root - > fs_info - > sb - > s_blocksize_bits ;
2007-10-16 00:14:19 +04:00
csums_in_item = btrfs_item_size_nr ( leaf , path - > slots [ 0 ] ) ;
2007-05-10 20:36:17 +04:00
csums_in_item / = BTRFS_CRC32_SIZE ;
2007-04-19 00:15:28 +04:00
if ( csum_offset > = csums_in_item ) {
ret = - EFBIG ;
2007-04-16 17:22:45 +04:00
goto fail ;
}
}
item = btrfs_item_ptr ( leaf , path - > slots [ 0 ] , struct btrfs_csum_item ) ;
2007-05-10 20:36:17 +04:00
item = ( struct btrfs_csum_item * ) ( ( unsigned char * ) item +
csum_offset * BTRFS_CRC32_SIZE ) ;
2007-04-16 17:22:45 +04:00
return item ;
fail :
if ( ret > 0 )
2007-04-17 21:26:50 +04:00
ret = - ENOENT ;
2007-04-16 17:22:45 +04:00
return ERR_PTR ( ret ) ;
}
2007-03-27 00:00:06 +04:00
int btrfs_lookup_file_extent ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root ,
struct btrfs_path * path , u64 objectid ,
2007-03-27 19:26:26 +04:00
u64 offset , int mod )
2007-03-27 00:00:06 +04:00
{
int ret ;
struct btrfs_key file_key ;
int ins_len = mod < 0 ? - 1 : 0 ;
int cow = mod ! = 0 ;
file_key . objectid = objectid ;
2007-04-17 23:39:32 +04:00
file_key . offset = offset ;
2007-03-27 00:00:06 +04:00
btrfs_set_key_type ( & file_key , BTRFS_EXTENT_DATA_KEY ) ;
ret = btrfs_search_slot ( trans , root , & file_key , path , ins_len , cow ) ;
return ret ;
}
2007-03-29 23:15:27 +04:00
2008-08-05 07:17:27 +04:00
#if 0 /* broken */
2008-07-31 23:42:53 +04:00
int btrfs_lookup_bio_sums ( struct btrfs_root * root , struct inode * inode ,
struct bio * bio )
{
u32 sum ;
struct bio_vec * bvec = bio - > bi_io_vec ;
int bio_index = 0 ;
u64 offset ;
u64 item_start_offset = 0 ;
u64 item_last_offset = 0 ;
u32 diff ;
int ret ;
struct btrfs_path * path ;
struct btrfs_csum_item * item = NULL ;
struct extent_io_tree * io_tree = & BTRFS_I ( inode ) - > io_tree ;
path = btrfs_alloc_path ( ) ;
WARN_ON ( bio - > bi_vcnt < = 0 ) ;
while ( bio_index < bio - > bi_vcnt ) {
offset = page_offset ( bvec - > bv_page ) + bvec - > bv_offset ;
ret = btrfs_find_ordered_sum ( inode , offset , & sum ) ;
if ( ret = = 0 )
goto found ;
if ( ! item | | offset < item_start_offset | |
offset > = item_last_offset ) {
struct btrfs_key found_key ;
u32 item_size ;
if ( item )
btrfs_release_path ( root , path ) ;
item = btrfs_lookup_csum ( NULL , root , path ,
inode - > i_ino , offset , 0 ) ;
if ( IS_ERR ( item ) ) {
ret = PTR_ERR ( item ) ;
if ( ret = = - ENOENT | | ret = = - EFBIG )
ret = 0 ;
sum = 0 ;
printk ( " no csum found for inode %lu start "
" %llu \n " , inode - > i_ino ,
( unsigned long long ) offset ) ;
2008-08-04 16:35:53 +04:00
item = NULL ;
2008-07-31 23:42:53 +04:00
goto found ;
}
btrfs_item_key_to_cpu ( path - > nodes [ 0 ] , & found_key ,
path - > slots [ 0 ] ) ;
item_start_offset = found_key . offset ;
item_size = btrfs_item_size_nr ( path - > nodes [ 0 ] ,
path - > slots [ 0 ] ) ;
item_last_offset = item_start_offset +
( item_size / BTRFS_CRC32_SIZE ) *
root - > sectorsize ;
item = btrfs_item_ptr ( path - > nodes [ 0 ] , path - > slots [ 0 ] ,
struct btrfs_csum_item ) ;
}
/*
* this byte range must be able to fit inside
* a single leaf so it will also fit inside a u32
*/
diff = offset - item_start_offset ;
diff = diff / root - > sectorsize ;
diff = diff * BTRFS_CRC32_SIZE ;
read_extent_buffer ( path - > nodes [ 0 ] , & sum ,
2008-08-05 07:17:27 +04:00
( ( unsigned long ) item ) + diff ,
2008-07-31 23:42:53 +04:00
BTRFS_CRC32_SIZE ) ;
found :
set_state_private ( io_tree , offset , sum ) ;
bio_index + + ;
bvec + + ;
}
btrfs_free_path ( path ) ;
return 0 ;
}
2008-08-05 07:17:27 +04:00
# endif
2008-07-31 23:42:53 +04:00
2008-07-18 14:17:13 +04:00
int btrfs_csum_one_bio ( struct btrfs_root * root , struct inode * inode ,
struct bio * bio )
2008-04-16 19:15:20 +04:00
{
2008-07-17 20:53:50 +04:00
struct btrfs_ordered_sum * sums ;
struct btrfs_sector_sum * sector_sum ;
2008-07-18 14:17:13 +04:00
struct btrfs_ordered_extent * ordered ;
2008-04-16 19:15:20 +04:00
char * data ;
struct bio_vec * bvec = bio - > bi_io_vec ;
int bio_index = 0 ;
2008-07-18 14:17:13 +04:00
unsigned long total_bytes = 0 ;
unsigned long this_sum_bytes = 0 ;
u64 offset ;
2008-04-16 19:15:20 +04:00
2008-07-17 20:53:50 +04:00
WARN_ON ( bio - > bi_vcnt < = 0 ) ;
sums = kzalloc ( btrfs_ordered_sum_size ( root , bio - > bi_size ) , GFP_NOFS ) ;
2008-04-16 19:15:20 +04:00
if ( ! sums )
return - ENOMEM ;
2008-07-18 14:17:13 +04:00
2008-07-23 07:06:42 +04:00
sector_sum = sums - > sums ;
2008-07-18 14:17:13 +04:00
sums - > file_offset = page_offset ( bvec - > bv_page ) + bvec - > bv_offset ;
2008-07-17 20:53:50 +04:00
sums - > len = bio - > bi_size ;
INIT_LIST_HEAD ( & sums - > list ) ;
2008-07-18 14:17:13 +04:00
ordered = btrfs_lookup_ordered_extent ( inode , sums - > file_offset ) ;
BUG_ON ( ! ordered ) ;
2008-04-16 19:15:20 +04:00
while ( bio_index < bio - > bi_vcnt ) {
2008-07-18 14:17:13 +04:00
offset = page_offset ( bvec - > bv_page ) + bvec - > bv_offset ;
2008-07-19 04:42:20 +04:00
if ( offset > = ordered - > file_offset + ordered - > len | |
offset < ordered - > file_offset ) {
2008-07-18 14:17:13 +04:00
unsigned long bytes_left ;
sums - > len = this_sum_bytes ;
this_sum_bytes = 0 ;
btrfs_add_ordered_sum ( inode , ordered , sums ) ;
btrfs_put_ordered_extent ( ordered ) ;
bytes_left = bio - > bi_size - total_bytes ;
sums = kzalloc ( btrfs_ordered_sum_size ( root , bytes_left ) ,
GFP_NOFS ) ;
BUG_ON ( ! sums ) ;
2008-07-23 07:06:42 +04:00
sector_sum = sums - > sums ;
2008-07-18 14:17:13 +04:00
sums - > len = bytes_left ;
sums - > file_offset = offset ;
ordered = btrfs_lookup_ordered_extent ( inode ,
sums - > file_offset ) ;
BUG_ON ( ! ordered ) ;
}
2008-04-16 19:15:20 +04:00
data = kmap_atomic ( bvec - > bv_page , KM_USER0 ) ;
2008-07-17 20:53:50 +04:00
sector_sum - > sum = ~ ( u32 ) 0 ;
sector_sum - > sum = btrfs_csum_data ( root ,
data + bvec - > bv_offset ,
sector_sum - > sum ,
bvec - > bv_len ) ;
2008-04-16 19:15:20 +04:00
kunmap_atomic ( data , KM_USER0 ) ;
2008-07-17 20:53:50 +04:00
btrfs_csum_final ( sector_sum - > sum ,
( char * ) & sector_sum - > sum ) ;
sector_sum - > offset = page_offset ( bvec - > bv_page ) +
bvec - > bv_offset ;
2008-07-23 07:06:42 +04:00
2008-07-17 20:53:50 +04:00
sector_sum + + ;
2008-04-16 19:15:20 +04:00
bio_index + + ;
2008-07-18 14:17:13 +04:00
total_bytes + = bvec - > bv_len ;
this_sum_bytes + = bvec - > bv_len ;
2008-04-16 19:15:20 +04:00
bvec + + ;
}
2008-07-23 07:06:42 +04:00
this_sum_bytes = 0 ;
2008-07-18 14:17:13 +04:00
btrfs_add_ordered_sum ( inode , ordered , sums ) ;
btrfs_put_ordered_extent ( ordered ) ;
2008-04-16 19:15:20 +04:00
return 0 ;
}
2008-02-20 20:07:25 +03:00
int btrfs_csum_file_blocks ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root , struct inode * inode ,
2008-07-17 20:53:50 +04:00
struct btrfs_ordered_sum * sums )
2007-03-29 23:15:27 +04:00
{
2008-02-20 20:07:25 +03:00
u64 objectid = inode - > i_ino ;
u64 offset ;
2007-03-29 23:15:27 +04:00
int ret ;
struct btrfs_key file_key ;
2007-04-16 17:22:45 +04:00
struct btrfs_key found_key ;
2008-02-20 20:07:25 +03:00
u64 next_offset ;
2008-07-17 20:53:50 +04:00
u64 total_bytes = 0 ;
2008-02-20 20:07:25 +03:00
int found_next ;
2007-04-02 19:20:42 +04:00
struct btrfs_path * path ;
2007-03-29 23:15:27 +04:00
struct btrfs_csum_item * item ;
2008-02-20 20:07:25 +03:00
struct btrfs_csum_item * item_end ;
2007-10-16 00:22:25 +04:00
struct extent_buffer * leaf = NULL ;
2007-04-16 17:22:45 +04:00
u64 csum_offset ;
2008-07-17 20:53:50 +04:00
struct btrfs_sector_sum * sector_sum ;
2007-10-25 23:42:56 +04:00
u32 nritems ;
u32 ins_size ;
2008-02-20 20:07:25 +03:00
char * eb_map ;
char * eb_token ;
unsigned long map_len ;
unsigned long map_start ;
2007-04-02 19:20:42 +04:00
path = btrfs_alloc_path ( ) ;
BUG_ON ( ! path ) ;
2008-07-23 07:06:42 +04:00
sector_sum = sums - > sums ;
2008-02-20 20:07:25 +03:00
again :
next_offset = ( u64 ) - 1 ;
found_next = 0 ;
2008-07-17 20:53:50 +04:00
offset = sector_sum - > offset ;
2007-03-29 23:15:27 +04:00
file_key . objectid = objectid ;
file_key . offset = offset ;
btrfs_set_key_type ( & file_key , BTRFS_CSUM_ITEM_KEY ) ;
2007-04-19 00:15:28 +04:00
2008-08-15 23:34:18 +04:00
mutex_lock ( & BTRFS_I ( inode ) - > csum_mutex ) ;
2007-04-19 00:15:28 +04:00
item = btrfs_lookup_csum ( trans , root , path , objectid , offset , 1 ) ;
2007-10-16 00:22:25 +04:00
if ( ! IS_ERR ( item ) ) {
leaf = path - > nodes [ 0 ] ;
2007-04-19 00:15:28 +04:00
goto found ;
2007-10-16 00:22:25 +04:00
}
2007-04-19 00:15:28 +04:00
ret = PTR_ERR ( item ) ;
if ( ret = = - EFBIG ) {
u32 item_size ;
/* we found one, but it isn't big enough yet */
2007-10-16 00:14:19 +04:00
leaf = path - > nodes [ 0 ] ;
item_size = btrfs_item_size_nr ( leaf , path - > slots [ 0 ] ) ;
2007-05-10 20:36:17 +04:00
if ( ( item_size / BTRFS_CRC32_SIZE ) > = MAX_CSUM_ITEMS ( root ) ) {
2007-04-19 00:15:28 +04:00
/* already at max size, make a new one */
goto insert ;
}
} else {
2007-10-25 23:42:56 +04:00
int slot = path - > slots [ 0 ] + 1 ;
2007-04-19 00:15:28 +04:00
/* we didn't find a csum item, insert one */
2007-10-25 23:42:56 +04:00
nritems = btrfs_header_nritems ( path - > nodes [ 0 ] ) ;
if ( path - > slots [ 0 ] > = nritems - 1 ) {
ret = btrfs_next_leaf ( root , path ) ;
2007-10-29 19:01:05 +03:00
if ( ret = = 1 )
2007-10-25 23:42:56 +04:00
found_next = 1 ;
2007-10-29 19:01:05 +03:00
if ( ret ! = 0 )
2007-10-25 23:42:56 +04:00
goto insert ;
2007-10-29 19:01:05 +03:00
slot = 0 ;
2007-10-25 23:42:56 +04:00
}
btrfs_item_key_to_cpu ( path - > nodes [ 0 ] , & found_key , slot ) ;
if ( found_key . objectid ! = objectid | |
found_key . type ! = BTRFS_CSUM_ITEM_KEY ) {
found_next = 1 ;
goto insert ;
}
next_offset = found_key . offset ;
found_next = 1 ;
2007-04-19 00:15:28 +04:00
goto insert ;
}
/*
* at this point , we know the tree has an item , but it isn ' t big
* enough yet to put our csum in . Grow it
*/
btrfs_release_path ( root , path ) ;
2007-04-16 17:22:45 +04:00
ret = btrfs_search_slot ( trans , root , & file_key , path ,
2007-05-10 20:36:17 +04:00
BTRFS_CRC32_SIZE , 1 ) ;
2007-04-16 17:22:45 +04:00
if ( ret < 0 )
2008-08-15 23:34:18 +04:00
goto fail_unlock ;
2007-04-16 17:22:45 +04:00
if ( ret = = 0 ) {
2007-04-17 21:26:50 +04:00
BUG ( ) ;
2007-04-16 17:22:45 +04:00
}
if ( path - > slots [ 0 ] = = 0 ) {
goto insert ;
}
path - > slots [ 0 ] - - ;
2007-10-16 00:14:19 +04:00
leaf = path - > nodes [ 0 ] ;
btrfs_item_key_to_cpu ( leaf , & found_key , path - > slots [ 0 ] ) ;
2007-04-16 17:22:45 +04:00
csum_offset = ( offset - found_key . offset ) > >
root - > fs_info - > sb - > s_blocksize_bits ;
if ( btrfs_key_type ( & found_key ) ! = BTRFS_CSUM_ITEM_KEY | |
found_key . objectid ! = objectid | |
csum_offset > = MAX_CSUM_ITEMS ( root ) ) {
goto insert ;
}
2007-10-16 00:14:19 +04:00
if ( csum_offset > = btrfs_item_size_nr ( leaf , path - > slots [ 0 ] ) /
2007-05-10 20:36:17 +04:00
BTRFS_CRC32_SIZE ) {
u32 diff = ( csum_offset + 1 ) * BTRFS_CRC32_SIZE ;
2007-10-16 00:14:19 +04:00
diff = diff - btrfs_item_size_nr ( leaf , path - > slots [ 0 ] ) ;
2007-05-24 21:35:57 +04:00
if ( diff ! = BTRFS_CRC32_SIZE )
goto insert ;
2007-04-19 00:15:28 +04:00
ret = btrfs_extend_item ( trans , root , path , diff ) ;
2007-04-16 17:22:45 +04:00
BUG_ON ( ret ) ;
goto csum ;
}
insert :
2007-04-19 00:15:28 +04:00
btrfs_release_path ( root , path ) ;
2007-04-16 17:22:45 +04:00
csum_offset = 0 ;
2007-10-25 23:42:56 +04:00
if ( found_next ) {
u64 tmp = min ( ( u64 ) i_size_read ( inode ) , next_offset ) ;
2007-10-29 19:01:05 +03:00
tmp - = offset & ~ ( ( u64 ) root - > sectorsize - 1 ) ;
2007-10-25 23:42:56 +04:00
tmp > > = root - > fs_info - > sb - > s_blocksize_bits ;
tmp = max ( ( u64 ) 1 , tmp ) ;
tmp = min ( tmp , ( u64 ) MAX_CSUM_ITEMS ( root ) ) ;
ins_size = BTRFS_CRC32_SIZE * tmp ;
} else {
ins_size = BTRFS_CRC32_SIZE ;
}
2007-04-02 19:20:42 +04:00
ret = btrfs_insert_empty_item ( trans , root , path , & file_key ,
2007-10-25 23:42:56 +04:00
ins_size ) ;
2007-06-22 22:16:25 +04:00
if ( ret < 0 )
2008-08-15 23:34:18 +04:00
goto fail_unlock ;
2007-04-19 00:15:28 +04:00
if ( ret ! = 0 ) {
WARN_ON ( 1 ) ;
2008-08-15 23:34:18 +04:00
goto fail_unlock ;
2007-04-19 00:15:28 +04:00
}
2007-04-16 17:22:45 +04:00
csum :
2007-10-16 00:14:19 +04:00
leaf = path - > nodes [ 0 ] ;
item = btrfs_item_ptr ( leaf , path - > slots [ 0 ] , struct btrfs_csum_item ) ;
2007-03-29 23:15:27 +04:00
ret = 0 ;
2007-05-10 20:36:17 +04:00
item = ( struct btrfs_csum_item * ) ( ( unsigned char * ) item +
csum_offset * BTRFS_CRC32_SIZE ) ;
2007-04-17 21:26:50 +04:00
found :
2008-02-20 20:07:25 +03:00
item_end = btrfs_item_ptr ( leaf , path - > slots [ 0 ] , struct btrfs_csum_item ) ;
item_end = ( struct btrfs_csum_item * ) ( ( unsigned char * ) item_end +
btrfs_item_size_nr ( leaf , path - > slots [ 0 ] ) ) ;
2008-02-20 20:07:25 +03:00
eb_token = NULL ;
2008-08-15 23:34:18 +04:00
mutex_unlock ( & BTRFS_I ( inode ) - > csum_mutex ) ;
cond_resched ( ) ;
2008-07-17 20:53:50 +04:00
next_sector :
2008-01-29 17:10:27 +03:00
2008-02-20 20:07:25 +03:00
if ( ! eb_token | |
( unsigned long ) item + BTRFS_CRC32_SIZE > = map_start + map_len ) {
int err ;
if ( eb_token )
2008-02-21 17:30:08 +03:00
unmap_extent_buffer ( leaf , eb_token , KM_USER1 ) ;
2008-02-20 20:07:25 +03:00
eb_token = NULL ;
err = map_private_extent_buffer ( leaf , ( unsigned long ) item ,
BTRFS_CRC32_SIZE ,
& eb_token , & eb_map ,
2008-02-21 17:30:08 +03:00
& map_start , & map_len , KM_USER1 ) ;
2008-02-20 20:07:25 +03:00
if ( err )
eb_token = NULL ;
}
if ( eb_token ) {
memcpy ( eb_token + ( ( unsigned long ) item & ( PAGE_CACHE_SIZE - 1 ) ) ,
2008-07-17 20:53:50 +04:00
& sector_sum - > sum , BTRFS_CRC32_SIZE ) ;
2008-02-20 20:07:25 +03:00
} else {
2008-07-17 20:53:50 +04:00
write_extent_buffer ( leaf , & sector_sum - > sum ,
( unsigned long ) item , BTRFS_CRC32_SIZE ) ;
2008-02-20 20:07:25 +03:00
}
2008-07-18 20:01:11 +04:00
2008-07-17 20:53:50 +04:00
total_bytes + = root - > sectorsize ;
sector_sum + + ;
if ( total_bytes < sums - > len ) {
2008-02-20 20:07:25 +03:00
item = ( struct btrfs_csum_item * ) ( ( char * ) item +
BTRFS_CRC32_SIZE ) ;
2008-02-20 23:44:32 +03:00
if ( item < item_end & & offset + PAGE_CACHE_SIZE = =
2008-07-17 20:53:50 +04:00
sector_sum - > offset ) {
offset = sector_sum - > offset ;
goto next_sector ;
2008-02-20 23:44:32 +03:00
}
2008-02-20 20:07:25 +03:00
}
2008-02-20 20:07:25 +03:00
if ( eb_token ) {
2008-02-21 17:30:08 +03:00
unmap_extent_buffer ( leaf , eb_token , KM_USER1 ) ;
2008-02-20 20:07:25 +03:00
eb_token = NULL ;
}
2007-04-02 19:20:42 +04:00
btrfs_mark_buffer_dirty ( path - > nodes [ 0 ] ) ;
2008-08-15 23:34:18 +04:00
cond_resched ( ) ;
2008-07-17 20:53:50 +04:00
if ( total_bytes < sums - > len ) {
2008-02-20 20:07:25 +03:00
btrfs_release_path ( root , path ) ;
goto again ;
}
2008-08-15 23:34:18 +04:00
out :
2007-04-02 19:20:42 +04:00
btrfs_free_path ( path ) ;
2007-03-29 23:15:27 +04:00
return ret ;
2008-08-15 23:34:18 +04:00
fail_unlock :
mutex_unlock ( & BTRFS_I ( inode ) - > csum_mutex ) ;
goto out ;
2007-03-29 23:15:27 +04:00
}
2007-05-29 23:17:08 +04:00
int btrfs_csum_truncate ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root , struct btrfs_path * path ,
u64 isize )
{
struct btrfs_key key ;
2007-10-16 00:14:19 +04:00
struct extent_buffer * leaf = path - > nodes [ 0 ] ;
2007-05-29 23:17:08 +04:00
int slot = path - > slots [ 0 ] ;
int ret ;
u32 new_item_size ;
u64 new_item_span ;
u64 blocks ;
2007-10-16 00:14:19 +04:00
btrfs_item_key_to_cpu ( leaf , & key , slot ) ;
2007-05-29 23:17:08 +04:00
if ( isize < = key . offset )
return 0 ;
new_item_span = isize - key . offset ;
2007-10-16 00:14:19 +04:00
blocks = ( new_item_span + root - > sectorsize - 1 ) > >
2007-06-12 15:43:08 +04:00
root - > fs_info - > sb - > s_blocksize_bits ;
2007-05-29 23:17:08 +04:00
new_item_size = blocks * BTRFS_CRC32_SIZE ;
2007-10-16 00:14:19 +04:00
if ( new_item_size > = btrfs_item_size_nr ( leaf , slot ) )
2007-05-29 23:17:08 +04:00
return 0 ;
2007-11-01 18:28:41 +03:00
ret = btrfs_truncate_item ( trans , root , path , new_item_size , 1 ) ;
2007-05-29 23:17:08 +04:00
BUG_ON ( ret ) ;
return ret ;
}