diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8edcdf6910f7..4d7c02258390 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -1641,7 +1641,7 @@ static void btrfs_clear_bit_hook(struct inode *inode, | |||
1641 | btrfs_delalloc_release_metadata(inode, len); | 1641 | btrfs_delalloc_release_metadata(inode, len); |
1642 | 1642 | ||
1643 | if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID | 1643 | if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID |
1644 | && do_list) | 1644 | && do_list && !(state->state & EXTENT_NORESERVE)) |
1645 | btrfs_free_reserved_data_space(inode, len); | 1645 | btrfs_free_reserved_data_space(inode, len); |
1646 | 1646 | ||
1647 | __percpu_counter_add(&root->fs_info->delalloc_bytes, -len, | 1647 | __percpu_counter_add(&root->fs_info->delalloc_bytes, -len, |
@@ -6396,10 +6396,10 @@ out: | |||
6396 | * returns 1 when the nocow is safe, < 1 on error, 0 if the | 6396 | * returns 1 when the nocow is safe, < 1 on error, 0 if the |
6397 | * block must be cow'd | 6397 | * block must be cow'd |
6398 | */ | 6398 | */ |
6399 | static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, | 6399 | noinline int can_nocow_extent(struct btrfs_trans_handle *trans, |
6400 | struct inode *inode, u64 offset, u64 *len, | 6400 | struct inode *inode, u64 offset, u64 *len, |
6401 | u64 *orig_start, u64 *orig_block_len, | 6401 | u64 *orig_start, u64 *orig_block_len, |
6402 | u64 *ram_bytes) | 6402 | u64 *ram_bytes) |
6403 | { | 6403 | { |
6404 | struct btrfs_path *path; | 6404 | struct btrfs_path *path; |
6405 | int ret; | 6405 | int ret; |
@@ -6413,7 +6413,7 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, | |||
6413 | u64 num_bytes; | 6413 | u64 num_bytes; |
6414 | int slot; | 6414 | int slot; |
6415 | int found_type; | 6415 | int found_type; |
6416 | 6416 | bool nocow = (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW); | |
6417 | path = btrfs_alloc_path(); | 6417 | path = btrfs_alloc_path(); |
6418 | if (!path) | 6418 | if (!path) |
6419 | return -ENOMEM; | 6419 | return -ENOMEM; |
@@ -6453,18 +6453,28 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, | |||
6453 | /* not a regular extent, must cow */ | 6453 | /* not a regular extent, must cow */ |
6454 | goto out; | 6454 | goto out; |
6455 | } | 6455 | } |
6456 | |||
6457 | if (!nocow && found_type == BTRFS_FILE_EXTENT_REG) | ||
6458 | goto out; | ||
6459 | |||
6456 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); | 6460 | disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); |
6461 | if (disk_bytenr == 0) | ||
6462 | goto out; | ||
6463 | |||
6464 | if (btrfs_file_extent_compression(leaf, fi) || | ||
6465 | btrfs_file_extent_encryption(leaf, fi) || | ||
6466 | btrfs_file_extent_other_encoding(leaf, fi)) | ||
6467 | goto out; | ||
6468 | |||
6457 | backref_offset = btrfs_file_extent_offset(leaf, fi); | 6469 | backref_offset = btrfs_file_extent_offset(leaf, fi); |
6458 | 6470 | ||
6459 | *orig_start = key.offset - backref_offset; | 6471 | if (orig_start) { |
6460 | *orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); | 6472 | *orig_start = key.offset - backref_offset; |
6461 | *ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); | 6473 | *orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); |
6474 | *ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); | ||
6475 | } | ||
6462 | 6476 | ||
6463 | extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); | 6477 | extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); |
6464 | if (extent_end < offset + *len) { | ||
6465 | /* extent doesn't include our full range, must cow */ | ||
6466 | goto out; | ||
6467 | } | ||
6468 | 6478 | ||
6469 | if (btrfs_extent_readonly(root, disk_bytenr)) | 6479 | if (btrfs_extent_readonly(root, disk_bytenr)) |
6470 | goto out; | 6480 | goto out; |
@@ -6708,8 +6718,8 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
6708 | if (IS_ERR(trans)) | 6718 | if (IS_ERR(trans)) |
6709 | goto must_cow; | 6719 | goto must_cow; |
6710 | 6720 | ||
6711 | if (can_nocow_odirect(trans, inode, start, &len, &orig_start, | 6721 | if (can_nocow_extent(trans, inode, start, &len, &orig_start, |
6712 | &orig_block_len, &ram_bytes) == 1) { | 6722 | &orig_block_len, &ram_bytes) == 1) { |
6713 | if (type == BTRFS_ORDERED_PREALLOC) { | 6723 | if (type == BTRFS_ORDERED_PREALLOC) { |
6714 | free_extent_map(em); | 6724 | free_extent_map(em); |
6715 | em = create_pinned_em(inode, start, len, | 6725 | em = create_pinned_em(inode, start, len, |