diff options
author | Yan <yanzheng@21cn.com> | 2007-12-05 10:41:38 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-12-05 10:41:38 -0500 |
commit | 07a4f1b81df6cd9b9e09773f680fc098faed310c (patch) | |
tree | 3543dcbdbe4fd1c153f468d2976bcebc34b72ae7 /file-item.c | |
parent | 1c2b38fe25fe6496d51d41aee7a5a1eb2e2694d8 (diff) |
Update btrfs-progs to better match the kernel
Diffstat (limited to 'file-item.c')
-rw-r--r-- | file-item.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/file-item.c b/file-item.c index 9d0a3544..9d119cf2 100644 --- a/file-item.c +++ b/file-item.c @@ -23,9 +23,272 @@ #include "ctree.h" #include "disk-io.h" #include "transaction.h" +#include "crc32c.h" +#define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ + sizeof(struct btrfs_item) * 2) / \ + BTRFS_CRC32_SIZE) - 1)) int btrfs_create_file(struct btrfs_trans_handle *trans, struct btrfs_root *root, u64 dirid, u64 *objectid) { return 0; } + +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) +{ + int ret = 0; + struct btrfs_file_extent_item *item; + struct btrfs_key file_key; + struct btrfs_path path; + struct btrfs_leaf *leaf; + + + btrfs_init_path(&path); + file_key.objectid = objectid; + file_key.offset = pos; + btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); + + ret = btrfs_insert_empty_item(trans, root, &path, &file_key, + sizeof(*item)); + if (ret < 0) + goto out; + BUG_ON(ret); + leaf = &path.nodes[0]->leaf; + item = btrfs_item_ptr(leaf, path.slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_disk_bytenr(item, offset); + btrfs_set_file_extent_disk_num_bytes(item, disk_num_bytes); + btrfs_set_file_extent_offset(item, 0); + btrfs_set_file_extent_num_bytes(item, num_bytes); + btrfs_set_file_extent_generation(item, trans->transid); + btrfs_set_file_extent_type(item, BTRFS_FILE_EXTENT_REG); +out: + btrfs_release_path(root, &path); + return ret; +} + +int btrfs_insert_inline_file_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, u64 objectid, + u64 offset, char *buffer, size_t size) +{ + int ret; + char *ptr; + u32 datasize; + struct btrfs_key key; + struct btrfs_path path; + struct btrfs_leaf *leaf; + struct btrfs_file_extent_item *ei; + + btrfs_init_path(&path); + key.objectid = objectid; + key.offset = offset; + btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); + + datasize = btrfs_file_extent_calc_inline_size(size); + ret = btrfs_insert_empty_item(trans, root, &path, &key, + datasize); + BUG_ON(ret); + leaf = &path.nodes[0]->leaf; + ei = btrfs_item_ptr(leaf, path.slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_generation(ei, trans->transid); + btrfs_set_file_extent_type(ei, BTRFS_FILE_EXTENT_INLINE); + ptr = btrfs_file_extent_inline_start(ei); + memcpy(ptr, buffer, size); + btrfs_release_path(root, &path); + return 0; +} + +int btrfs_lookup_csum(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, + u64 objectid, u64 offset, int cow, + struct btrfs_csum_item **item_ret) +{ + int ret; + int slot; + struct btrfs_key file_key; + struct btrfs_key found_key; + struct btrfs_csum_item *item; + struct btrfs_leaf *leaf; + u64 csum_offset = 0; + int csums_in_item; + + file_key.objectid = objectid; + file_key.offset = offset; + btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); + ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); + if (ret < 0) + goto fail; + leaf = &path->nodes[0]->leaf; + if (ret > 0) { + if (path->slots[0] == 0) + goto fail; + path->slots[0]--; + + slot = path->slots[0]; + btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key); + if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || + found_key.objectid != objectid) { + goto fail; + } + csum_offset = (offset - found_key.offset) / root->sectorsize; + csums_in_item = btrfs_item_size(&leaf->items[slot]); + csums_in_item /= BTRFS_CRC32_SIZE; + + if (csum_offset >= csums_in_item) { + ret = -EFBIG; + goto fail; + } + ret = 0; + } + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); + item = (struct btrfs_csum_item *)((unsigned char *)item + + csum_offset * BTRFS_CRC32_SIZE); + *item_ret = item; +fail: + if (ret > 0) + ret = -ENOENT; + return ret; +} + +int btrfs_csum_file_block(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_inode_item *inode, + u64 objectid, u64 offset, + char *data, size_t len) +{ + int ret; + int slot; + struct btrfs_key file_key; + struct btrfs_key found_key; + u64 next_offset = (u64)-1; + int found_next = 0; + struct btrfs_path path; + struct btrfs_csum_item *item; + struct btrfs_leaf *leaf = NULL; + u64 csum_offset; + u32 csum_result = ~(u32)0; + u32 nritems; + u32 ins_size; + + btrfs_init_path(&path); + + file_key.objectid = objectid; + file_key.offset = offset; + btrfs_set_key_type(&file_key, BTRFS_CSUM_ITEM_KEY); + + ret = btrfs_lookup_csum(trans, root, &path, objectid, + offset, 1, &item); + if (!ret) { + leaf = &path.nodes[0]->leaf; + goto found; + } + if (ret != -EFBIG && ret != -ENOENT) + goto fail; + leaf = &path.nodes[0]->leaf; + if (ret == -EFBIG) { + u32 item_size; + slot = path.slots[0]; + /* we found one, but it isn't big enough yet */ + item_size = btrfs_item_size(&leaf->items[slot]); + if ((item_size / BTRFS_CRC32_SIZE) >= MAX_CSUM_ITEMS(root)) { + /* already at max size, make a new one */ + goto insert; + } + } else { + slot = path.slots[0] + 1; + /* we didn't find a csum item, insert one */ + nritems = btrfs_header_nritems(&leaf->header); + if (path.slots[0] >= nritems - 1) { + ret = btrfs_next_leaf(root, &path); + if (ret == 1) + found_next = 1; + if (ret != 0) + goto insert; + slot = 0; + } + btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key); + 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; + 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); + ret = btrfs_search_slot(trans, root, &file_key, &path, + BTRFS_CRC32_SIZE, 1); + if (ret < 0) + goto fail; + BUG_ON(ret == 0); + if (path.slots[0] == 0) { + goto insert; + } + path.slots[0]--; + slot = path.slots[0]; + leaf = &path.nodes[0]->leaf; + btrfs_disk_key_to_cpu(&found_key, &leaf->items[slot].key); + csum_offset = (offset - found_key.offset) / root->sectorsize; + if (btrfs_key_type(&found_key) != BTRFS_CSUM_ITEM_KEY || + found_key.objectid != objectid || + csum_offset >= MAX_CSUM_ITEMS(root)) { + goto insert; + } + if (csum_offset >= btrfs_item_size(&leaf->items[slot]) / + BTRFS_CRC32_SIZE) { + u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE; + diff = diff - btrfs_item_size(&leaf->items[slot]); + if (diff != BTRFS_CRC32_SIZE) + goto insert; + ret = btrfs_extend_item(trans, root, &path, diff); + BUG_ON(ret); + goto csum; + } + +insert: + btrfs_release_path(root, &path); + csum_offset = 0; + if (found_next) { + u64 tmp; + if (next_offset > btrfs_inode_size(inode)) + next_offset = btrfs_inode_size(inode); + tmp = next_offset - offset + root->sectorsize - 1; + tmp /= root->sectorsize; + if (tmp > MAX_CSUM_ITEMS(root)) + tmp = MAX_CSUM_ITEMS(root); + ins_size = BTRFS_CRC32_SIZE * tmp; + } else { + ins_size = BTRFS_CRC32_SIZE; + } + ret = btrfs_insert_empty_item(trans, root, &path, &file_key, + ins_size); + if (ret < 0) + goto fail; + BUG_ON(ret != 0); +csum: + slot = path.slots[0]; + leaf = &path.nodes[0]->leaf; + item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item); + item = (struct btrfs_csum_item *)((unsigned char *)item + + csum_offset * BTRFS_CRC32_SIZE); +found: + csum_result = crc32c(csum_result, data, len); + csum_result = ~cpu_to_le32(csum_result); + memcpy(item, &csum_result, BTRFS_CRC32_SIZE); + ret = 0; +fail: + btrfs_release_path(root, &path); + return ret; +} |