diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 30a5094fffa71b86e65d3465f52a1250738c6696..db996f0edf0b5b3feeb6c3ca47f16afb50f8cac4 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, 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 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root, } 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 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root, 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; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1bf37d15b17411c77f2428dd2afa40692720f5d3..a492fd238c887a145af5a9634d33c7417e275861 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -207,9 +207,8 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) 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 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) if (!block_group || block_group->ro) goto not_found; - start = extent_end; } else { goto not_found; @@ -260,8 +258,8 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) 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; }