aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2014-02-27 00:58:05 -0500
committerJosef Bacik <jbacik@fb.com>2014-03-10 15:17:00 -0400
commit7b2b70851f862b68714f357d2926adbb6c574fdd (patch)
treeb1f0715cb4140c4ddd63bf3c6e70f1900c8b9acf /fs/btrfs/inode.c
parentc933956ddf80bc455d33cbcf39d35d935daf45a9 (diff)
Btrfs: fix preallocate vs double nocow write
We can not release the reserved metadata space for the first write if we find the write position is pre-allocated. Because the kernel might write the data on the disk before we do the second write but after the can-nocow check, if we release the space for the first write, we might fail to update the metadata because of no space. Fix this problem by end nocow write if there is dirty data in the range whose space is pre-allocated. Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fb.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r--fs/btrfs/inode.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8dba152883d3..0182f081d499 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6557,6 +6557,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
6557 int ret; 6557 int ret;
6558 struct extent_buffer *leaf; 6558 struct extent_buffer *leaf;
6559 struct btrfs_root *root = BTRFS_I(inode)->root; 6559 struct btrfs_root *root = BTRFS_I(inode)->root;
6560 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
6560 struct btrfs_file_extent_item *fi; 6561 struct btrfs_file_extent_item *fi;
6561 struct btrfs_key key; 6562 struct btrfs_key key;
6562 u64 disk_bytenr; 6563 u64 disk_bytenr;
@@ -6633,6 +6634,20 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
6633 6634
6634 if (btrfs_extent_readonly(root, disk_bytenr)) 6635 if (btrfs_extent_readonly(root, disk_bytenr))
6635 goto out; 6636 goto out;
6637
6638 num_bytes = min(offset + *len, extent_end) - offset;
6639 if (!nocow && found_type == BTRFS_FILE_EXTENT_PREALLOC) {
6640 u64 range_end;
6641
6642 range_end = round_up(offset + num_bytes, root->sectorsize) - 1;
6643 ret = test_range_bit(io_tree, offset, range_end,
6644 EXTENT_DELALLOC, 0, NULL);
6645 if (ret) {
6646 ret = -EAGAIN;
6647 goto out;
6648 }
6649 }
6650
6636 btrfs_release_path(path); 6651 btrfs_release_path(path);
6637 6652
6638 /* 6653 /*
@@ -6661,7 +6676,6 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
6661 */ 6676 */
6662 disk_bytenr += backref_offset; 6677 disk_bytenr += backref_offset;
6663 disk_bytenr += offset - key.offset; 6678 disk_bytenr += offset - key.offset;
6664 num_bytes = min(offset + *len, extent_end) - offset;
6665 if (csum_exist_in_range(root, disk_bytenr, num_bytes)) 6679 if (csum_exist_in_range(root, disk_bytenr, num_bytes))
6666 goto out; 6680 goto out;
6667 /* 6681 /*