aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fusionio.com>2012-09-11 15:40:07 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-01 15:19:20 -0400
commit69ffb54347a71c4f2a4694e0c1155af8538d55f6 (patch)
tree34e12adce924817ccfba6ecc7be3b68e4cdcab98 /fs/btrfs/inode.c
parent6df7881a84013f91405e5e113a4c322dd1804ba6 (diff)
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>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 9e9754adf7a4..406666cb6156 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5898,6 +5898,48 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
5898 return ret; 5898 return ret;
5899} 5899}
5900 5900
5901static struct extent_map *create_pinned_em(struct inode *inode, u64 start,
5902 u64 len, u64 orig_start,
5903 u64 block_start, u64 block_len,
5904 int type)
5905{
5906 struct extent_map_tree *em_tree;
5907 struct extent_map *em;
5908 struct btrfs_root *root = BTRFS_I(inode)->root;
5909 int ret;
5910
5911 em_tree = &BTRFS_I(inode)->extent_tree;
5912 em = alloc_extent_map();
5913 if (!em)
5914 return ERR_PTR(-ENOMEM);
5915
5916 em->start = start;
5917 em->orig_start = orig_start;
5918 em->len = len;
5919 em->block_len = block_len;
5920 em->block_start = block_start;
5921 em->bdev = root->fs_info->fs_devices->latest_bdev;
5922 set_bit(EXTENT_FLAG_PINNED, &em->flags);
5923 if (type == BTRFS_ORDERED_PREALLOC)
5924 set_bit(EXTENT_FLAG_PREALLOC, &em->flags);
5925
5926 do {
5927 btrfs_drop_extent_cache(inode, em->start,
5928 em->start + em->len - 1, 0);
5929 write_lock(&em_tree->lock);
5930 ret = add_extent_mapping(em_tree, em);
5931 write_unlock(&em_tree->lock);
5932 } while (ret == -EEXIST);
5933
5934 if (ret) {
5935 free_extent_map(em);
5936 return ERR_PTR(ret);
5937 }
5938
5939 return em;
5940}
5941
5942
5901static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, 5943static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
5902 struct buffer_head *bh_result, int create) 5944 struct buffer_head *bh_result, int create)
5903{ 5945{
@@ -6012,6 +6054,19 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
6012 goto must_cow; 6054 goto must_cow;
6013 6055
6014 if (can_nocow_odirect(trans, inode, start, len) == 1) { 6056 if (can_nocow_odirect(trans, inode, start, len) == 1) {
6057 u64 orig_start = em->start;
6058
6059 if (type == BTRFS_ORDERED_PREALLOC) {
6060 free_extent_map(em);
6061 em = create_pinned_em(inode, start, len,
6062 orig_start,
6063 block_start, len, type);
6064 if (IS_ERR(em)) {
6065 btrfs_end_transaction(trans, root);
6066 goto unlock_err;
6067 }
6068 }
6069
6015 ret = btrfs_add_ordered_extent_dio(inode, start, 6070 ret = btrfs_add_ordered_extent_dio(inode, start,
6016 block_start, len, len, type); 6071 block_start, len, len, type);
6017 btrfs_end_transaction(trans, root); 6072 btrfs_end_transaction(trans, root);