X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=fs%2Fbtrfs%2Ffile-item.c;h=f537eb43c2c60df79f195cdbce329bbd5af7cf05;hb=a74a4b97b61beede185b4b3ad359d7d378b0d312;hp=614176e5285182938a05917e0b55ea8d7e20d55e;hpb=179e29e488cc74f1e9bd67bc45f70b832740e9ec;p=deliverable%2Flinux.git diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 614176e52851..f537eb43c2c6 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -16,6 +16,9 @@ * Boston, MA 021110-1307, USA. */ +#include +#include +#include #include "ctree.h" #include "disk-io.h" #include "transaction.h" @@ -25,10 +28,10 @@ sizeof(struct btrfs_item) * 2) / \ BTRFS_CRC32_SIZE) - 1)) int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 pos, - u64 offset, u64 disk_num_bytes, - u64 num_bytes) + struct btrfs_root *root, + u64 objectid, u64 pos, + u64 disk_offset, u64 disk_num_bytes, + u64 num_bytes, u64 offset) { int ret = 0; struct btrfs_file_extent_item *item; @@ -50,9 +53,9 @@ int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, leaf = path->nodes[0]; item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_file_extent_item); - btrfs_set_file_extent_disk_bytenr(leaf, item, offset); + btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); - btrfs_set_file_extent_offset(leaf, item, 0); + btrfs_set_file_extent_offset(leaf, item, offset); btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); btrfs_set_file_extent_generation(leaf, item, trans->transid); btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); @@ -131,28 +134,65 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, return ret; } -int btrfs_csum_file_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - u64 objectid, u64 offset, - char *data, size_t len) +int btrfs_csum_one_bio(struct btrfs_root *root, + struct bio *bio, char **sums_ret) { + u32 *sums; + char *data; + struct bio_vec *bvec = bio->bi_io_vec; + int bio_index = 0; + + sums = kmalloc(bio->bi_vcnt * BTRFS_CRC32_SIZE, GFP_NOFS); + if (!sums) + return -ENOMEM; + *sums_ret = (char *)sums; + + while(bio_index < bio->bi_vcnt) { + data = kmap_atomic(bvec->bv_page, KM_USER0); + *sums = ~(u32)0; + *sums = btrfs_csum_data(root, data + bvec->bv_offset, + *sums, bvec->bv_len); + kunmap_atomic(data, KM_USER0); + btrfs_csum_final(*sums, (char *)sums); + sums++; + bio_index++; + bvec++; + } + return 0; +} + +int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, + struct btrfs_root *root, struct inode *inode, + struct bio *bio, char *sums) +{ + u64 objectid = inode->i_ino; + u64 offset; int ret; struct btrfs_key file_key; struct btrfs_key found_key; - u64 next_offset = (u64)-1; - int found_next = 0; + u64 next_offset; + int found_next; struct btrfs_path *path; struct btrfs_csum_item *item; + struct btrfs_csum_item *item_end; struct extent_buffer *leaf = NULL; u64 csum_offset; - u32 csum_result = ~(u32)0; + u32 *sums32 = (u32 *)sums; u32 nritems; u32 ins_size; + int bio_index = 0; + struct bio_vec *bvec = bio->bi_io_vec; + char *eb_map; + char *eb_token; + unsigned long map_len; + unsigned long map_start; path = btrfs_alloc_path(); BUG_ON(!path); - +again: + next_offset = (u64)-1; + found_next = 0; + offset = page_offset(bvec->bv_page) + bvec->bv_offset; file_key.objectid = objectid; file_key.offset = offset; btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); @@ -259,13 +299,55 @@ csum: item = (struct btrfs_csum_item *)((unsigned char *)item + csum_offset * BTRFS_CRC32_SIZE); found: - csum_result = btrfs_csum_data(root, data, csum_result, len); - btrfs_csum_final(csum_result, (char *)&csum_result); - write_extent_buffer(leaf, &csum_result, (unsigned long)item, - BTRFS_CRC32_SIZE); + 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])); + eb_token = NULL; +next_bvec: + + if (!eb_token || + (unsigned long)item + BTRFS_CRC32_SIZE >= map_start + map_len) { + int err; + + if (eb_token) + unmap_extent_buffer(leaf, eb_token, KM_USER1); + eb_token = NULL; + err = map_private_extent_buffer(leaf, (unsigned long)item, + BTRFS_CRC32_SIZE, + &eb_token, &eb_map, + &map_start, &map_len, KM_USER1); + if (err) + eb_token = NULL; + } + if (eb_token) { + memcpy(eb_token + ((unsigned long)item & (PAGE_CACHE_SIZE - 1)), + sums32, BTRFS_CRC32_SIZE); + } else { + write_extent_buffer(leaf, sums32, (unsigned long)item, + BTRFS_CRC32_SIZE); + } + bio_index++; + bvec++; + sums32++; + if (bio_index < bio->bi_vcnt) { + item = (struct btrfs_csum_item *)((char *)item + + BTRFS_CRC32_SIZE); + if (item < item_end && offset + PAGE_CACHE_SIZE == + page_offset(bvec->bv_page)) { + offset = page_offset(bvec->bv_page); + goto next_bvec; + } + } + if (eb_token) { + unmap_extent_buffer(leaf, eb_token, KM_USER1); + eb_token = NULL; + } btrfs_mark_buffer_dirty(path->nodes[0]); + if (bio_index < bio->bi_vcnt) { + btrfs_release_path(root, path); + goto again; + } fail: - btrfs_release_path(root, path); btrfs_free_path(path); return ret; }