diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-04-16 09:22:45 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-04-16 09:22:45 -0400 |
commit | 6567e837df07e43bffc08ac40858af8133a007bf (patch) | |
tree | 3bf186544e5cd5d4ef5c755e1e3b8f678f6df198 /fs/btrfs/file-item.c | |
parent | b4100d64241fed93a3f821ddf59d11ab4443a3ba (diff) | |
download | linux-stable-6567e837df07e43bffc08ac40858af8133a007bf.tar.gz linux-stable-6567e837df07e43bffc08ac40858af8133a007bf.tar.bz2 linux-stable-6567e837df07e43bffc08ac40858af8133a007bf.zip |
Btrfs: early work to file_write in big extents
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/file-item.c')
-rw-r--r-- | fs/btrfs/file-item.c | 111 |
1 files changed, 104 insertions, 7 deletions
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index d9fd7f4d3794..93d42d650820 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -3,6 +3,9 @@ #include "disk-io.h" #include "transaction.h" +#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ + sizeof(struct btrfs_item)) / \ + sizeof(struct btrfs_csum_item)) - 1)) int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, @@ -43,6 +46,54 @@ int btrfs_alloc_file_extent(struct btrfs_trans_handle *trans, return 0; } +static struct btrfs_csum_item *__lookup_csum_item(struct btrfs_root *root, + struct btrfs_path *path, + u64 objectid, u64 offset) +{ + int ret; + struct btrfs_key file_key; + struct btrfs_key found_key; + struct btrfs_csum_item *item; + struct btrfs_leaf *leaf; + u64 csum_offset = 0; + + file_key.objectid = objectid; + file_key.offset = offset; + file_key.flags = 0; + btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); + ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0); + if (ret < 0) + goto fail; + leaf = btrfs_buffer_leaf(path->nodes[0]); + if (ret > 0) { + ret = 1; + if (path->slots[0] == 0) + goto fail; + path->slots[0]--; + btrfs_disk_key_to_cpu(&found_key, + &leaf->items[path->slots[0]].key); + 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; + if (csum_offset >= + btrfs_item_size(leaf->items + path->slots[0]) / + sizeof(struct btrfs_csum_item)) { + goto fail; + } + } + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); + item += csum_offset; + return item; +fail: + if (ret > 0) + ret = -EIO; + return ERR_PTR(ret); +} + + int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, struct btrfs_path *path, u64 objectid, @@ -52,11 +103,16 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, struct btrfs_key file_key; int ins_len = mod < 0 ? -1 : 0; int cow = mod != 0; + struct btrfs_csum_item *csum_item; + csum_item = __lookup_csum_item(root, path, objectid, offset); + if (IS_ERR(csum_item)) + return PTR_ERR(csum_item); file_key.objectid = objectid; - file_key.offset = offset; + file_key.offset = btrfs_csum_extent_offset(csum_item); file_key.flags = 0; btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); + btrfs_release_path(root, path); ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); return ret; } @@ -64,12 +120,16 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, int btrfs_csum_file_block(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 objectid, u64 offset, + u64 extent_offset, char *data, size_t len) { int ret; struct btrfs_key file_key; + struct btrfs_key found_key; struct btrfs_path *path; struct btrfs_csum_item *item; + struct btrfs_leaf *leaf; + u64 csum_offset; path = btrfs_alloc_path(); BUG_ON(!path); @@ -78,14 +138,50 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, file_key.offset = offset; file_key.flags = 0; btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); + ret = btrfs_search_slot(trans, root, &file_key, path, + sizeof(struct btrfs_csum_item), 1); + if (ret < 0) + goto fail; + if (ret == 0) { + csum_offset = 0; + goto csum; + } + if (path->slots[0] == 0) { + btrfs_release_path(root, path); + goto insert; + } + path->slots[0]--; + leaf = btrfs_buffer_leaf(path->nodes[0]); + btrfs_disk_key_to_cpu(&found_key, &leaf->items[path->slots[0]].key); + 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)) { + btrfs_release_path(root, path); + goto insert; + } + if (csum_offset >= btrfs_item_size(leaf->items + path->slots[0]) / + sizeof(struct btrfs_csum_item)) { + ret = btrfs_extend_item(trans, root, path, + sizeof(struct btrfs_csum_item)); + BUG_ON(ret); + goto csum; + } + +insert: + csum_offset = 0; ret = btrfs_insert_empty_item(trans, root, path, &file_key, - BTRFS_CSUM_SIZE); + sizeof(struct btrfs_csum_item)); if (ret != 0 && ret != -EEXIST) goto fail; +csum: item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], struct btrfs_csum_item); ret = 0; + item += csum_offset; ret = btrfs_csum_data(root, data, len, item->csum); + btrfs_set_csum_extent_offset(item, extent_offset); btrfs_mark_buffer_dirty(path->nodes[0]); fail: btrfs_release_path(root, path); @@ -111,12 +207,13 @@ int btrfs_csum_verify_file_block(struct btrfs_root *root, file_key.flags = 0; btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); mutex_lock(&root->fs_info->fs_mutex); - ret = btrfs_search_slot(NULL, root, &file_key, path, 0, 0); - if (ret) + + item = __lookup_csum_item(root, path, objectid, offset); + if (IS_ERR(item)) { + ret = PTR_ERR(item); goto fail; - item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], - struct btrfs_csum_item); - ret = 0; + } + ret = btrfs_csum_data(root, data, len, result); WARN_ON(ret); if (memcmp(result, item->csum, BTRFS_CSUM_SIZE)) |