Ejemplo n.º 1
0
static int do_setxattr(struct btrfs_trans_handle *trans,
		       struct inode *inode, const char *name,
		       const void *value, size_t size, int flags)
{
	struct btrfs_dir_item *di;
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_path *path;
	size_t name_len = strlen(name);
	int ret = 0;

	if (name_len + size > BTRFS_MAX_XATTR_SIZE(root))
		return -ENOSPC;

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

	/* first lets see if we already have this xattr */
	di = btrfs_lookup_xattr(trans, root, path, inode->i_ino, name,
				strlen(name), -1);
	if (IS_ERR(di)) {
		ret = PTR_ERR(di);
		goto out;
	}

	/* ok we already have this xattr, lets remove it */
	if (di) {
		/* if we want create only exit */
		if (flags & XATTR_CREATE) {
			ret = -EEXIST;
			goto out;
		}

		ret = btrfs_delete_one_dir_name(trans, root, path, di);
		BUG_ON(ret);
		btrfs_release_path(root, path);

		/* if we don't have a value then we are removing the xattr */
		if (!value)
			goto out;
	} else {
		btrfs_release_path(root, path);

		if (flags & XATTR_REPLACE) {
			/* we couldn't find the attr to replace */
			ret = -ENODATA;
			goto out;
		}
	}

	/* ok we have to create a completely new xattr */
	ret = btrfs_insert_xattr_item(trans, root, path, inode->i_ino,
				      name, name_len, value, size);
	BUG_ON(ret);
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 2
0
static int map_one_extent(struct btrfs_fs_info *fs_info,
			  u64 *logical_ret, u64 *len_ret, int search_forward)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	u64 logical;
	u64 len = 0;
	int ret = 0;

	BUG_ON(!logical_ret);
	logical = *logical_ret;

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

	key.objectid = logical;
	key.type = 0;
	key.offset = 0;

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

again:
	btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
	if ((search_forward && key.objectid < logical) ||
	    (!search_forward && key.objectid > logical) ||
	    (key.type != BTRFS_EXTENT_ITEM_KEY &&
	     key.type != BTRFS_METADATA_ITEM_KEY)) {
		if (!search_forward)
			ret = btrfs_previous_extent_item(fs_info->extent_root,
							 path, 0);
		else
			ret = btrfs_next_extent_item(fs_info->extent_root,
						     path, 0);
		if (ret)
			goto out;
		goto again;
	}
	logical = key.objectid;
	if (key.type == BTRFS_METADATA_ITEM_KEY)
		len = fs_info->nodesize;
	else
		len = key.offset;

out:
	btrfs_free_path(path);
	if (!ret) {
		*logical_ret = logical;
		if (len_ret)
			*len_ret = len;
	}
	return ret;
}
Ejemplo n.º 3
0
int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
				   const char *name, int name_len)
{
	int ret;
	struct btrfs_key key;
	struct btrfs_dir_item *di;
	int data_size;
	struct extent_buffer *leaf;
	int slot;
	struct btrfs_path *path;


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

	key.objectid = dir;
	key.type = BTRFS_DIR_ITEM_KEY;
	key.offset = btrfs_name_hash(name, name_len);

	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);

	/* return back any errors */
	if (ret < 0)
		goto out;

	/* nothing found, we're safe */
	if (ret > 0) {
		ret = 0;
		goto out;
	}

	/* we found an item, look for our name in the item */
	di = btrfs_match_dir_item_name(root, path, name, name_len);
	if (di) {
		/* our exact name was found */
		ret = -EEXIST;
		goto out;
	}

	/*
	 * see if there is room in the item to insert this
	 * name
	 */
	data_size = sizeof(*di) + name_len;
	leaf = path->nodes[0];
	slot = path->slots[0];
	if (data_size + btrfs_item_size_nr(leaf, slot) +
	    sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) {
		ret = -EOVERFLOW;
	} else {
		/* plenty of insertion room */
		ret = 0;
	}
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 4
0
ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
				void *buffer, size_t size)
{
	struct btrfs_dir_item *di;
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	int ret = 0;
	unsigned long data_ptr;

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

	/* lookup the xattr by name */
	di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name,
				strlen(name), 0);
	if (!di) {
		ret = -ENODATA;
		goto out;
	} else if (IS_ERR(di)) {
		ret = PTR_ERR(di);
		goto out;
	}

	leaf = path->nodes[0];
	/* if size is 0, that means we want the size of the attr */
	if (!size) {
		ret = btrfs_dir_data_len(leaf, di);
		goto out;
	}

	/* now get the data out of our dir_item */
	if (btrfs_dir_data_len(leaf, di) > size) {
		ret = -ERANGE;
		goto out;
	}

	/*
	 * The way things are packed into the leaf is like this
	 * |struct btrfs_dir_item|name|data|
	 * where name is the xattr name, so security.foo, and data is the
	 * content of the xattr.  data_ptr points to the location in memory
	 * where the data starts in the in memory leaf
	 */
	data_ptr = (unsigned long)((char *)(di + 1) +
				   btrfs_dir_name_len(leaf, di));
	read_extent_buffer(leaf, buffer, data_ptr,
			   btrfs_dir_data_len(leaf, di));
	ret = btrfs_dir_data_len(leaf, di);

out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 5
0
ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
				void *buffer, size_t size)
{
	struct btrfs_dir_item *di;
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	int ret = 0;
	unsigned long data_ptr;

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

	/*                          */
	di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name,
				strlen(name), 0);
	if (!di) {
		ret = -ENODATA;
		goto out;
	} else if (IS_ERR(di)) {
		ret = PTR_ERR(di);
		goto out;
	}

	leaf = path->nodes[0];
	/*                                                       */
	if (!size) {
		ret = btrfs_dir_data_len(leaf, di);
		goto out;
	}

	/*                                      */
	if (btrfs_dir_data_len(leaf, di) > size) {
		ret = -ERANGE;
		goto out;
	}

	/*
                                                        
                                     
                                                                  
                                                                    
                                               
  */
	data_ptr = (unsigned long)((char *)(di + 1) +
				   btrfs_dir_name_len(leaf, di));
	read_extent_buffer(leaf, buffer, data_ptr,
			   btrfs_dir_data_len(leaf, di));
	ret = btrfs_dir_data_len(leaf, di);

out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 6
0
static int remove_extent_ref(struct btrfs_root *root, u64 bytenr,
			     u64 num_bytes, u64 parent, u64 root_objectid)
{
	struct btrfs_trans_handle trans;
	struct btrfs_extent_item *item;
	struct btrfs_path *path;
	struct btrfs_key key;
	u64 refs;
	int ret;

	btrfs_init_dummy_trans(&trans);

	key.objectid = bytenr;
	key.type = BTRFS_EXTENT_ITEM_KEY;
	key.offset = num_bytes;

	path = btrfs_alloc_path();
	if (!path) {
		test_msg("Couldn't allocate path\n");
		return -ENOMEM;
	}

	path->leave_spinning = 1;
	ret = btrfs_search_slot(&trans, root, &key, path, 0, 1);
	if (ret) {
		test_msg("Couldn't find extent ref\n");
		btrfs_free_path(path);
		return ret;
	}

	item = btrfs_item_ptr(path->nodes[0], path->slots[0],
			      struct btrfs_extent_item);
	refs = btrfs_extent_refs(path->nodes[0], item);
	btrfs_set_extent_refs(path->nodes[0], item, refs - 1);
	btrfs_release_path(path);

	key.objectid = bytenr;
	if (parent) {
		key.type = BTRFS_SHARED_BLOCK_REF_KEY;
		key.offset = parent;
	} else {
		key.type = BTRFS_TREE_BLOCK_REF_KEY;
		key.offset = root_objectid;
	}

	ret = btrfs_search_slot(&trans, root, &key, path, -1, 1);
	if (ret) {
		test_msg("Couldn't find backref %d\n", ret);
		btrfs_free_path(path);
		return ret;
	}
	btrfs_del_item(&trans, root, path);
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 7
0
static int copy_metadata(struct btrfs_root *root, int fd,
		struct btrfs_key *key)
{
	struct btrfs_path *path;
	struct btrfs_inode_item *inode_item;
	int ret;

	path = btrfs_alloc_path();
	if (!path) {
		fprintf(stderr, "ERROR: Ran out of memory\n");
		return -ENOMEM;
	}

	ret = btrfs_lookup_inode(NULL, root, path, key, 0);
	if (ret == 0) {
		struct btrfs_timespec *bts;
		struct timespec times[2];

		inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
				struct btrfs_inode_item);

		ret = fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item),
				btrfs_inode_gid(path->nodes[0], inode_item));
		if (ret) {
			fprintf(stderr, "ERROR: Failed to change owner: %s\n",
					strerror(errno));
			goto out;
		}

		ret = fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item));
		if (ret) {
			fprintf(stderr, "ERROR: Failed to change mode: %s\n",
					strerror(errno));
			goto out;
		}

		bts = btrfs_inode_atime(inode_item);
		times[0].tv_sec = btrfs_timespec_sec(path->nodes[0], bts);
		times[0].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts);

		bts = btrfs_inode_mtime(inode_item);
		times[1].tv_sec = btrfs_timespec_sec(path->nodes[0], bts);
		times[1].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts);

		ret = futimens(fd, times);
		if (ret) {
			fprintf(stderr, "ERROR: Failed to set times: %s\n",
					strerror(errno));
			goto out;
		}
	}
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 8
0
static int copy_file(struct btrfs_root *root, int fd, struct btrfs_key *key,
		     const char *file)
{
	struct extent_buffer *leaf;
	struct btrfs_path *path;
	struct btrfs_file_extent_item *fi;
	struct btrfs_inode_item *inode_item;
	struct btrfs_timespec *bts;
	struct btrfs_key found_key;
	int ret;
	int extent_type;
	int compression;
	int loops = 0;
	u64 found_size = 0;
	struct timespec times[2];
	int times_ok = 0;

	path = btrfs_alloc_path();
	if (!path) {
		fprintf(stderr, "Ran out of memory\n");
		return -ENOMEM;
	}

	ret = btrfs_lookup_inode(NULL, root, path, key, 0);
	if (ret == 0) {
		inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
				    struct btrfs_inode_item);
		found_size = btrfs_inode_size(path->nodes[0], inode_item);

		if (restore_metadata) {
			/*
			 * Change the ownership and mode now, set times when
			 * copyout is finished.
			 */

			ret = fchown(fd, btrfs_inode_uid(path->nodes[0], inode_item),
					btrfs_inode_gid(path->nodes[0], inode_item));
			if (ret && !ignore_errors)
				goto out;

			ret = fchmod(fd, btrfs_inode_mode(path->nodes[0], inode_item));
			if (ret && !ignore_errors)
				goto out;

			bts = btrfs_inode_atime(inode_item);
			times[0].tv_sec = btrfs_timespec_sec(path->nodes[0], bts);
			times[0].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts);

			bts = btrfs_inode_mtime(inode_item);
			times[1].tv_sec = btrfs_timespec_sec(path->nodes[0], bts);
			times[1].tv_nsec = btrfs_timespec_nsec(path->nodes[0], bts);
			times_ok = 1;
		}
	}
Ejemplo n.º 9
0
int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
			   struct btrfs_root *root,
			   const char *name, int name_len,
			   u64 inode_objectid, u64 ref_objectid)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_inode_ref *ref;
	struct extent_buffer *leaf;
	unsigned long ptr;
	unsigned long item_start;
	u32 item_size;
	u32 sub_item_len;
	int ret;
	int del_len = name_len + sizeof(*ref);

	key.objectid = inode_objectid;
	key.offset = ref_objectid;
	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);

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

	ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
	if (ret > 0) {
		ret = -ENOENT;
		goto out;
	} else if (ret < 0) {
		goto out;
	}
	if (!find_name_in_backref(path, name, name_len, &ref)) {
		ret = -ENOENT;
		goto out;
	}
	leaf = path->nodes[0];
	item_size = btrfs_item_size_nr(leaf, path->slots[0]);
	if (del_len == item_size) {
		ret = btrfs_del_item(trans, root, path);
		goto out;
	}
	ptr = (unsigned long)ref;
	sub_item_len = name_len + sizeof(*ref);
	item_start = btrfs_item_ptr_offset(leaf, path->slots[0]);
	memmove_extent_buffer(leaf, ptr, ptr + sub_item_len,
			      item_size - (ptr + sub_item_len - item_start));
	ret = btrfs_truncate_item(trans, root, path,
				  item_size - sub_item_len, 1);
	BUG_ON(ret);
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 10
0
/*
 * xattrs work a lot like directories, this inserts an xattr item
 * into the tree
 */
int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans,
			    struct btrfs_root *root, const char *name,
			    u16 name_len, const void *data, u16 data_len,
			    u64 dir)
{
	int ret = 0;
	struct btrfs_path *path;
	struct btrfs_dir_item *dir_item;
	unsigned long name_ptr, data_ptr;
	struct btrfs_key key, location;
	struct btrfs_disk_key disk_key;
	struct extent_buffer *leaf;
	u32 data_size;

	key.objectid = dir;
	btrfs_set_key_type(&key, BTRFS_XATTR_ITEM_KEY);
	key.offset = btrfs_name_hash(name, name_len);
	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	if (name_len + data_len + sizeof(struct btrfs_dir_item) >
	    BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item))
		return -ENOSPC;

	data_size = sizeof(*dir_item) + name_len + data_len;
	dir_item = insert_with_overflow(trans, root, path, &key, data_size,
					name, name_len);
	/*
	 * FIXME: at some point we should handle xattr's that are larger than
	 * what we can fit in our leaf.  We set location to NULL b/c we arent
	 * pointing at anything else, that will change if we store the xattr
	 * data in a separate inode.
	 */
	BUG_ON(IS_ERR(dir_item));
	memset(&location, 0, sizeof(location));

	leaf = path->nodes[0];
	btrfs_cpu_key_to_disk(&disk_key, &location);
	btrfs_set_dir_item_key(leaf, dir_item, &disk_key);
	btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR);
	btrfs_set_dir_name_len(leaf, dir_item, name_len);
	btrfs_set_dir_transid(leaf, dir_item, trans->transid);
	btrfs_set_dir_data_len(leaf, dir_item, data_len);
	name_ptr = (unsigned long)(dir_item + 1);
	data_ptr = (unsigned long)((char *)name_ptr + name_len);

	write_extent_buffer(leaf, name, name_ptr, name_len);
	write_extent_buffer(leaf, data, data_ptr, data_len);
	btrfs_mark_buffer_dirty(path->nodes[0]);

	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 11
0
static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr,
				  u64 num_bytes, u64 parent, u64 root_objectid)
{
	struct btrfs_trans_handle trans;
	struct btrfs_extent_item *item;
	struct btrfs_extent_inline_ref *iref;
	struct btrfs_tree_block_info *block_info;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	struct btrfs_key ins;
	u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info);
	int ret;

	btrfs_init_dummy_trans(&trans);

	ins.objectid = bytenr;
	ins.type = BTRFS_EXTENT_ITEM_KEY;
	ins.offset = num_bytes;

	path = btrfs_alloc_path();
	if (!path) {
		test_msg("Couldn't allocate path\n");
		return -ENOMEM;
	}

	path->leave_spinning = 1;
	ret = btrfs_insert_empty_item(&trans, root, path, &ins, size);
	if (ret) {
		test_msg("Couldn't insert ref %d\n", ret);
		btrfs_free_path(path);
		return ret;
	}

	leaf = path->nodes[0];
	item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item);
	btrfs_set_extent_refs(leaf, item, 1);
	btrfs_set_extent_generation(leaf, item, 1);
	btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK);
	block_info = (struct btrfs_tree_block_info *)(item + 1);
	btrfs_set_tree_block_level(leaf, block_info, 1);
	iref = (struct btrfs_extent_inline_ref *)(block_info + 1);
	if (parent > 0) {
		btrfs_set_extent_inline_ref_type(leaf, iref,
						 BTRFS_SHARED_BLOCK_REF_KEY);
		btrfs_set_extent_inline_ref_offset(leaf, iref, parent);
	} else {
		btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY);
		btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid);
	}
	btrfs_free_path(path);
	return 0;
}
Ejemplo n.º 12
0
int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
{
	struct extent_buffer *leaf;
	struct btrfs_path *path;
	struct btrfs_key key;
	int err = 0;
	int ret;

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

	key.objectid = BTRFS_ORPHAN_OBJECTID;
	key.type = BTRFS_ORPHAN_ITEM_KEY;
	key.offset = 0;

	while (1) {
		ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
		if (ret < 0) {
			err = ret;
			break;
		}

		leaf = path->nodes[0];
		if (path->slots[0] >= btrfs_header_nritems(leaf)) {
			ret = btrfs_next_leaf(tree_root, path);
			if (ret < 0)
				err = ret;
			if (ret != 0)
				break;
			leaf = path->nodes[0];
		}

		btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
		btrfs_release_path(tree_root, path);

		if (key.objectid != BTRFS_ORPHAN_OBJECTID ||
		    key.type != BTRFS_ORPHAN_ITEM_KEY)
			break;

		ret = btrfs_find_dead_roots(tree_root, key.offset);
		if (ret) {
			err = ret;
			break;
		}

		key.offset++;
	}

	btrfs_free_path(path);
	return err;
}
Ejemplo n.º 13
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.º 14
0
static struct dentry *btrfs_get_parent(struct dentry *child)
{
	struct inode *dir = d_inode(child);
	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
	struct btrfs_root *root = BTRFS_I(dir)->root;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	struct btrfs_root_ref *ref;
	struct btrfs_key key;
	struct btrfs_key found_key;
	int ret;

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

	if (btrfs_ino(BTRFS_I(dir)) == BTRFS_FIRST_FREE_OBJECTID) {
		key.objectid = root->root_key.objectid;
		key.type = BTRFS_ROOT_BACKREF_KEY;
		key.offset = (u64)-1;
		root = fs_info->tree_root;
	} else {
		key.objectid = btrfs_ino(BTRFS_I(dir));
		key.type = BTRFS_INODE_REF_KEY;
		key.offset = (u64)-1;
	}

	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
	if (ret < 0)
		goto fail;

	BUG_ON(ret == 0); /* Key with offset of -1 found */
	if (path->slots[0] == 0) {
		ret = -ENOENT;
		goto fail;
	}

	path->slots[0]--;
	leaf = path->nodes[0];

	btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
	if (found_key.objectid != key.objectid || found_key.type != key.type) {
		ret = -ENOENT;
		goto fail;
	}

	if (found_key.type == BTRFS_ROOT_BACKREF_KEY) {
		ref = btrfs_item_ptr(leaf, path->slots[0],
				     struct btrfs_root_ref);
		key.objectid = btrfs_root_ref_dirid(leaf, ref);
	} else {
int load_free_space_tree(struct btrfs_caching_control *caching_ctl)
{
    struct btrfs_block_group_cache *block_group;
    struct btrfs_fs_info *fs_info;
    struct btrfs_free_space_info *info;
    struct btrfs_path *path;
    u32 extent_count, flags;
    int ret;

    block_group = caching_ctl->block_group;
    fs_info = block_group->fs_info;

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

    /*
     * Just like caching_thread() doesn't want to deadlock on the extent
     * tree, we don't want to deadlock on the free space tree.
     */
    path->skip_locking = 1;
    path->search_commit_root = 1;
    path->reada = 1;

    info = search_free_space_info(NULL, fs_info, block_group, path, 0);
    if (IS_ERR(info)) {
        ret = PTR_ERR(info);
        goto out;
    }
    extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
    flags = btrfs_free_space_flags(path->nodes[0], info);

    /*
     * We left path pointing to the free space info item, so now
     * load_free_space_foo can just iterate through the free space tree from
     * there.
     */
    if (flags & BTRFS_FREE_SPACE_USING_BITMAPS)
        ret = load_free_space_bitmaps(caching_ctl, path, extent_count);
    else
        ret = load_free_space_extents(caching_ctl, path, extent_count);

out:
    btrfs_free_path(path);
    return ret;
}
Ejemplo n.º 16
0
int btrfs_insert_inline_extent(struct btrfs_trans_handle *trans,
			       struct btrfs_root *root, u64 objectid,
			       u64 offset, char *buffer, size_t size)
{
	struct btrfs_key key;
	struct btrfs_path *path;
	struct extent_buffer *leaf;
	unsigned long ptr;
	struct btrfs_file_extent_item *ei;
	u32 datasize;
	int err = 0;
	int ret;

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

	key.objectid = objectid;
	key.offset = offset;
	btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);

	datasize = btrfs_file_extent_calc_inline_size(size);
	ret = btrfs_insert_empty_item(trans, root, path, &key, datasize);
	if (ret) {
		err = ret;
		goto fail;
	}

	leaf = path->nodes[0];
	ei = btrfs_item_ptr(leaf, path->slots[0],
			    struct btrfs_file_extent_item);
	btrfs_set_file_extent_generation(leaf, ei, trans->transid);
	btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE);
	btrfs_set_file_extent_ram_bytes(leaf, ei, size);
	btrfs_set_file_extent_compression(leaf, ei, 0);
	btrfs_set_file_extent_encryption(leaf, ei, 0);
	btrfs_set_file_extent_other_encoding(leaf, ei, 0);

	ptr = btrfs_file_extent_inline_start(ei) + offset - key.offset;
	write_extent_buffer(leaf, buffer, ptr, size);
	btrfs_mark_buffer_dirty(leaf);
fail:
	btrfs_free_path(path);
	return err;
}
Ejemplo n.º 17
0
int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
			     struct btrfs_root *root,
			     u64 objectid, u64 pos,
			     u64 disk_offset, u64 disk_num_bytes,
			     u64 num_bytes, u64 offset, u64 ram_bytes,
			     u8 compression, u8 encryption, u16 other_encoding)
{
	int ret = 0;
	struct btrfs_file_extent_item *item;
	struct btrfs_key file_key;
	struct btrfs_path *path;
	struct extent_buffer *leaf;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	file_key.objectid = objectid;
	file_key.offset = pos;
	btrfs_set_key_type(&file_key, BTRFS_EXTENT_DATA_KEY);

	path->leave_spinning = 1;
	ret = btrfs_insert_empty_item(trans, root, path, &file_key,
				      sizeof(*item));
	if (ret < 0)
		goto out;
	BUG_ON(ret); /* Can't happen */
	leaf = path->nodes[0];
	item = btrfs_item_ptr(leaf, path->slots[0],
			      struct btrfs_file_extent_item);
	btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset);
	btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes);
	btrfs_set_file_extent_offset(leaf, item, offset);
	btrfs_set_file_extent_num_bytes(leaf, item, num_bytes);
	btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes);
	btrfs_set_file_extent_generation(leaf, item, trans->transid);
	btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG);
	btrfs_set_file_extent_compression(leaf, item, compression);
	btrfs_set_file_extent_encryption(leaf, item, encryption);
	btrfs_set_file_extent_other_encoding(leaf, item, other_encoding);

	btrfs_mark_buffer_dirty(leaf);
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 18
0
static int ondisk_del(struct btrfs_trans_handle *trans,
		      struct btrfs_dedup_info *dedup_info, u64 bytenr)
{
	struct btrfs_root *dedup_root = dedup_info->dedup_root;
	struct btrfs_path *path;
	struct btrfs_key key;
	int ret;

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

	key.objectid = bytenr;
	key.type = BTRFS_DEDUP_BYTENR_ITEM_KEY;
	key.offset = 0;

	mutex_lock(&dedup_info->lock);

	ret = ondisk_search_bytenr(trans, dedup_info, path, bytenr, 1);
	if (ret <= 0)
		goto out;

	btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
	btrfs_del_item(trans, dedup_root, path);
	btrfs_release_path(path);

	/* Search for hash item and delete it */
	key.objectid = key.offset;
	key.type = BTRFS_DEDUP_HASH_ITEM_KEY;
	key.offset = bytenr;

	ret = btrfs_search_slot(trans, dedup_root, &key, path, -1, 1);
	if (WARN_ON(ret > 0)) {
		ret = -ENOENT;
		goto out;
	}
	if (ret < 0)
		goto out;
	btrfs_del_item(trans, dedup_root, path);

out:
	btrfs_free_path(path);
	mutex_unlock(&dedup_info->lock);
	return ret;
}
Ejemplo n.º 19
0
int btrfs_dedup_resume(struct btrfs_fs_info *fs_info,
		       struct btrfs_root *dedup_root)
{
	struct btrfs_dedup_status_item *status;
	struct btrfs_key key;
	struct btrfs_path *path;
	u64 blocksize;
	u64 limit;
	u16 type;
	u16 backend;
	int ret = 0;

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

	key.objectid = 0;
	key.type = BTRFS_DEDUP_STATUS_ITEM_KEY;
	key.offset = 0;

	ret = btrfs_search_slot(NULL, dedup_root, &key, path, 0, 0);
	if (ret > 0) {
		ret = -ENOENT;
		goto out;
	} else if (ret < 0) {
		goto out;
	}

	status = btrfs_item_ptr(path->nodes[0], path->slots[0],
				struct btrfs_dedup_status_item);
	blocksize = btrfs_dedup_status_blocksize(path->nodes[0], status);
	limit = btrfs_dedup_status_limit(path->nodes[0], status);
	type = btrfs_dedup_status_hash_type(path->nodes[0], status);
	backend = btrfs_dedup_status_backend(path->nodes[0], status);

	ret = init_dedup_info(fs_info, type, backend, blocksize, limit);
	if (ret < 0)
		goto out;
	fs_info->dedup_info->dedup_root = dedup_root;

out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 20
0
/*
 * lookup the root with the highest offset for a given objectid.  The key we do
 * find is copied into 'key'.  If we find something return 0, otherwise 1, < 0
 * on error.
 */
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid,
			struct btrfs_root_item *item, struct btrfs_key *key)
{
	struct btrfs_path *path;
	struct btrfs_key search_key;
	struct btrfs_key found_key;
	struct extent_buffer *l;
	int ret;
	int slot;

	search_key.objectid = objectid;
	search_key.type = BTRFS_ROOT_ITEM_KEY;
	search_key.offset = (u64)-1;

	path = btrfs_alloc_path();
	if (!path)
		return -ENOMEM;
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
	if (ret < 0)
		goto out;

	BUG_ON(ret == 0);
	if (path->slots[0] == 0) {
		ret = 1;
		goto out;
	}
	l = path->nodes[0];
	slot = path->slots[0] - 1;
	btrfs_item_key_to_cpu(l, &found_key, slot);
	if (found_key.objectid != objectid ||
	    found_key.type != BTRFS_ROOT_ITEM_KEY) {
		ret = 1;
		goto out;
	}
	if (item)
		read_extent_buffer(l, item, btrfs_item_ptr_offset(l, slot),
				   sizeof(*item));
	if (key)
		memcpy(key, &found_key, sizeof(found_key));
	ret = 0;
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 21
0
int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	int ret;

	key.objectid = BTRFS_ORPHAN_OBJECTID;
	key.type = BTRFS_ORPHAN_ITEM_KEY;
	key.offset = offset;

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

	ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);

	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 22
0
int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans,
			     struct btrfs_root *root, u64 offset)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	int ret = 0;

	key.objectid = BTRFS_ORPHAN_OBJECTID;
	btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY);
	key.offset = offset;

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

	ret = btrfs_insert_empty_item(trans, root, path, &key, 0);

	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 23
0
int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
		       u64 root_id, u64 ref_id, u64 dirid, u64 *sequence,
		       const char *name, int name_len)

{
	struct btrfs_path *path;
	struct btrfs_root_ref *ref;
	struct extent_buffer *leaf;
	struct btrfs_key key;
	unsigned long ptr;
	int err = 0;
	int ret;

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

	key.objectid = root_id;
	key.type = BTRFS_ROOT_BACKREF_KEY;
	key.offset = ref_id;
again:
	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
	BUG_ON(ret < 0);
	if (ret == 0) {
		leaf = path->nodes[0];
		ref = btrfs_item_ptr(leaf, path->slots[0],
				     struct btrfs_root_ref);

		WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid);
		WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len);
		ptr = (unsigned long)(ref + 1);
		WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len));
		*sequence = btrfs_root_ref_sequence(leaf, ref);

		ret = btrfs_del_item(trans, tree_root, path);
		if (ret) {
			err = ret;
			goto out;
		}
	} else
Ejemplo n.º 24
0
/*
 *  search forward for a root, starting with objectid 'search_start'
 *  if a root key is found, the objectid we find is filled into 'found_objectid'
 *  and 0 is returned.  < 0 is returned on error, 1 if there is nothing
 *  left in the tree.
 */
int btrfs_search_root(struct btrfs_root *root, u64 search_start,
		      u64 *found_objectid)
{
	struct btrfs_path *path;
	struct btrfs_key search_key;
	int ret;

	root = root->fs_info->tree_root;
	search_key.objectid = search_start;
	search_key.type = (u8)-1;
	search_key.offset = (u64)-1;

	path = btrfs_alloc_path();
	BUG_ON(!path);
again:
	ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
	if (ret < 0)
		goto out;
	if (ret == 0) {
		ret = 1;
		goto out;
	}
	if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
		ret = btrfs_next_leaf(root, path);
		if (ret)
			goto out;
	}
	btrfs_item_key_to_cpu(path->nodes[0], &search_key, path->slots[0]);
	if (search_key.type != BTRFS_ROOT_ITEM_KEY) {
		search_key.offset++;
		btrfs_release_path(root, path);
		goto again;
	}
	ret = 0;
	*found_objectid = search_key.objectid;

out:
	btrfs_free_path(path);
	return ret;
}
static int clear_free_space_tree(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root)
{
    struct btrfs_path *path;
    struct btrfs_key key;
    int nr;
    int ret;

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

    path->leave_spinning = 1;

    key.objectid = 0;
    key.type = 0;
    key.offset = 0;

    while (1) {
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
            goto out;

        nr = btrfs_header_nritems(path->nodes[0]);
        if (!nr)
            break;

        path->slots[0] = 0;
        ret = btrfs_del_items(trans, root, path, 0, nr);
        if (ret)
            goto out;

        btrfs_release_path(path);
    }

    ret = 0;
out:
    btrfs_free_path(path);
    return ret;
}
Ejemplo n.º 26
0
int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
			   struct btrfs_root *root,
			   const char *name, int name_len,
			   u64 inode_objectid, u64 ref_objectid, u64 index)
{
	struct btrfs_path *path;
	struct btrfs_key key;
	struct btrfs_inode_ref *ref;
	unsigned long ptr;
	int ret;
	int ins_len = name_len + sizeof(*ref);

	key.objectid = inode_objectid;
	key.offset = ref_objectid;
	btrfs_set_key_type(&key, BTRFS_INODE_REF_KEY);

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

	ret = btrfs_insert_empty_item(trans, root, path, &key,
				      ins_len);
	if (ret == -EEXIST) {
		u32 old_size;

		if (find_name_in_backref(path, name, name_len, &ref))
			goto out;

		old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
		ret = btrfs_extend_item(trans, root, path, ins_len);
		BUG_ON(ret);
		ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
				     struct btrfs_inode_ref);
		ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size);
		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
		btrfs_set_inode_ref_index(path->nodes[0], ref, index);
		ptr = (unsigned long)(ref + 1);
		ret = 0;
	} else if (ret < 0) {
Ejemplo n.º 27
0
/* drop the root item for 'key' from 'root' */
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   struct btrfs_key *key)
{
	struct btrfs_path *path;
	int ret;
	u32 refs;
	struct btrfs_root_item *ri;
	struct extent_buffer *leaf;

	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
	if (ret < 0)
		goto out;

	BUG_ON(ret != 0);
	leaf = path->nodes[0];
	ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);

	refs = btrfs_disk_root_refs(leaf, ri);
	BUG_ON(refs != 0);
	ret = btrfs_del_item(trans, root, path);
out:
	btrfs_release_path(root, path);
	btrfs_free_path(path);
	return ret;
}

#if 0 /* this will get used when snapshot deletion is implemented */
int btrfs_del_root_ref(struct btrfs_trans_handle *trans,
		       struct btrfs_root *tree_root,
		       u64 root_id, u8 type, u64 ref_id)
{
	struct btrfs_key key;
	int ret;
	struct btrfs_path *path;

	path = btrfs_alloc_path();

	key.objectid = root_id;
	key.type = type;
	key.offset = ref_id;

	ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1);
	BUG_ON(ret);

	ret = btrfs_del_item(trans, tree_root, path);
	BUG_ON(ret);

	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 28
0
/* drop the root item for 'key' from 'root' */
int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		   struct btrfs_key *key)
{
	struct btrfs_path *path;
	int ret;
	struct btrfs_root_item *ri;
	struct extent_buffer *leaf;

	path = btrfs_alloc_path();
	BUG_ON(!path);
	ret = btrfs_search_slot(trans, root, key, path, -1, 1);
	if (ret < 0)
		goto out;

	BUG_ON(ret != 0);
	leaf = path->nodes[0];
	ri = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_item);

	ret = btrfs_del_item(trans, root, path);
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 29
0
/*
 * copy the data in 'item' into the btree
 */
int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
		      *root, struct btrfs_key *key, struct btrfs_root_item
		      *item)
{
	struct btrfs_path *path;
	struct extent_buffer *l;
	int ret;
	int slot;
	unsigned long ptr;

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

	ret = btrfs_search_slot(trans, root, key, path, 0, 1);
	if (ret < 0) {
		btrfs_abort_transaction(trans, root, ret);
		goto out;
	}

	if (ret != 0) {
		btrfs_print_leaf(root, path->nodes[0]);
		printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
		       (unsigned long long)key->objectid, key->type,
		       (unsigned long long)key->offset);
		BUG_ON(1);
	}

	l = path->nodes[0];
	slot = path->slots[0];
	ptr = btrfs_item_ptr_offset(l, slot);
	write_extent_buffer(l, item, ptr, sizeof(*item));
	btrfs_mark_buffer_dirty(path->nodes[0]);
out:
	btrfs_free_path(path);
	return ret;
}
Ejemplo n.º 30
0
/*
 * Punch hole ranged [offset,len) for the file given by ino and root.
 *
 * Unlink kernel punch_hole, which will not zero/free existing extent,
 * instead it will return -EEXIST if there is any extents in the hole
 * range.
 */
int btrfs_punch_hole(struct btrfs_trans_handle *trans,
		     struct btrfs_root *root,
		     u64 ino, u64 offset, u64 len)
{
	struct btrfs_path *path;
	int ret = 0;

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

	ret = btrfs_get_extent(NULL, root, path, ino, offset, len, 0);
	if (ret < 0)
		goto out;
	if (ret == 0) {
		ret = -EEXIST;
		goto out;
	}

	ret = btrfs_insert_file_extent(trans, root, ino, offset, 0, 0, len);
out:
	btrfs_free_path(path);
	return ret;
}