Josef Bacik
2012-Sep-11 19:42 UTC
[PATCH] Btrfs: create a pinned em when writing to a prealloc range in DIO
Wade Cline reported a problem where he was getting garbage and warnings when writing to a preallocated range via O_DIRECT. This is because we weren''t creating our normal pinned extent_map for the range we were writing to, which was causing all sorts of issues. This patch fixes the problem and makes his testcase much happier. Thanks, Reported-by: Wade Cline <clinew@linux.vnet.ibm.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> --- fs/btrfs/inode.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 55 insertions(+), 0 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e7107bd..ccc3310 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6513,6 +6513,48 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, return ret; } +static struct extent_map *create_pinned_em(struct inode *inode, u64 start, + u64 len, u64 orig_start, + u64 block_start, u64 block_len, + int type) +{ + struct extent_map_tree *em_tree; + struct extent_map *em; + struct btrfs_root *root = BTRFS_I(inode)->root; + int ret; + + em_tree = &BTRFS_I(inode)->extent_tree; + em = alloc_extent_map(); + if (!em) + return ERR_PTR(-ENOMEM); + + em->start = start; + em->orig_start = orig_start; + em->len = len; + em->block_len = block_len; + em->block_start = block_start; + em->bdev = root->fs_info->fs_devices->latest_bdev; + set_bit(EXTENT_FLAG_PINNED, &em->flags); + if (type == BTRFS_ORDERED_PREALLOC) + set_bit(EXTENT_FLAG_PREALLOC, &em->flags); + + do { + btrfs_drop_extent_cache(inode, em->start, + em->start + em->len - 1, 0); + write_lock(&em_tree->lock); + ret = add_extent_mapping(em_tree, em); + write_unlock(&em_tree->lock); + } while (ret == -EEXIST); + + if (ret) { + free_extent_map(em); + return ERR_PTR(ret); + } + + return em; +} + + static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { @@ -6627,6 +6669,19 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, goto must_cow; if (can_nocow_odirect(trans, inode, start, len) == 1) { + u64 orig_start = em->start; + + if (type == BTRFS_ORDERED_PREALLOC) { + free_extent_map(em); + em = create_pinned_em(inode, start, len, + orig_start, + block_start, len, type); + if (IS_ERR(em)) { + btrfs_end_transaction(trans, root); + goto unlock_err; + } + } + ret = btrfs_add_ordered_extent_dio(inode, start, block_start, len, len, type); btrfs_end_transaction(trans, root); -- 1.7.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Wade Cline
2012-Sep-11 22:16 UTC
Re: [PATCH] Btrfs: create a pinned em when writing to a prealloc range in DIO
On 09/11/2012 12:42 PM, Josef Bacik wrote:> Wade Cline reported a problem where he was getting garbage and warnings when > writing to a preallocated range via O_DIRECT. This is because we weren''t > creating our normal pinned extent_map for the range we were writing to, > which was causing all sorts of issues. This patch fixes the problem and > makes his testcase much happier. Thanks, > > Reported-by: Wade Cline<clinew@linux.vnet.ibm.com> > Signed-off-by: Josef Bacik<jbacik@fusionio.com>I ran some basic tests and this seems to have fixed the issue. Tested-by: Wade Cline <clinew@linux.vnet.ibm.com> Thank you, Wade -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html