Btrfs: A number of nodatacow fixes
authorChris Mason <chris.mason@oracle.com>
Thu, 8 May 2008 20:31:21 +0000 (16:31 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:02 +0000 (11:04 -0400)
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>
fs/btrfs/extent-tree.c
fs/btrfs/inode.c

index 30a5094fffa71b86e65d3465f52a1250738c6696..db996f0edf0b5b3feeb6c3ca47f16afb50f8cac4 100644 (file)
@@ -731,6 +731,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
        u64 found_owner;
        u64 root_objectid = root->root_key.objectid;
        u32 total_count = 0;
+       u32 extent_refs;
        u32 cur_count;
        u32 nritems;
        int ret;
@@ -767,6 +768,7 @@ again:
        }
 
        item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
+       extent_refs = btrfs_extent_refs(l, item);
        while (1) {
                l = path->nodes[0];
                nritems = btrfs_header_nritems(l);
@@ -800,10 +802,28 @@ again:
                                total_count = 2;
                                goto out;
                        }
+                       /*
+                        * nasty.  we don't count a reference held by
+                        * the running transaction.  This allows nodatacow
+                        * to avoid cow most of the time
+                        */
+                       if (found_owner >= BTRFS_FIRST_FREE_OBJECTID &&
+                           btrfs_ref_generation(l, ref_item) ==
+                           root->fs_info->generation) {
+                               extent_refs--;
+                       }
                }
                total_count = 1;
                path->slots[0]++;
        }
+       /*
+        * if there is more than one reference against a data extent,
+        * we have to assume the other ref is another snapshot
+        */
+       if (level == -1 && extent_refs > 1) {
+               total_count = 2;
+               goto out;
+       }
        if (cur_count == 0) {
                total_count = 0;
                goto out;
index 1bf37d15b17411c77f2428dd2afa40692720f5d3..a492fd238c887a145af5a9634d33c7417e275861 100644 (file)
@@ -207,9 +207,8 @@ again:
        btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
        found_type = btrfs_key_type(&found_key);
        if (found_key.objectid != inode->i_ino ||
-           found_type != BTRFS_EXTENT_DATA_KEY) {
+           found_type != BTRFS_EXTENT_DATA_KEY)
                goto not_found;
-       }
 
        found_type = btrfs_file_extent_type(leaf, item);
        extent_start = found_key.offset;
@@ -245,7 +244,6 @@ again:
                if (!block_group || block_group->ro)
                        goto not_found;
 
-
                start = extent_end;
        } else {
                goto not_found;
@@ -260,8 +258,8 @@ loop:
        goto again;
 
 not_found:
-       cow_file_range(inode, start, cow_end);
-       start = cow_end + 1;
+       cow_file_range(inode, start, end);
+       start = end + 1;
        goto loop;
 }