aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/ctree.h6
-rw-r--r--fs/btrfs/file-item.c76
-rw-r--r--fs/btrfs/inode.c42
-rw-r--r--fs/btrfs/ioctl.c69
4 files changed, 155 insertions, 38 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index af523d695432..b7e2c1c1ef36 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3749,6 +3749,12 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
3749 struct bio *bio, u64 file_start, int contig); 3749 struct bio *bio, u64 file_start, int contig);
3750int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, 3750int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
3751 struct list_head *list, int search_commit); 3751 struct list_head *list, int search_commit);
3752void btrfs_extent_item_to_extent_map(struct inode *inode,
3753 const struct btrfs_path *path,
3754 struct btrfs_file_extent_item *fi,
3755 const bool new_inline,
3756 struct extent_map *em);
3757
3752/* inode.c */ 3758/* inode.c */
3753struct btrfs_delalloc_work { 3759struct btrfs_delalloc_work {
3754 struct inode *inode; 3760 struct inode *inode;
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index 609d56b9fd8e..f46cfe45d686 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -885,3 +885,79 @@ out:
885fail_unlock: 885fail_unlock:
886 goto out; 886 goto out;
887} 887}
888
889void btrfs_extent_item_to_extent_map(struct inode *inode,
890 const struct btrfs_path *path,
891 struct btrfs_file_extent_item *fi,
892 const bool new_inline,
893 struct extent_map *em)
894{
895 struct btrfs_root *root = BTRFS_I(inode)->root;
896 struct extent_buffer *leaf = path->nodes[0];
897 const int slot = path->slots[0];
898 struct btrfs_key key;
899 u64 extent_start, extent_end;
900 u64 bytenr;
901 u8 type = btrfs_file_extent_type(leaf, fi);
902 int compress_type = btrfs_file_extent_compression(leaf, fi);
903
904 em->bdev = root->fs_info->fs_devices->latest_bdev;
905 btrfs_item_key_to_cpu(leaf, &key, slot);
906 extent_start = key.offset;
907
908 if (type == BTRFS_FILE_EXTENT_REG ||
909 type == BTRFS_FILE_EXTENT_PREALLOC) {
910 extent_end = extent_start +
911 btrfs_file_extent_num_bytes(leaf, fi);
912 } else if (type == BTRFS_FILE_EXTENT_INLINE) {
913 size_t size;
914 size = btrfs_file_extent_inline_len(leaf, slot, fi);
915 extent_end = ALIGN(extent_start + size, root->sectorsize);
916 }
917
918 em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
919 if (type == BTRFS_FILE_EXTENT_REG ||
920 type == BTRFS_FILE_EXTENT_PREALLOC) {
921 em->start = extent_start;
922 em->len = extent_end - extent_start;
923 em->orig_start = extent_start -
924 btrfs_file_extent_offset(leaf, fi);
925 em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi);
926 bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
927 if (bytenr == 0) {
928 em->block_start = EXTENT_MAP_HOLE;
929 return;
930 }
931 if (compress_type != BTRFS_COMPRESS_NONE) {
932 set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
933 em->compress_type = compress_type;
934 em->block_start = bytenr;
935 em->block_len = em->orig_block_len;
936 } else {
937 bytenr += btrfs_file_extent_offset(leaf, fi);
938 em->block_start = bytenr;
939 em->block_len = em->len;
940 if (type == BTRFS_FILE_EXTENT_PREALLOC)
941 set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
942 }
943 } else if (type == BTRFS_FILE_EXTENT_INLINE) {
944 em->block_start = EXTENT_MAP_INLINE;
945 em->start = extent_start;
946 em->len = extent_end - extent_start;
947 /*
948 * Initialize orig_start and block_len with the same values
949 * as in inode.c:btrfs_get_extent().
950 */
951 em->orig_start = EXTENT_MAP_HOLE;
952 em->block_len = (u64)-1;
953 if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) {
954 set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
955 em->compress_type = compress_type;
956 }
957 } else {
958 btrfs_err(root->fs_info,
959 "unknown file extent item type %d, inode %llu, offset %llu, root %llu",
960 type, btrfs_ino(inode), extent_start,
961 root->root_key.objectid);
962 }
963}
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 477e64a1146f..372b2cb2b297 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6129,7 +6129,6 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
6129{ 6129{
6130 int ret; 6130 int ret;
6131 int err = 0; 6131 int err = 0;
6132 u64 bytenr;
6133 u64 extent_start = 0; 6132 u64 extent_start = 0;
6134 u64 extent_end = 0; 6133 u64 extent_end = 0;
6135 u64 objectid = btrfs_ino(inode); 6134 u64 objectid = btrfs_ino(inode);
@@ -6143,7 +6142,7 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
6143 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; 6142 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
6144 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; 6143 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
6145 struct btrfs_trans_handle *trans = NULL; 6144 struct btrfs_trans_handle *trans = NULL;
6146 int compress_type; 6145 const bool new_inline = !page || create;
6147 6146
6148again: 6147again:
6149 read_lock(&em_tree->lock); 6148 read_lock(&em_tree->lock);
@@ -6217,7 +6216,6 @@ again:
6217 6216
6218 found_type = btrfs_file_extent_type(leaf, item); 6217 found_type = btrfs_file_extent_type(leaf, item);
6219 extent_start = found_key.offset; 6218 extent_start = found_key.offset;
6220 compress_type = btrfs_file_extent_compression(leaf, item);
6221 if (found_type == BTRFS_FILE_EXTENT_REG || 6219 if (found_type == BTRFS_FILE_EXTENT_REG ||
6222 found_type == BTRFS_FILE_EXTENT_PREALLOC) { 6220 found_type == BTRFS_FILE_EXTENT_PREALLOC) {
6223 extent_end = extent_start + 6221 extent_end = extent_start +
@@ -6252,32 +6250,10 @@ next:
6252 goto not_found_em; 6250 goto not_found_em;
6253 } 6251 }
6254 6252
6255 em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, item); 6253 btrfs_extent_item_to_extent_map(inode, path, item, new_inline, em);
6254
6256 if (found_type == BTRFS_FILE_EXTENT_REG || 6255 if (found_type == BTRFS_FILE_EXTENT_REG ||
6257 found_type == BTRFS_FILE_EXTENT_PREALLOC) { 6256 found_type == BTRFS_FILE_EXTENT_PREALLOC) {
6258 em->start = extent_start;
6259 em->len = extent_end - extent_start;
6260 em->orig_start = extent_start -
6261 btrfs_file_extent_offset(leaf, item);
6262 em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf,
6263 item);
6264 bytenr = btrfs_file_extent_disk_bytenr(leaf, item);
6265 if (bytenr == 0) {
6266 em->block_start = EXTENT_MAP_HOLE;
6267 goto insert;
6268 }
6269 if (compress_type != BTRFS_COMPRESS_NONE) {
6270 set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
6271 em->compress_type = compress_type;
6272 em->block_start = bytenr;
6273 em->block_len = em->orig_block_len;
6274 } else {
6275 bytenr += btrfs_file_extent_offset(leaf, item);
6276 em->block_start = bytenr;
6277 em->block_len = em->len;
6278 if (found_type == BTRFS_FILE_EXTENT_PREALLOC)
6279 set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
6280 }
6281 goto insert; 6257 goto insert;
6282 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { 6258 } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
6283 unsigned long ptr; 6259 unsigned long ptr;
@@ -6286,12 +6262,8 @@ next:
6286 size_t extent_offset; 6262 size_t extent_offset;
6287 size_t copy_size; 6263 size_t copy_size;
6288 6264
6289 em->block_start = EXTENT_MAP_INLINE; 6265 if (new_inline)
6290 if (!page || create) {
6291 em->start = extent_start;
6292 em->len = extent_end - extent_start;
6293 goto out; 6266 goto out;
6294 }
6295 6267
6296 size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); 6268 size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
6297 extent_offset = page_offset(page) + pg_offset - extent_start; 6269 extent_offset = page_offset(page) + pg_offset - extent_start;
@@ -6301,10 +6273,6 @@ next:
6301 em->len = ALIGN(copy_size, root->sectorsize); 6273 em->len = ALIGN(copy_size, root->sectorsize);
6302 em->orig_block_len = em->len; 6274 em->orig_block_len = em->len;
6303 em->orig_start = em->start; 6275 em->orig_start = em->start;
6304 if (compress_type) {
6305 set_bit(EXTENT_FLAG_COMPRESSED, &em->flags);
6306 em->compress_type = compress_type;
6307 }
6308 ptr = btrfs_file_extent_inline_start(item) + extent_offset; 6276 ptr = btrfs_file_extent_inline_start(item) + extent_offset;
6309 if (create == 0 && !PageUptodate(page)) { 6277 if (create == 0 && !PageUptodate(page)) {
6310 if (btrfs_file_extent_compression(leaf, item) != 6278 if (btrfs_file_extent_compression(leaf, item) !=
@@ -6351,8 +6319,6 @@ next:
6351 set_extent_uptodate(io_tree, em->start, 6319 set_extent_uptodate(io_tree, em->start,
6352 extent_map_end(em) - 1, NULL, GFP_NOFS); 6320 extent_map_end(em) - 1, NULL, GFP_NOFS);
6353 goto insert; 6321 goto insert;
6354 } else {
6355 WARN(1, KERN_ERR "btrfs unknown found_type %d\n", found_type);
6356 } 6322 }
6357not_found: 6323not_found:
6358 em->start = start; 6324 em->start = start;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index dd9a02a53c7b..c2e796b664c1 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3043,6 +3043,60 @@ out:
3043 return ret; 3043 return ret;
3044} 3044}
3045 3045
3046static void clone_update_extent_map(struct inode *inode,
3047 const struct btrfs_trans_handle *trans,
3048 const struct btrfs_path *path,
3049 struct btrfs_file_extent_item *fi,
3050 const u64 hole_offset,
3051 const u64 hole_len)
3052{
3053 struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
3054 struct extent_map *em;
3055 int ret;
3056
3057 em = alloc_extent_map();
3058 if (!em) {
3059 set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
3060 &BTRFS_I(inode)->runtime_flags);
3061 return;
3062 }
3063
3064 if (fi) {
3065 btrfs_extent_item_to_extent_map(inode, path, fi, false, em);
3066 em->generation = -1;
3067 if (btrfs_file_extent_type(path->nodes[0], fi) ==
3068 BTRFS_FILE_EXTENT_INLINE)
3069 set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
3070 &BTRFS_I(inode)->runtime_flags);
3071 } else {
3072 em->start = hole_offset;
3073 em->len = hole_len;
3074 em->ram_bytes = em->len;
3075 em->orig_start = hole_offset;
3076 em->block_start = EXTENT_MAP_HOLE;
3077 em->block_len = 0;
3078 em->orig_block_len = 0;
3079 em->compress_type = BTRFS_COMPRESS_NONE;
3080 em->generation = trans->transid;
3081 }
3082
3083 while (1) {
3084 write_lock(&em_tree->lock);
3085 ret = add_extent_mapping(em_tree, em, 1);
3086 write_unlock(&em_tree->lock);
3087 if (ret != -EEXIST) {
3088 free_extent_map(em);
3089 break;
3090 }
3091 btrfs_drop_extent_cache(inode, em->start,
3092 em->start + em->len - 1, 0);
3093 }
3094
3095 if (unlikely(ret))
3096 set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
3097 &BTRFS_I(inode)->runtime_flags);
3098}
3099
3046/** 3100/**
3047 * btrfs_clone() - clone a range from inode file to another 3101 * btrfs_clone() - clone a range from inode file to another
3048 * 3102 *
@@ -3361,8 +3415,19 @@ process_slot:
3361 btrfs_item_ptr_offset(leaf, slot), 3415 btrfs_item_ptr_offset(leaf, slot),
3362 size); 3416 size);
3363 inode_add_bytes(inode, datal); 3417 inode_add_bytes(inode, datal);
3418 extent = btrfs_item_ptr(leaf, slot,
3419 struct btrfs_file_extent_item);
3364 } 3420 }
3365 3421
3422 /* If we have an implicit hole (NO_HOLES feature). */
3423 if (drop_start < new_key.offset)
3424 clone_update_extent_map(inode, trans,
3425 path, NULL, drop_start,
3426 new_key.offset - drop_start);
3427
3428 clone_update_extent_map(inode, trans, path,
3429 extent, 0, 0);
3430
3366 btrfs_mark_buffer_dirty(leaf); 3431 btrfs_mark_buffer_dirty(leaf);
3367 btrfs_release_path(path); 3432 btrfs_release_path(path);
3368 3433
@@ -3406,6 +3471,10 @@ process_slot:
3406 } 3471 }
3407 ret = clone_finish_inode_update(trans, inode, destoff + len, 3472 ret = clone_finish_inode_update(trans, inode, destoff + len,
3408 destoff, olen); 3473 destoff, olen);
3474 if (ret)
3475 goto out;
3476 clone_update_extent_map(inode, trans, path, NULL, last_dest_end,
3477 destoff + len - last_dest_end);
3409 } 3478 }
3410 3479
3411out: 3480out: