예제 #1
0
/*
 * Make a dir under the parent inode 'parent_ino' with 'name'
 * and 'mode', The owner will be root/root.
 */
int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root,
		char *name, int namelen, u64 parent_ino, u64 *ino, int mode)
{
	struct btrfs_dir_item *dir_item;
	struct btrfs_path *path;
	u64 ret_ino = 0;
	int ret = 0;

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

	if (ino && *ino)
		ret_ino = *ino;

	dir_item = btrfs_lookup_dir_item(NULL, root, path, parent_ino,
					 name, namelen, 0);
	if (IS_ERR(dir_item)) {
		ret = PTR_ERR(dir_item);
		goto out;
	}

	if (dir_item) {
		struct btrfs_key found_key;

		/*
		 * Already have conflicting name, check if it is a dir.
		 * Either way, no need to continue.
		 */
		btrfs_dir_item_key_to_cpu(path->nodes[0], dir_item, &found_key);
		ret_ino = found_key.objectid;
		if (btrfs_dir_type(path->nodes[0], dir_item) != BTRFS_FT_DIR)
			ret = -EEXIST;
		goto out;
	}

	if (!ret_ino)
		/*
		 * This is *UNSAFE* if some leaf is corrupted,
		 * only used as a fallback method. Caller should either
		 * ensure the fs is OK or pass ino with unused inode number.
		 */
		ret = btrfs_find_free_objectid(NULL, root, parent_ino,
					       &ret_ino);
	if (ret)
		goto out;
	ret = btrfs_new_inode(trans, root, ret_ino, mode | S_IFDIR);
	if (ret)
		goto out;
	ret = btrfs_add_link(trans, root, ret_ino, parent_ino, name, namelen,
			     BTRFS_FT_DIR, NULL, 1);
	if (ret)
		goto out;
out:
	btrfs_free_path(path);
	if (ret == 0 && ino)
		*ino = ret_ino;
	return ret;
}
예제 #2
0
/*
 * new snapshots need to be created at a very specific time in the
 * transaction commit.  This does the actual creation
 */
static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
				   struct btrfs_fs_info *fs_info,
				   struct btrfs_pending_snapshot *pending)
{
	struct btrfs_key key;
	struct btrfs_root_item *new_root_item;
	struct btrfs_root *tree_root = fs_info->tree_root;
	struct btrfs_root *root = pending->root;
	struct extent_buffer *tmp;
	struct extent_buffer *old;
	int ret;
	u64 objectid;

	new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
	if (!new_root_item) {
		ret = -ENOMEM;
		goto fail;
	}
	ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid);
	if (ret)
		goto fail;

	record_root_in_trans(trans, root);
	btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
	memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));

	key.objectid = objectid;
	/* record when the snapshot was created in key.offset */
	key.offset = trans->transid;
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);

	old = btrfs_lock_root_node(root);
	btrfs_cow_block(trans, root, old, NULL, 0, &old);
	btrfs_set_lock_blocking(old);

	btrfs_copy_root(trans, root, old, &tmp, objectid);
	btrfs_tree_unlock(old);
	free_extent_buffer(old);

	btrfs_set_root_node(new_root_item, tmp);
	ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
				new_root_item);
	btrfs_tree_unlock(tmp);
	free_extent_buffer(tmp);
	if (ret)
		goto fail;

	key.offset = (u64)-1;
	memcpy(&pending->root_key, &key, sizeof(key));
fail:
	kfree(new_root_item);
	btrfs_unreserve_metadata_space(root, 6);
	return ret;
}
예제 #3
0
static noinline int create_subvol(struct btrfs_root *root,
				  struct dentry *dentry,
				  char *name, int namelen)
{
	struct btrfs_trans_handle *trans;
	struct btrfs_key key;
	struct btrfs_root_item root_item;
	struct btrfs_inode_item *inode_item;
	struct extent_buffer *leaf;
	struct btrfs_root *new_root;
	struct inode *dir = dentry->d_parent->d_inode;
	int ret;
	int err;
	u64 objectid;
	u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID;
	u64 index = 0;

	ret = btrfs_find_free_objectid(NULL, root->fs_info->tree_root,
				       0, &objectid);
	if (ret)
		return ret;
	/*
	 * 1 - inode item
	 * 2 - refs
	 * 1 - root item
	 * 2 - dir items
	 */
	trans = btrfs_start_transaction(root, 6);
	if (IS_ERR(trans))
		return PTR_ERR(trans);

	leaf = btrfs_alloc_free_block(trans, root, root->leafsize,
				      0, objectid, NULL, 0, 0, 0);
	if (IS_ERR(leaf)) {
		ret = PTR_ERR(leaf);
		goto fail;
	}

	memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
	btrfs_set_header_bytenr(leaf, leaf->start);
	btrfs_set_header_generation(leaf, trans->transid);
	btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
	btrfs_set_header_owner(leaf, objectid);

	write_extent_buffer(leaf, root->fs_info->fsid,
			    (unsigned long)btrfs_header_fsid(leaf),
			    BTRFS_FSID_SIZE);
	write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
			    (unsigned long)btrfs_header_chunk_tree_uuid(leaf),
			    BTRFS_UUID_SIZE);
	btrfs_mark_buffer_dirty(leaf);

	inode_item = &root_item.inode;
	memset(inode_item, 0, sizeof(*inode_item));
	inode_item->generation = cpu_to_le64(1);
	inode_item->size = cpu_to_le64(3);
	inode_item->nlink = cpu_to_le32(1);
	inode_item->nbytes = cpu_to_le64(root->leafsize);
	inode_item->mode = cpu_to_le32(S_IFDIR | 0755);

	root_item.flags = 0;
	root_item.byte_limit = 0;
	inode_item->flags = cpu_to_le64(BTRFS_INODE_ROOT_ITEM_INIT);

	btrfs_set_root_bytenr(&root_item, leaf->start);
	btrfs_set_root_generation(&root_item, trans->transid);
	btrfs_set_root_level(&root_item, 0);
	btrfs_set_root_refs(&root_item, 1);
	btrfs_set_root_used(&root_item, leaf->len);
	btrfs_set_root_last_snapshot(&root_item, 0);

	memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
	root_item.drop_level = 0;

	btrfs_tree_unlock(leaf);
	free_extent_buffer(leaf);
	leaf = NULL;

	btrfs_set_root_dirid(&root_item, new_dirid);

	key.objectid = objectid;
	key.offset = 0;
	btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
	ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key,
				&root_item);
	if (ret)
		goto fail;

	key.offset = (u64)-1;
	new_root = btrfs_read_fs_root_no_name(root->fs_info, &key);
	BUG_ON(IS_ERR(new_root));

	btrfs_record_root_in_trans(trans, new_root);

	ret = btrfs_create_subvol_root(trans, new_root, new_dirid,
				       BTRFS_I(dir)->block_group);
	/*
	 * insert the directory item
	 */
	ret = btrfs_set_inode_index(dir, &index);
	BUG_ON(ret);

	ret = btrfs_insert_dir_item(trans, root,
				    name, namelen, dir->i_ino, &key,
				    BTRFS_FT_DIR, index);
	if (ret)
		goto fail;

	btrfs_i_size_write(dir, dir->i_size + namelen * 2);
	ret = btrfs_update_inode(trans, root, dir);
	BUG_ON(ret);

	ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
				 objectid, root->root_key.objectid,
				 dir->i_ino, index, name, namelen);

	BUG_ON(ret);

	d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
fail:
	err = btrfs_commit_transaction(trans, root);
	if (err && !ret)
		ret = err;
	return ret;
}
예제 #4
0
static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
        struct btrfs_fs_info *fs_info,
        struct btrfs_pending_snapshot *pending)
{
    struct btrfs_key key;
    struct btrfs_root_item *new_root_item;
    struct btrfs_root *tree_root = fs_info->tree_root;
    struct btrfs_root *root = pending->root;
    struct btrfs_root *parent_root;
    struct inode *parent_inode;
    struct dentry *dentry;
    struct extent_buffer *tmp;
    struct extent_buffer *old;
    int ret;
    int retries = 0;
    u64 to_reserve = 0;
    u64 index = 0;
    u64 objectid;

    new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
    if (!new_root_item) {
        pending->error = -ENOMEM;
        goto fail;
    }

    ret = btrfs_find_free_objectid(trans, tree_root, 0, &objectid);
    if (ret) {
        pending->error = ret;
        goto fail;
    }

    btrfs_reloc_pre_snapshot(trans, pending, &to_reserve);
    btrfs_orphan_pre_snapshot(trans, pending, &to_reserve);

    if (to_reserve > 0) {
        ret = btrfs_block_rsv_add(trans, root, &pending->block_rsv,
                                  to_reserve, &retries);
        if (ret) {
            pending->error = ret;
            goto fail;
        }
    }

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

    trans->block_rsv = &pending->block_rsv;

    dentry = pending->dentry;
    parent_inode = dentry->d_parent->d_inode;
    parent_root = BTRFS_I(parent_inode)->root;
    record_root_in_trans(trans, parent_root);

    /*
     * insert the directory item
     */
    ret = btrfs_set_inode_index(parent_inode, &index);
    BUG_ON(ret);
    ret = btrfs_insert_dir_item(trans, parent_root,
                                dentry->d_name.name, dentry->d_name.len,
                                parent_inode->i_ino, &key,
                                BTRFS_FT_DIR, index);
    BUG_ON(ret);

    btrfs_i_size_write(parent_inode, parent_inode->i_size +
                       dentry->d_name.len * 2);
    ret = btrfs_update_inode(trans, parent_root, parent_inode);
    BUG_ON(ret);

    record_root_in_trans(trans, root);
    btrfs_set_root_last_snapshot(&root->root_item, trans->transid);
    memcpy(new_root_item, &root->root_item, sizeof(*new_root_item));

    old = btrfs_lock_root_node(root);
    btrfs_cow_block(trans, root, old, NULL, 0, &old);
    btrfs_set_lock_blocking(old);

    btrfs_copy_root(trans, root, old, &tmp, objectid);
    btrfs_tree_unlock(old);
    free_extent_buffer(old);

    btrfs_set_root_node(new_root_item, tmp);
    /* record when the snapshot was created in key.offset */
    key.offset = trans->transid;
    ret = btrfs_insert_root(trans, tree_root, &key, new_root_item);
    btrfs_tree_unlock(tmp);
    free_extent_buffer(tmp);
    BUG_ON(ret);

    /*
     * insert root back/forward references
     */
    ret = btrfs_add_root_ref(trans, tree_root, objectid,
                             parent_root->root_key.objectid,
                             parent_inode->i_ino, index,
                             dentry->d_name.name, dentry->d_name.len);
    BUG_ON(ret);

    key.offset = (u64)-1;
    pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key);
    BUG_ON(IS_ERR(pending->snap));

    btrfs_reloc_post_snapshot(trans, pending);
    btrfs_orphan_post_snapshot(trans, pending);
fail:
    kfree(new_root_item);
    btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
    return 0;
}