Ejemplo n.º 1
0
/*
 * Find a free inode index for later btrfs_add_link().
 * Currently just search from the largest dir_index and +1.
 */
static int btrfs_find_free_dir_index(struct btrfs_root *root, u64 dir_ino,
				     u64 *ret_ino)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_key found_key;
	u64 ret_val = 2;
	int ret = 0;

	if (!ret_ino)
		return 0;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;

	key.objectid = dir_ino;
	key.type = BTRFS_DIR_INDEX_KEY;
	key.offset = (u64)-1;

	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto out;
	ret = 0;
	if (path->slots[0] == 0) {
		ret = btrfs_prev_leaf(root, path);
		if (ret < 0)
			goto out;
		if (ret > 0) {
			/*
			 * This shouldn't happen since there must be a leaf
			 * containing the DIR_ITEM.
			 * Can only happen when the previous leaf is corrupted.
			 */
			ret = -EIO;
			goto out;
		}
	} else {
		path->slots[0]--;
	}
	btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
	if (found_key.objectid != dir_ino ||
	    found_key.type != BTRFS_DIR_INDEX_KEY)
		goto out;
	ret_val = found_key.offset + 1;
out:
	btrfs_free_path(path);
	if (ret == 0)
		*ret_ino = ret_val;
	return ret;
}
Ejemplo n.º 2
0
/*
 * Get the first file extent that covers (part of) the given range
 * Unlike kernel using extent_map to handle hole even no-hole is enabled,
 * progs don't have such infrastructure, so caller should do extra care
 * for no-hole.
 *
 * return 0 for found, and path points to the file extent.
 * return >0 for not found, and path points to the insert position.
 * return <0 for error.
 */
int btrfs_get_extent(struct btrfs_trans_handle *trans,
		     struct btrfs_root *root,
		     struct btrfs_path *path,
		     u64 ino, u64 offset, u64 len, int ins_len)
{
	struct btrfs_key key;
	struct btrfs_key found_key;
	struct btrfs_file_extent_item *fi_item;
	u64 end = 0;
	int ret = 0;
	int not_found = 1;

	key.objectid = ino;
	key.type = BTRFS_EXTENT_DATA_KEY;
	key.offset = offset;

	ret = btrfs_search_slot(trans, root, &key, path, ins_len,
				ins_len ? 1 : 0);
	if (ret <= 0)
		goto out;
	if (ret > 0) {
		/* Check preivous file extent */
		ret = btrfs_previous_item(root, path, ino,
					  BTRFS_EXTENT_DATA_KEY);
		if (ret < 0)
			goto out;
		if (ret > 0)
			goto check_next;
	}
	btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
	if (found_key.objectid != ino ||
	    found_key.type != BTRFS_EXTENT_DATA_KEY)
		goto check_next;

	fi_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
				 struct btrfs_file_extent_item);
	end = found_key.offset +
	      btrfs_file_extent_ram_bytes(path->nodes[0], fi_item);
	/*
	 * existing file extent
	 * |--------|	  |----|
	 *      |-------|
	 *      offset + len
	 * OR
	 * |---------------|
	 *	|-------|
	 */
	if (end > offset) {
		not_found = 0;
		goto out;
	}
check_next:
	ret = btrfs_next_item(root, path);
	if (ret)
		goto out;

	btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
	if (found_key.objectid != ino ||
	    found_key.type != BTRFS_EXTENT_DATA_KEY) {
		ret = 1;
		goto out;
	}
	if (found_key.offset < offset + len)
		/*
		 * existing file extent
		 * |---|	|------|
		 *	|-------|
		 *	offset + len
		 */
		not_found = 0;
	else
		/*
		 * existing file extent
		 * |----|		|----|
		 *		|----|
		 *		offset + len
		 */
		not_found = 1;

	/*
	 * To keep the search hehavior consistent with search_slot(),
	 * we need to go back to the prev leaf's nritem slot if
	 * we are at the first slot of the leaf.
	 */
	if (path->slots[0] == 0) {
		ret = btrfs_prev_leaf(root, path);
		/* Not possible */
		if (ret)
			goto out;
		path->slots[0] = btrfs_header_nritems(path->nodes[0]);
	}

out:
	if (ret == 0)
		ret = not_found;
	return ret;
}
Ejemplo n.º 3
0
/*
 * this makes the path point to (logical EXTENT_ITEM *)
 * returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for
 * tree blocks and <0 on error.
 */
int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
			struct btrfs_path *path, struct btrfs_key *found_key,
			u64 *flags_ret)
{
	int ret;
	u64 flags;
	u64 size = 0;
	u32 item_size;
	struct extent_buffer *eb;
	struct btrfs_extent_item *ei;
	struct btrfs_key key;

	if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
		key.type = BTRFS_METADATA_ITEM_KEY;
	else
		key.type = BTRFS_EXTENT_ITEM_KEY;
	key.objectid = logical;
	key.offset = (u64)-1;

	ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
	if (ret < 0)
		return ret;

	while (1) {
		u32 nritems;
		if (path->slots[0] == 0) {
			btrfs_set_path_blocking(path);
			ret = btrfs_prev_leaf(fs_info->extent_root, path);
			if (ret != 0) {
				if (ret > 0) {
					pr_debug("logical %llu is not within "
						 "any extent\n", logical);
					ret = -ENOENT;
				}
				return ret;
			}
		} else {
			path->slots[0]--;
		}
		nritems = btrfs_header_nritems(path->nodes[0]);
		if (nritems == 0) {
			pr_debug("logical %llu is not within any extent\n",
				 logical);
			return -ENOENT;
		}
		if (path->slots[0] == nritems)
			path->slots[0]--;

		btrfs_item_key_to_cpu(path->nodes[0], found_key,
				      path->slots[0]);
		if (found_key->type == BTRFS_EXTENT_ITEM_KEY ||
		    found_key->type == BTRFS_METADATA_ITEM_KEY)
			break;
	}

	if (found_key->type == BTRFS_METADATA_ITEM_KEY)
		size = fs_info->extent_root->leafsize;
	else if (found_key->type == BTRFS_EXTENT_ITEM_KEY)
		size = found_key->offset;

	if (found_key->objectid > logical ||
	    found_key->objectid + size <= logical) {
		pr_debug("logical %llu is not within any extent\n", logical);
		return -ENOENT;
	}

	eb = path->nodes[0];
	item_size = btrfs_item_size_nr(eb, path->slots[0]);
	BUG_ON(item_size < sizeof(*ei));

	ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item);
	flags = btrfs_extent_flags(eb, ei);

	pr_debug("logical %llu is at position %llu within the extent (%llu "
		 "EXTENT_ITEM %llu) flags %#llx size %u\n",
		 logical, logical - found_key->objectid, found_key->objectid,
		 found_key->offset, flags, item_size);

	WARN_ON(!flags_ret);
	if (flags_ret) {
		if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)
			*flags_ret = BTRFS_EXTENT_FLAG_TREE_BLOCK;
		else if (flags & BTRFS_EXTENT_FLAG_DATA)
			*flags_ret = BTRFS_EXTENT_FLAG_DATA;
		else
			BUG_ON(1);
		return 0;
	}

	return -EIO;
}