Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bbaf549e authored by Chris Mason's avatar Chris Mason
Browse files

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: default avatarChris Mason <chris.mason@oracle.com>
parent c1c4d91c
Loading
Loading
Loading
Loading
+20 −0
Original line number Original line Diff line number Diff line
@@ -731,6 +731,7 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
	u64 found_owner;
	u64 found_owner;
	u64 root_objectid = root->root_key.objectid;
	u64 root_objectid = root->root_key.objectid;
	u32 total_count = 0;
	u32 total_count = 0;
	u32 extent_refs;
	u32 cur_count;
	u32 cur_count;
	u32 nritems;
	u32 nritems;
	int ret;
	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);
	item = btrfs_item_ptr(l, path->slots[0], struct btrfs_extent_item);
	extent_refs = btrfs_extent_refs(l, item);
	while (1) {
	while (1) {
		l = path->nodes[0];
		l = path->nodes[0];
		nritems = btrfs_header_nritems(l);
		nritems = btrfs_header_nritems(l);
@@ -800,10 +802,28 @@ u32 btrfs_count_snapshots_in_path(struct btrfs_root *root,
				total_count = 2;
				total_count = 2;
				goto out;
				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;
		total_count = 1;
		path->slots[0]++;
		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) {
	if (cur_count == 0) {
		total_count = 0;
		total_count = 0;
		goto out;
		goto out;
+3 −5
Original line number Original line Diff line number Diff line
@@ -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]);
	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
	found_type = btrfs_key_type(&found_key);
	found_type = btrfs_key_type(&found_key);
	if (found_key.objectid != inode->i_ino ||
	if (found_key.objectid != inode->i_ino ||
	    found_type != BTRFS_EXTENT_DATA_KEY) {
	    found_type != BTRFS_EXTENT_DATA_KEY)
		goto not_found;
		goto not_found;
	}


	found_type = btrfs_file_extent_type(leaf, item);
	found_type = btrfs_file_extent_type(leaf, item);
	extent_start = found_key.offset;
	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)
		if (!block_group || block_group->ro)
			goto not_found;
			goto not_found;



		start = extent_end;
		start = extent_end;
	} else {
	} else {
		goto not_found;
		goto not_found;
@@ -260,8 +258,8 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end)
	goto again;
	goto again;


not_found:
not_found:
	cow_file_range(inode, start, cow_end);
	cow_file_range(inode, start, end);
	start = cow_end + 1;
	start = end + 1;
	goto loop;
	goto loop;
}
}