diff options
author | Yan <yanzheng@21cn.com> | 2008-01-04 10:38:22 -0500 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2008-01-04 10:38:22 -0500 |
commit | 7777e63b425f1444d2472ea05a6b2b9cf865f35b (patch) | |
tree | 257d9645b094cd3bae9051f7bb5b24d862764bf4 /file-item.c | |
parent | 088f78aeaadac6cc877975c6974731968c0093d1 (diff) |
Update btrfs-progs to match kernel sources
Diffstat (limited to 'file-item.c')
-rw-r--r-- | file-item.c | 328 |
1 files changed, 227 insertions, 101 deletions
diff --git a/file-item.c b/file-item.c index 9d119cf2..26399013 100644 --- a/file-item.c +++ b/file-item.c @@ -23,6 +23,7 @@ #include "ctree.h" #include "disk-io.h" #include "transaction.h" +#include "print-tree.h" #include "crc32c.h" #define MAX_CSUM_ITEMS(r) ((((BTRFS_LEAF_DATA_SIZE(r) - \ @@ -35,86 +36,169 @@ int btrfs_create_file(struct btrfs_trans_handle *trans, } 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 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; + struct btrfs_path *path; + struct extent_buffer *leaf; - - btrfs_init_path(&path); + path = btrfs_alloc_path(); + BUG_ON(!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, + 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], + leaf = path->nodes[0]; + 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); + btrfs_set_file_extent_disk_bytenr(leaf, item, 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_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); + btrfs_mark_buffer_dirty(leaf); out: - btrfs_release_path(root, &path); + btrfs_free_path(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 btrfs_insert_inline_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_path *path; + struct extent_buffer *leaf; + unsigned long ptr; struct btrfs_file_extent_item *ei; + u32 datasize; + int err = 0; + int ret; + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; - 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; + ret = btrfs_search_slot(trans, root, &key, path, 0, 1); + if (ret < 0) { + err = ret; + goto fail; + } + if (ret == 1) { + struct btrfs_key found_key; + + if (path->slots[0] == 0) + goto insert; + + path->slots[0]--; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid != objectid) + goto insert; + + if (found_key.type != BTRFS_EXTENT_DATA_KEY) + goto insert; + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + + if (btrfs_file_extent_type(leaf, ei) != + BTRFS_FILE_EXTENT_INLINE) { + goto insert; + } + btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); + ret = 0; + } + if (ret == 0) { + u32 found_size; + u64 found_end; + + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + + if (btrfs_file_extent_type(leaf, ei) != + BTRFS_FILE_EXTENT_INLINE) { + err = ret; + btrfs_print_leaf(root, leaf); + printk("found wasn't inline offset %llu inode %llu\n", + offset, objectid); + goto fail; + } + found_size = btrfs_file_extent_inline_len(leaf, + btrfs_item_nr(leaf, path->slots[0])); + found_end = key.offset + found_size; + + if (found_end < offset + size) { + btrfs_release_path(root, path); + ret = btrfs_search_slot(trans, root, &key, path, + offset + size - found_end, 1); + BUG_ON(ret != 0); + + ret = btrfs_extend_item(trans, root, path, + offset + size - found_end); + if (ret) { + err = ret; + goto fail; + } + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + } + if (found_end < offset) { + ptr = btrfs_file_extent_inline_start(ei) + found_size; + memset_extent_buffer(leaf, 0, ptr, offset - found_end); + } + } else { +insert: + btrfs_release_path(root, path); + datasize = offset + size - key.offset; + datasize = btrfs_file_extent_calc_inline_size(datasize); + ret = btrfs_insert_empty_item(trans, root, path, &key, + datasize); + if (ret) { + err = ret; + printk("got bad ret %d\n", ret); + goto fail; + } + leaf = path->nodes[0]; + ei = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + btrfs_set_file_extent_generation(leaf, ei, trans->transid); + btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); + } + ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset; + write_extent_buffer(leaf, buffer, ptr, size); + btrfs_mark_buffer_dirty(leaf); +fail: + btrfs_free_path(path); + return err; } -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) +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) { int ret; - int slot; struct btrfs_key file_key; struct btrfs_key found_key; struct btrfs_csum_item *item; - struct btrfs_leaf *leaf; + struct extent_buffer *leaf; u64 csum_offset = 0; int csums_in_item; @@ -124,35 +208,51 @@ int btrfs_lookup_csum(struct btrfs_trans_handle *trans, ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); if (ret < 0) goto fail; - leaf = &path->nodes[0]->leaf; + leaf = path->nodes[0]; if (ret > 0) { + ret = 1; 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); + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 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]); + csum_offset = (offset - found_key.offset) >> root->sectorsize; + csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); 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; + return item; fail: if (ret > 0) ret = -ENOENT; + return ERR_PTR(ret); +} + + +int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, + struct btrfs_root *root, + struct btrfs_path *path, u64 objectid, + u64 offset, int mod) +{ + int ret; + struct btrfs_key file_key; + int ins_len = mod < 0 ? -1 : 0; + int cow = mod != 0; + + file_key.objectid = objectid; + file_key.offset = offset; + btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY); + ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); return ret; } @@ -163,56 +263,53 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, 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_path *path; struct btrfs_csum_item *item; - struct btrfs_leaf *leaf = NULL; + struct extent_buffer *leaf = NULL; u64 csum_offset; u32 csum_result = ~(u32)0; u32 nritems; u32 ins_size; - btrfs_init_path(&path); + path = btrfs_alloc_path(); + BUG_ON(!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; + item = btrfs_lookup_csum(trans, root, path, objectid, offset, 1); + if (!IS_ERR(item)) { + leaf = path->nodes[0]; goto found; } - if (ret != -EFBIG && ret != -ENOENT) - goto fail; - leaf = &path.nodes[0]->leaf; + ret = PTR_ERR(item); 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]); + leaf = path->nodes[0]; + item_size = btrfs_item_size_nr(leaf, path->slots[0]); 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; + int 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); + nritems = btrfs_header_nritems(path->nodes[0]); + 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); + 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; @@ -227,68 +324,97 @@ int btrfs_csum_file_block(struct btrfs_trans_handle *trans, * 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_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) { + if (ret == 0) { + BUG(); + } + 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); + path->slots[0]--; + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 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]) / + if (csum_offset >= btrfs_item_size_nr(leaf, path->slots[0]) / BTRFS_CRC32_SIZE) { u32 diff = (csum_offset + 1) * BTRFS_CRC32_SIZE; - diff = diff - btrfs_item_size(&leaf->items[slot]); + diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); if (diff != BTRFS_CRC32_SIZE) goto insert; - ret = btrfs_extend_item(trans, root, &path, diff); + ret = btrfs_extend_item(trans, root, path, diff); BUG_ON(ret); goto csum; } insert: - btrfs_release_path(root, &path); + 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; + u64 tmp = min(btrfs_stack_inode_size(inode), next_offset); + tmp -= offset & ~((u64)root->sectorsize -1); tmp /= root->sectorsize; - if (tmp > MAX_CSUM_ITEMS(root)) - tmp = MAX_CSUM_ITEMS(root); + 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; } - ret = btrfs_insert_empty_item(trans, root, &path, &file_key, + ret = btrfs_insert_empty_item(trans, root, path, &file_key, ins_size); if (ret < 0) goto fail; - BUG_ON(ret != 0); + if (ret != 0) { + WARN_ON(1); + goto fail; + } csum: - slot = path.slots[0]; - leaf = &path.nodes[0]->leaf; - item = btrfs_item_ptr(leaf, slot, struct btrfs_csum_item); + leaf = path->nodes[0]; + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); + ret = 0; 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; + 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); + btrfs_mark_buffer_dirty(path->nodes[0]); fail: - btrfs_release_path(root, &path); + btrfs_release_path(root, path); + btrfs_free_path(path); + return ret; +} + +int btrfs_csum_truncate(struct btrfs_trans_handle *trans, + struct btrfs_root *root, struct btrfs_path *path, + u64 isize) +{ + struct btrfs_key key; + struct extent_buffer *leaf = path->nodes[0]; + int slot = path->slots[0]; + int ret; + u32 new_item_size; + u64 new_item_span; + u64 blocks; + + btrfs_item_key_to_cpu(leaf, &key, slot); + if (isize <= key.offset) + return 0; + new_item_span = isize - key.offset; + blocks = (new_item_span + root->sectorsize - 1) / root->sectorsize; + new_item_size = blocks * BTRFS_CRC32_SIZE; + if (new_item_size >= btrfs_item_size_nr(leaf, slot)) + return 0; + ret = btrfs_truncate_item(trans, root, path, new_item_size, 1); + BUG_ON(ret); return ret; } |