aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-11-12 14:19:50 -0500
committerChris Mason <chris.mason@oracle.com>2008-11-12 14:19:50 -0500
commitc36047d729a3fa080dd194b20b684cc9fe73e90c (patch)
treeac1ac2a3a5e3b9ecb1caf29fde32c00959006ec3
parent2b82032c34ec40515d3c45c36cd1961f37977de8 (diff)
Btrfs: Fix race in btrfs_mark_extent_written
When extent needs to be split, btrfs_mark_extent_written truncates the extent first, then inserts a new extent and increases the reference count. The race happens if someone else deletes the old extent before the new extent is inserted. The fix here is increase the reference count in advance. This race is similar to the race in btrfs_drop_extents that was recently fixed. Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
-rw-r--r--fs/btrfs/file.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 934bc094bf17..1e8c024c69c3 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -746,6 +746,7 @@ int btrfs_mark_extent_written(struct btrfs_trans_handle *trans,
746 u64 other_end; 746 u64 other_end;
747 u64 split = start; 747 u64 split = start;
748 u64 locked_end = end; 748 u64 locked_end = end;
749 u64 orig_parent;
749 int extent_type; 750 int extent_type;
750 int split_end = 1; 751 int split_end = 1;
751 int ret; 752 int ret;
@@ -890,6 +891,12 @@ again:
890 } 891 }
891 892
892 btrfs_mark_buffer_dirty(leaf); 893 btrfs_mark_buffer_dirty(leaf);
894
895 orig_parent = leaf->start;
896 ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes,
897 orig_parent, root->root_key.objectid,
898 trans->transid, inode->i_ino);
899 BUG_ON(ret);
893 btrfs_release_path(root, path); 900 btrfs_release_path(root, path);
894 901
895 key.offset = start; 902 key.offset = start;
@@ -910,10 +917,13 @@ again:
910 btrfs_set_file_extent_encryption(leaf, fi, 0); 917 btrfs_set_file_extent_encryption(leaf, fi, 0);
911 btrfs_set_file_extent_other_encoding(leaf, fi, 0); 918 btrfs_set_file_extent_other_encoding(leaf, fi, 0);
912 919
913 ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 920 if (orig_parent != leaf->start) {
914 leaf->start, root->root_key.objectid, 921 ret = btrfs_update_extent_ref(trans, root, bytenr,
915 trans->transid, inode->i_ino); 922 orig_parent, leaf->start,
916 BUG_ON(ret); 923 root->root_key.objectid,
924 trans->transid, inode->i_ino);
925 BUG_ON(ret);
926 }
917done: 927done:
918 btrfs_mark_buffer_dirty(leaf); 928 btrfs_mark_buffer_dirty(leaf);
919 btrfs_release_path(root, path); 929 btrfs_release_path(root, path);