diff options
| -rw-r--r-- | fs/btrfs/ctree.h | 6 | ||||
| -rw-r--r-- | fs/btrfs/file-item.c | 76 | ||||
| -rw-r--r-- | fs/btrfs/inode.c | 42 | ||||
| -rw-r--r-- | fs/btrfs/ioctl.c | 69 |
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); |
| 3750 | int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, | 3750 | int 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); |
| 3752 | void 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 */ |
| 3753 | struct btrfs_delalloc_work { | 3759 | struct 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: | |||
| 885 | fail_unlock: | 885 | fail_unlock: |
| 886 | goto out; | 886 | goto out; |
| 887 | } | 887 | } |
| 888 | |||
| 889 | void 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 | ||
| 6148 | again: | 6147 | again: |
| 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 | } |
| 6357 | not_found: | 6323 | not_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 | ||
| 3046 | static 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 | ||
| 3411 | out: | 3480 | out: |
