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

Commit 7bfc837d authored by Miao Xie's avatar Miao Xie Committed by Chris Mason
Browse files

btrfs: restructure find_free_dev_extent()



- make it return the start position and length of the max free space when it can
  not find a suitable free space.
- make it more readability

Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 1974a3b4
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -8099,7 +8099,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
	mutex_lock(&root->fs_info->chunk_mutex);
	mutex_lock(&root->fs_info->chunk_mutex);
	list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
	list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) {
		u64 min_free = btrfs_block_group_used(&block_group->item);
		u64 min_free = btrfs_block_group_used(&block_group->item);
		u64 dev_offset, max_avail;
		u64 dev_offset;


		/*
		/*
		 * check to make sure we can actually find a chunk with enough
		 * check to make sure we can actually find a chunk with enough
@@ -8107,7 +8107,7 @@ int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr)
		 */
		 */
		if (device->total_bytes > device->bytes_used + min_free) {
		if (device->total_bytes > device->bytes_used + min_free) {
			ret = find_free_dev_extent(NULL, device, min_free,
			ret = find_free_dev_extent(NULL, device, min_free,
						   &dev_offset, &max_avail);
						   &dev_offset, NULL);
			if (!ret)
			if (!ret)
				break;
				break;
			ret = -1;
			ret = -1;
+89 −66
Original line number Original line Diff line number Diff line
@@ -729,58 +729,82 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
}
}


/*
/*
 * find_free_dev_extent - find free space in the specified device
 * @trans:	transaction handler
 * @device:	the device which we search the free space in
 * @num_bytes:	the size of the free space that we need
 * @start:	store the start of the free space.
 * @len:	the size of the free space. that we find, or the size of the max
 * 		free space if we don't find suitable free space
 *
 * this uses a pretty simple search, the expectation is that it is
 * this uses a pretty simple search, the expectation is that it is
 * called very infrequently and that a given device has a small number
 * called very infrequently and that a given device has a small number
 * of extents
 * of extents
 *
 * @start is used to store the start of the free space if we find. But if we
 * don't find suitable free space, it will be used to store the start position
 * of the max free space.
 *
 * @len is used to store the size of the free space that we find.
 * But if we don't find suitable free space, it is used to store the size of
 * the max free space.
 */
 */
int find_free_dev_extent(struct btrfs_trans_handle *trans,
int find_free_dev_extent(struct btrfs_trans_handle *trans,
			 struct btrfs_device *device, u64 num_bytes,
			 struct btrfs_device *device, u64 num_bytes,
			 u64 *start, u64 *max_avail)
			 u64 *start, u64 *len)
{
{
	struct btrfs_key key;
	struct btrfs_key key;
	struct btrfs_root *root = device->dev_root;
	struct btrfs_root *root = device->dev_root;
	struct btrfs_dev_extent *dev_extent = NULL;
	struct btrfs_dev_extent *dev_extent;
	struct btrfs_path *path;
	struct btrfs_path *path;
	u64 hole_size = 0;
	u64 hole_size;
	u64 last_byte = 0;
	u64 max_hole_start;
	u64 search_start = 0;
	u64 max_hole_size;
	u64 extent_end;
	u64 search_start;
	u64 search_end = device->total_bytes;
	u64 search_end = device->total_bytes;
	int ret;
	int ret;
	int slot = 0;
	int slot;
	int start_found;
	struct extent_buffer *l;
	struct extent_buffer *l;


	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	path->reada = 2;
	start_found = 0;

	/* FIXME use last free of some kind */
	/* FIXME use last free of some kind */


	/* we don't want to overwrite the superblock on the drive,
	/* we don't want to overwrite the superblock on the drive,
	 * so we make sure to start at an offset of at least 1MB
	 * so we make sure to start at an offset of at least 1MB
	 */
	 */
	search_start = max((u64)1024 * 1024, search_start);
	search_start = 1024 * 1024;


	if (root->fs_info->alloc_start + num_bytes <= device->total_bytes)
	if (root->fs_info->alloc_start + num_bytes <= search_end)
		search_start = max(root->fs_info->alloc_start, search_start);
		search_start = max(root->fs_info->alloc_start, search_start);


	max_hole_start = search_start;
	max_hole_size = 0;

	if (search_start >= search_end) {
		ret = -ENOSPC;
		goto error;
	}

	path = btrfs_alloc_path();
	if (!path) {
		ret = -ENOMEM;
		goto error;
	}
	path->reada = 2;

	key.objectid = device->devid;
	key.objectid = device->devid;
	key.offset = search_start;
	key.offset = search_start;
	key.type = BTRFS_DEV_EXTENT_KEY;
	key.type = BTRFS_DEV_EXTENT_KEY;

	ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
	ret = btrfs_search_slot(trans, root, &key, path, 0, 0);
	if (ret < 0)
	if (ret < 0)
		goto error;
		goto out;
	if (ret > 0) {
	if (ret > 0) {
		ret = btrfs_previous_item(root, path, key.objectid, key.type);
		ret = btrfs_previous_item(root, path, key.objectid, key.type);
		if (ret < 0)
		if (ret < 0)
			goto error;
			goto out;
		if (ret > 0)
			start_found = 1;
	}
	}
	l = path->nodes[0];

	btrfs_item_key_to_cpu(l, &key, path->slots[0]);
	while (1) {
	while (1) {
		l = path->nodes[0];
		l = path->nodes[0];
		slot = path->slots[0];
		slot = path->slots[0];
@@ -789,24 +813,9 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
			if (ret == 0)
			if (ret == 0)
				continue;
				continue;
			if (ret < 0)
			if (ret < 0)
				goto error;
				goto out;
no_more_items:

			if (!start_found) {
			break;
				if (search_start >= search_end) {
					ret = -ENOSPC;
					goto error;
				}
				*start = search_start;
				start_found = 1;
				goto check_pending;
			}
			*start = last_byte > search_start ?
				last_byte : search_start;
			if (search_end <= *start) {
				ret = -ENOSPC;
				goto error;
			}
			goto check_pending;
		}
		}
		btrfs_item_key_to_cpu(l, &key, slot);
		btrfs_item_key_to_cpu(l, &key, slot);


@@ -814,48 +823,62 @@ int find_free_dev_extent(struct btrfs_trans_handle *trans,
			goto next;
			goto next;


		if (key.objectid > device->devid)
		if (key.objectid > device->devid)
			goto no_more_items;
			break;


		if (key.offset >= search_start && key.offset > last_byte &&
		if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
		    start_found) {
			goto next;
			if (last_byte < search_start)
				last_byte = search_start;
			hole_size = key.offset - last_byte;


			if (hole_size > *max_avail)
		if (key.offset > search_start) {
				*max_avail = hole_size;
			hole_size = key.offset - search_start;


			if (key.offset > last_byte &&
			if (hole_size > max_hole_size) {
			    hole_size >= num_bytes) {
				max_hole_start = search_start;
				*start = last_byte;
				max_hole_size = hole_size;
				goto check_pending;
			}

			/*
			 * If this free space is greater than which we need,
			 * it must be the max free space that we have found
			 * until now, so max_hole_start must point to the start
			 * of this free space and the length of this free space
			 * is stored in max_hole_size. Thus, we return
			 * max_hole_start and max_hole_size and go back to the
			 * caller.
			 */
			if (hole_size >= num_bytes) {
				ret = 0;
				goto out;
			}
			}
		}
		}
		if (btrfs_key_type(&key) != BTRFS_DEV_EXTENT_KEY)
			goto next;


		start_found = 1;
		dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
		dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent);
		last_byte = key.offset + btrfs_dev_extent_length(l, dev_extent);
		extent_end = key.offset + btrfs_dev_extent_length(l,
								  dev_extent);
		if (extent_end > search_start)
			search_start = extent_end;
next:
next:
		path->slots[0]++;
		path->slots[0]++;
		cond_resched();
		cond_resched();
	}
	}
check_pending:
	/* we have to make sure we didn't find an extent that has already
	 * been allocated by the map tree or the original allocation
	 */
	BUG_ON(*start < search_start);


	if (*start + num_bytes > search_end) {
	hole_size = search_end- search_start;
		ret = -ENOSPC;
	if (hole_size > max_hole_size) {
		goto error;
		max_hole_start = search_start;
		max_hole_size = hole_size;
	}
	}
	/* check for pending inserts here */

	/* See above. */
	if (hole_size < num_bytes)
		ret = -ENOSPC;
	else
		ret = 0;
		ret = 0;


error:
out:
	btrfs_free_path(path);
	btrfs_free_path(path);
error:
	*start = max_hole_start;
	if (len && max_hole_size > *len)
		*len = max_hole_size;
	return ret;
	return ret;
}
}