aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-05-08 16:31:21 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:02 -0400
commitbbaf549e0c3d28399fc5abd68020d4025ae5c3a7 (patch)
tree19443b7e2a18fd04556ab9c5d914de3d29034a0d /fs
parentc1c4d91c38e6e5b29543b02d4a4fb7f007e44f70 (diff)
Btrfs: A number of nodatacow fixes
Once part of a delalloc request fails the cow checks, just cow the entire range It is possible for the back references to all be from the same root, but still have snapshots against an extent. The checks are now more strict, forcing cow any time there are multiple refs against the data extent. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/extent-tree.c20
-rw-r--r--fs/btrfs/inode.c8
2 files changed, 23 insertions, 5 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 30a5094fffa7..db996f0edf0b 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -731,6 +731,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
731 u64 found_owner; 731 u64 found_owner;
732 u64 root_objectid = root->root_key.objectid; 732 u64 root_objectid = root->root_key.objectid;
733 u32 total_count = 0; 733 u32 total_count = 0;
734 u32 extent_refs;
734 u32 cur_count; 735 u32 cur_count;
735 u32 nritems; 736 u32 nritems;
736 int ret; 737 int ret;
@@ -767,6 +768,7 @@ again:
767 } 768 }
768 769
769 item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item); 770 item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
771 extent_refs = btrfs_extent_refs(l, item);
770 while (1) { 772 while (1) {
771 l = path->nodes[0]; 773 l = path->nodes[0];
772 nritems = btrfs_header_nritems(l); 774 nritems = btrfs_header_nritems(l);
@@ -800,10 +802,28 @@ again:
800 total_count = 2; 802 total_count = 2;
801 goto out; 803 goto out;
802 } 804 }
805 /*
806 * nasty. we don't count a reference held by
807 * the running transaction. This allows nodatacow
808 * to avoid cow most of the time
809 */
810 if (found_owner >= BTRFS_FIRST_FREE_OBJECTID &&
811 btrfs_ref_generation(l, ref_item) ==
812 root->fs_info->generation) {
813 extent_refs--;
814 }
803 } 815 }
804 total_count = 1; 816 total_count = 1;
805 path->slots[0]++; 817 path->slots[0]++;
806 } 818 }
819 /*
820 * if there is more than one reference against a data extent,
821 * we have to assume the other ref is another snapshot
822 */
823 if (level == -1 && extent_refs > 1) {
824 total_count = 2;
825 goto out;
826 }
807 if (cur_count == 0) { 827 if (cur_count == 0) {
808 total_count = 0; 828 total_count = 0;
809 goto out; 829 goto out;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 1bf37d15b174..a492fd238c88 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -207,9 +207,8 @@ again:
207 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); 207 btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
208 found_type = btrfs_key_type(&found_key); 208 found_type = btrfs_key_type(&found_key);
209 if (found_key.objectid != inode->i_ino || 209 if (found_key.objectid != inode->i_ino ||
210 found_type != BTRFS_EXTENT_DATA_KEY) { 210 found_type != BTRFS_EXTENT_DATA_KEY)
211 goto not_found; 211 goto not_found;
212 }
213 212
214 found_type = btrfs_file_extent_type(leaf, item); 213 found_type = btrfs_file_extent_type(leaf, item);
215 extent_start = found_key.offset; 214 extent_start = found_key.offset;
@@ -245,7 +244,6 @@ again:
245 if (!block_group || block_group->ro) 244 if (!block_group || block_group->ro)
246 goto not_found; 245 goto not_found;
247 246
248
249 start = extent_end; 247 start = extent_end;
250 } else { 248 } else {
251 goto not_found; 249 goto not_found;
@@ -260,8 +258,8 @@ loop:
260 goto again; 258 goto again;
261 259
262not_found: 260not_found:
263 cow_file_range(inode, start, cow_end); 261 cow_file_range(inode, start, end);
264 start = cow_end + 1; 262 start = end + 1;
265 goto loop; 263 goto loop;
266} 264}
267 265