Commit eb384b55 authored by Josef Bacik's avatar Josef Bacik

Btrfs: fix extent logging with O_DIRECT into prealloc

This is the same as the fix from commit

Btrfs: fix bad extent logging

but for O_DIRECT.  I missed this when I fixed the problem originally, we were
still using the em for the orig_start and orig_block_len, which would be the
merged extent.  We need to use the actual extent from the on disk file extent
item, which we have to lookup to make sure it's ok to nocow anyway so just pass
in some pointers to hold this info.  Thanks,

Cc: stable@vger.kernel.org
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent 416bc658
...@@ -6504,7 +6504,9 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode, ...@@ -6504,7 +6504,9 @@ static struct extent_map *btrfs_new_extent_direct(struct inode *inode,
* block must be cow'd * block must be cow'd
*/ */
static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
struct inode *inode, u64 offset, u64 len) struct inode *inode, u64 offset, u64 *len,
u64 *orig_start, u64 *orig_block_len,
u64 *ram_bytes)
{ {
struct btrfs_path *path; struct btrfs_path *path;
int ret; int ret;
...@@ -6561,8 +6563,12 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, ...@@ -6561,8 +6563,12 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
backref_offset = btrfs_file_extent_offset(leaf, fi); backref_offset = btrfs_file_extent_offset(leaf, fi);
*orig_start = key.offset - backref_offset;
*orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi);
*ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
if (extent_end < offset + len) { if (extent_end < offset + *len) {
/* extent doesn't include our full range, must cow */ /* extent doesn't include our full range, must cow */
goto out; goto out;
} }
...@@ -6586,13 +6592,14 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans, ...@@ -6586,13 +6592,14 @@ static noinline int can_nocow_odirect(struct btrfs_trans_handle *trans,
*/ */
disk_bytenr += backref_offset; disk_bytenr += backref_offset;
disk_bytenr += offset - key.offset; disk_bytenr += offset - key.offset;
num_bytes = min(offset + len, extent_end) - offset; num_bytes = min(offset + *len, extent_end) - offset;
if (csum_exist_in_range(root, disk_bytenr, num_bytes)) if (csum_exist_in_range(root, disk_bytenr, num_bytes))
goto out; goto out;
/* /*
* all of the above have passed, it is safe to overwrite this extent * all of the above have passed, it is safe to overwrite this extent
* without cow * without cow
*/ */
*len = num_bytes;
ret = 1; ret = 1;
out: out:
btrfs_free_path(path); btrfs_free_path(path);
...@@ -6790,7 +6797,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -6790,7 +6797,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
em->block_start != EXTENT_MAP_HOLE)) { em->block_start != EXTENT_MAP_HOLE)) {
int type; int type;
int ret; int ret;
u64 block_start; u64 block_start, orig_start, orig_block_len, ram_bytes;
if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags))
type = BTRFS_ORDERED_PREALLOC; type = BTRFS_ORDERED_PREALLOC;
...@@ -6808,11 +6815,8 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, ...@@ -6808,11 +6815,8 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
if (IS_ERR(trans)) if (IS_ERR(trans))
goto must_cow; goto must_cow;
if (can_nocow_odirect(trans, inode, start, len) == 1) { if (can_nocow_odirect(trans, inode, start, &len, &orig_start,
u64 orig_start = em->orig_start; &orig_block_len, &ram_bytes) == 1) {
u64 orig_block_len = em->orig_block_len;
u64 ram_bytes = em->ram_bytes;
if (type == BTRFS_ORDERED_PREALLOC) { if (type == BTRFS_ORDERED_PREALLOC) {
free_extent_map(em); free_extent_map(em);
em = create_pinned_em(inode, start, len, em = create_pinned_em(inode, start, len,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment