Exemplo n.º 1
0
int __btrfs_setxattr(struct btrfs_trans_handle *trans,
		     struct inode *inode, const char *name,
		     const void *value, size_t size, int flags)
{
	struct btrfs_root *root = BTRFS_I(inode)->root;
	int ret;

	if (trans)
		return do_setxattr(trans, inode, name, value, size, flags);

	trans = btrfs_start_transaction(root, 2);
	if (IS_ERR(trans))
		return PTR_ERR(trans);

	ret = do_setxattr(trans, inode, name, value, size, flags);
	if (ret)
		goto out;

	inode->i_ctime = CURRENT_TIME;
	ret = btrfs_update_inode(trans, root, inode);
	BUG_ON(ret);
out:
	btrfs_end_transaction(trans, root);
	return ret;
}
Exemplo n.º 2
0
/*
 * after copy_from_user, pages need to be dirtied and we need to make
 * sure holes are created between the current EOF and the start of
 * any next extents (if required).
 *
 * this also makes the decision about creating an inline extent vs
 * doing real data extents, marking pages dirty and delalloc as required.
 */
static noinline int dirty_and_release_pages(struct btrfs_trans_handle *trans,
				   struct btrfs_root *root,
				   struct file *file,
				   struct page **pages,
				   size_t num_pages,
				   loff_t pos,
				   size_t write_bytes)
{
	int err = 0;
	int i;
	struct inode *inode = fdentry(file)->d_inode;
	struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
	u64 hint_byte;
	u64 num_bytes;
	u64 start_pos;
	u64 end_of_last_block;
	u64 end_pos = pos + write_bytes;
	loff_t isize = i_size_read(inode);

	start_pos = pos & ~((u64)root->sectorsize - 1);
	num_bytes = (write_bytes + pos - start_pos +
		    root->sectorsize - 1) & ~((u64)root->sectorsize - 1);

	end_of_last_block = start_pos + num_bytes - 1;

	lock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
	trans = btrfs_join_transaction(root, 1);
	if (!trans) {
		err = -ENOMEM;
		goto out_unlock;
	}
	btrfs_set_trans_block_group(trans, inode);
	hint_byte = 0;

	set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS);

	/* check for reserved extents on each page, we don't want
	 * to reset the delalloc bit on things that already have
	 * extents reserved.
	 */
	btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block);
	for (i = 0; i < num_pages; i++) {
		struct page *p = pages[i];
		SetPageUptodate(p);
		ClearPageChecked(p);
		set_page_dirty(p);
	}
	if (end_pos > isize) {
		i_size_write(inode, end_pos);
		/* we've only changed i_size in ram, and we haven't updated
		 * the disk i_size.  There is no need to log the inode
		 * at this time.
		 */
	}
	err = btrfs_end_transaction(trans, root);
out_unlock:
	unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS);
	return err;
}
Exemplo n.º 3
0
static struct btrfs_trans_handle *start_transaction(struct btrfs_root *root,
        u64 num_items, int type)
{
    struct btrfs_trans_handle *h;
    struct btrfs_transaction *cur_trans;
    int retries = 0;
    int ret;
again:
    h = kmem_cache_alloc(btrfs_trans_handle_cachep, GFP_NOFS);
    if (!h)
        return ERR_PTR(-ENOMEM);

    mutex_lock(&root->fs_info->trans_mutex);
    if (may_wait_transaction(root, type))
        wait_current_trans(root);

    ret = join_transaction(root);
    BUG_ON(ret);

    cur_trans = root->fs_info->running_transaction;
    cur_trans->use_count++;
    mutex_unlock(&root->fs_info->trans_mutex);

    h->transid = cur_trans->transid;
    h->transaction = cur_trans;
    h->blocks_used = 0;
    h->block_group = 0;
    h->bytes_reserved = 0;
    h->delayed_ref_updates = 0;
    h->block_rsv = NULL;

    smp_mb();
    if (cur_trans->blocked && may_wait_transaction(root, type)) {
        btrfs_commit_transaction(h, root);
        goto again;
    }

    if (num_items > 0) {
        ret = btrfs_trans_reserve_metadata(h, root, num_items,
                                           &retries);
        if (ret == -EAGAIN) {
            btrfs_commit_transaction(h, root);
            goto again;
        }
        if (ret < 0) {
            btrfs_end_transaction(h, root);
            return ERR_PTR(ret);
        }
    }

    mutex_lock(&root->fs_info->trans_mutex);
    record_root_in_trans(h, root);
    mutex_unlock(&root->fs_info->trans_mutex);

    if (!current->journal_info && type != TRANS_USERSPACE)
        current->journal_info = h;
    return h;
}
int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
{
    struct btrfs_trans_handle *trans;
    struct btrfs_root *tree_root = fs_info->tree_root;
    struct btrfs_root *free_space_root;
    struct btrfs_block_group_cache *block_group;
    struct rb_node *node;
    int ret;

    trans = btrfs_start_transaction(tree_root, 0);
    if (IS_ERR(trans))
        return PTR_ERR(trans);

    fs_info->creating_free_space_tree = 1;
    free_space_root = btrfs_create_tree(trans, fs_info,
                                        BTRFS_FREE_SPACE_TREE_OBJECTID);
    if (IS_ERR(free_space_root)) {
        ret = PTR_ERR(free_space_root);
        goto abort;
    }
    fs_info->free_space_root = free_space_root;

    node = rb_first(&fs_info->block_group_cache_tree);
    while (node) {
        block_group = rb_entry(node, struct btrfs_block_group_cache,
                               cache_node);
        ret = populate_free_space_tree(trans, fs_info, block_group);
        if (ret)
            goto abort;
        node = rb_next(node);
    }

    btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE);
    fs_info->creating_free_space_tree = 0;

    ret = btrfs_commit_transaction(trans, tree_root);
    if (ret)
        return ret;

    return 0;

abort:
    fs_info->creating_free_space_tree = 0;
    btrfs_abort_transaction(trans, ret);
    btrfs_end_transaction(trans, tree_root);
    return ret;
}
Exemplo n.º 5
0
static noinline int finish_pending_snapshot(struct btrfs_fs_info *fs_info,
				   struct btrfs_pending_snapshot *pending)
{
	int ret;
	int namelen;
	u64 index = 0;
	struct btrfs_trans_handle *trans;
	struct inode *parent_inode;
	struct inode *inode;
	struct btrfs_root *parent_root;

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

	/*
	 * insert the directory item
	 */
	namelen = strlen(pending->name);
	ret = btrfs_set_inode_index(parent_inode, &index);
	ret = btrfs_insert_dir_item(trans, parent_root,
			    pending->name, namelen,
			    parent_inode->i_ino,
			    &pending->root_key, BTRFS_FT_DIR, index);

	if (ret)
		goto fail;

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

	ret = btrfs_add_root_ref(trans, parent_root->fs_info->tree_root,
				 pending->root_key.objectid,
				 parent_root->root_key.objectid,
				 parent_inode->i_ino, index, pending->name,
				 namelen);

	BUG_ON(ret);

	inode = btrfs_lookup_dentry(parent_inode, pending->dentry);
	d_instantiate(pending->dentry, inode);
fail:
	btrfs_end_transaction(trans, fs_info->fs_root);
	return ret;
}
int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
{
    struct btrfs_trans_handle *trans;
    struct btrfs_root *tree_root = fs_info->tree_root;
    struct btrfs_root *free_space_root = fs_info->free_space_root;
    int ret;

    trans = btrfs_start_transaction(tree_root, 0);
    if (IS_ERR(trans))
        return PTR_ERR(trans);

    btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE);
    fs_info->free_space_root = NULL;

    ret = clear_free_space_tree(trans, free_space_root);
    if (ret)
        goto abort;

    ret = btrfs_del_root(trans, tree_root, &free_space_root->root_key);
    if (ret)
        goto abort;

    list_del(&free_space_root->dirty_list);

    btrfs_tree_lock(free_space_root->node);
    clean_tree_block(trans, tree_root->fs_info, free_space_root->node);
    btrfs_tree_unlock(free_space_root->node);
    btrfs_free_tree_block(trans, free_space_root, free_space_root->node,
                          0, 1);

    free_extent_buffer(free_space_root->node);
    free_extent_buffer(free_space_root->commit_root);
    kfree(free_space_root);

    ret = btrfs_commit_transaction(trans, tree_root);
    if (ret)
        return ret;

    return 0;

abort:
    btrfs_abort_transaction(trans, ret);
    btrfs_end_transaction(trans, tree_root);
    return ret;
}
Exemplo n.º 7
0
static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
			       u64 subid)
{
	struct btrfs_trans_handle *trans;
	int ret;

	/* 1 - for the uuid item */
	trans = btrfs_start_transaction(uuid_root, 1);
	if (IS_ERR(trans)) {
		ret = PTR_ERR(trans);
		goto out;
	}

	ret = btrfs_uuid_tree_remove(trans, uuid, type, subid);
	btrfs_end_transaction(trans);

out:
	return ret;
}
Exemplo n.º 8
0
static int generic_search(struct inode *inode, u64 file_pos,
			struct btrfs_dedup_hash *hash)
{
	int ret;
	struct btrfs_root *root = BTRFS_I(inode)->root;
	struct btrfs_fs_info *fs_info = root->fs_info;
	struct btrfs_trans_handle *trans;
	struct btrfs_delayed_ref_root *delayed_refs;
	struct btrfs_delayed_ref_head *head;
	struct btrfs_dedup_info *dedup_info = fs_info->dedup_info;
	u64 bytenr;
	u64 tmp_bytenr;
	u32 num_bytes;

	trans = btrfs_join_transaction(root);
	if (IS_ERR(trans))
		return PTR_ERR(trans);

again:
	mutex_lock(&dedup_info->lock);
	ret = generic_search_hash(dedup_info, hash->hash, &bytenr, &num_bytes);
	if (ret <= 0)
		goto out;

	delayed_refs = &trans->transaction->delayed_refs;

	spin_lock(&delayed_refs->lock);
	head = btrfs_find_delayed_ref_head(trans, bytenr);
	if (!head) {
		/*
		 * We can safely insert a new delayed_ref as long as we
		 * hold delayed_refs->lock.
		 * Only need to use atomic inc_extent_ref()
		 */
		ret = btrfs_inc_extent_ref_atomic(trans, root, bytenr,
				num_bytes, 0, root->root_key.objectid,
				btrfs_ino(inode), file_pos);
		spin_unlock(&delayed_refs->lock);

		if (ret == 0) {
			hash->bytenr = bytenr;
			hash->num_bytes = num_bytes;
			ret = 1;
		}
		goto out;
	}

	/*
	 * We can't lock ref head with dedup_info->lock hold or we will cause
	 * ABBA dead lock.
	 */
	mutex_unlock(&dedup_info->lock);
	ret = btrfs_delayed_ref_lock(trans, head);
	spin_unlock(&delayed_refs->lock);
	if (ret == -EAGAIN)
		goto again;

	mutex_lock(&dedup_info->lock);
	/*
	 * Search again to ensure the hash is still here and bytenr didn't
	 * change
	 */
	ret = generic_search_hash(dedup_info, hash->hash, &tmp_bytenr,
				  &num_bytes);
	if (ret <= 0) {
		mutex_unlock(&head->mutex);
		goto out;
	}
	if (tmp_bytenr != bytenr) {
		mutex_unlock(&head->mutex);
		mutex_unlock(&dedup_info->lock);
		goto again;
	}
	hash->bytenr = bytenr;
	hash->num_bytes = num_bytes;

	/*
	 * Increase the extent ref right now, to avoid delayed ref run
	 * Or we may increase ref on non-exist extent.
	 */
	btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0,
			     root->root_key.objectid,
			     btrfs_ino(inode), file_pos);
	mutex_unlock(&head->mutex);
out:
	mutex_unlock(&dedup_info->lock);
	btrfs_end_transaction(trans, root);

	return ret;
}
Exemplo n.º 9
0
static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
{
	struct inode *inode = file->f_path.dentry->d_inode;
	struct btrfs_inode *ip = BTRFS_I(inode);
	struct btrfs_root *root = ip->root;
	struct btrfs_trans_handle *trans;
	unsigned int flags, oldflags;
	int ret;

	if (copy_from_user(&flags, arg, sizeof(flags)))
		return -EFAULT;

	if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \
		      FS_NOATIME_FL | FS_NODUMP_FL | \
		      FS_SYNC_FL | FS_DIRSYNC_FL))
		return -EOPNOTSUPP;

	if (!is_owner_or_cap(inode))
		return -EACCES;

	mutex_lock(&inode->i_mutex);

	flags = btrfs_mask_flags(inode->i_mode, flags);
	oldflags = btrfs_flags_to_ioctl(ip->flags);
	if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) {
		if (!capable(CAP_LINUX_IMMUTABLE)) {
			ret = -EPERM;
			goto out_unlock;
		}
	}

	ret = mnt_want_write(file->f_path.mnt);
	if (ret)
		goto out_unlock;

	if (flags & FS_SYNC_FL)
		ip->flags |= BTRFS_INODE_SYNC;
	else
		ip->flags &= ~BTRFS_INODE_SYNC;
	if (flags & FS_IMMUTABLE_FL)
		ip->flags |= BTRFS_INODE_IMMUTABLE;
	else
		ip->flags &= ~BTRFS_INODE_IMMUTABLE;
	if (flags & FS_APPEND_FL)
		ip->flags |= BTRFS_INODE_APPEND;
	else
		ip->flags &= ~BTRFS_INODE_APPEND;
	if (flags & FS_NODUMP_FL)
		ip->flags |= BTRFS_INODE_NODUMP;
	else
		ip->flags &= ~BTRFS_INODE_NODUMP;
	if (flags & FS_NOATIME_FL)
		ip->flags |= BTRFS_INODE_NOATIME;
	else
		ip->flags &= ~BTRFS_INODE_NOATIME;
	if (flags & FS_DIRSYNC_FL)
		ip->flags |= BTRFS_INODE_DIRSYNC;
	else
		ip->flags &= ~BTRFS_INODE_DIRSYNC;


	trans = btrfs_join_transaction(root, 1);
	BUG_ON(!trans);

	ret = btrfs_update_inode(trans, root, inode);
	BUG_ON(ret);

	btrfs_update_iflags(inode);
	inode->i_ctime = CURRENT_TIME;
	btrfs_end_transaction(trans, root);

	mnt_drop_write(file->f_path.mnt);
 out_unlock:
	mutex_unlock(&inode->i_mutex);
	return 0;
}
Exemplo n.º 10
0
/*
 * Given a list of roots that need to be deleted, call btrfs_drop_snapshot on
 * all of them
 */
static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
                                     struct list_head *list)
{
    struct btrfs_dirty_root *dirty;
    struct btrfs_trans_handle *trans;
    unsigned long nr;
    u64 num_bytes;
    u64 bytes_used;
    u64 max_useless;
    int ret = 0;
    int err;

    while (!list_empty(list)) {
        struct btrfs_root *root;

        dirty = list_entry(list->prev, struct btrfs_dirty_root, list);
        list_del_init(&dirty->list);

        num_bytes = btrfs_root_used(&dirty->root->root_item);
        root = dirty->latest_root;
        atomic_inc(&root->fs_info->throttles);

        while (1) {
            /*
             * we don't want to jump in and create a bunch of
             * delayed refs if the transaction is starting to close
             */
            wait_transaction_pre_flush(tree_root->fs_info);
            trans = btrfs_start_transaction(tree_root, 1);

            /*
             * we've joined a transaction, make sure it isn't
             * closing right now
             */
            if (trans->transaction->delayed_refs.flushing) {
                btrfs_end_transaction(trans, tree_root);
                continue;
            }

            mutex_lock(&root->fs_info->drop_mutex);
            ret = btrfs_drop_snapshot(trans, dirty->root);
            if (ret != -EAGAIN)
                break;
            mutex_unlock(&root->fs_info->drop_mutex);

            err = btrfs_update_root(trans,
                                    tree_root,
                                    &dirty->root->root_key,
                                    &dirty->root->root_item);
            if (err)
                ret = err;
            nr = trans->blocks_used;
            ret = btrfs_end_transaction(trans, tree_root);
            BUG_ON(ret);

            btrfs_btree_balance_dirty(tree_root, nr);
            cond_resched();
        }
        BUG_ON(ret);
        atomic_dec(&root->fs_info->throttles);
        wake_up(&root->fs_info->transaction_throttle);

        num_bytes -= btrfs_root_used(&dirty->root->root_item);
        bytes_used = btrfs_root_used(&root->root_item);
        if (num_bytes) {
            mutex_lock(&root->fs_info->trans_mutex);
            btrfs_record_root_in_trans(root);
            mutex_unlock(&root->fs_info->trans_mutex);
            btrfs_set_root_used(&root->root_item,
                                bytes_used - num_bytes);
        }

        ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
        if (ret) {
            BUG();
            break;
        }
        mutex_unlock(&root->fs_info->drop_mutex);

        spin_lock(&root->list_lock);
        list_del_init(&dirty->root->dead_list);
        if (!list_empty(&root->dead_list)) {
            struct btrfs_root *oldest;
            oldest = list_entry(root->dead_list.prev,
                                struct btrfs_root, dead_list);
            max_useless = oldest->root_key.offset - 1;
        } else {
            max_useless = root->root_key.offset - 1;
        }
        spin_unlock(&root->list_lock);

        nr = trans->blocks_used;
        ret = btrfs_end_transaction(trans, tree_root);
        BUG_ON(ret);

        ret = btrfs_remove_leaf_refs(root, max_useless, 0);
        BUG_ON(ret);

        free_extent_buffer(dirty->root->node);
        kfree(dirty->root);
        kfree(dirty);

        btrfs_btree_balance_dirty(tree_root, nr);
        cond_resched();
    }
Exemplo n.º 11
0
int __btrfs_setxattr(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_trans_handle *trans;
	struct btrfs_path *path;
	int ret = 0, mod = 0;

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

	trans = btrfs_join_transaction(root, 1);
	btrfs_set_trans_block_group(trans, inode);

	/* 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);
		if (ret)
			goto out;
		btrfs_release_path(root, path);

		/* if we don't have a value then we are removing the xattr */
		if (!value) {
			mod = 1;
			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, name, strlen(name),
				      value, size, inode->i_ino);
	if (ret)
		goto out;
	mod = 1;

out:
	if (mod) {
		inode->i_ctime = CURRENT_TIME;
		ret = btrfs_update_inode(trans, root, inode);
	}

	btrfs_end_transaction(trans, root);
	btrfs_free_path(path);
	return ret;
}
Exemplo n.º 12
0
/*
 * calls iterate() for every inode that references the extent identified by
 * the given parameters.
 * when the iterator function returns a non-zero value, iteration stops.
 */
int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
				u64 extent_item_objectid, u64 extent_item_pos,
				int search_commit_root,
				iterate_extent_inodes_t *iterate, void *ctx)
{
	int ret;
	struct btrfs_trans_handle *trans = NULL;
	struct ulist *refs = NULL;
	struct ulist *roots = NULL;
	struct ulist_node *ref_node = NULL;
	struct ulist_node *root_node = NULL;
	struct seq_list tree_mod_seq_elem = {};
	struct ulist_iterator ref_uiter;
	struct ulist_iterator root_uiter;

	pr_debug("resolving all inodes for extent %llu\n",
			extent_item_objectid);

	if (!search_commit_root) {
		trans = btrfs_join_transaction(fs_info->extent_root);
		if (IS_ERR(trans))
			return PTR_ERR(trans);
		btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem);
	} else {
		down_read(&fs_info->commit_root_sem);
	}

	ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid,
				   tree_mod_seq_elem.seq, &refs,
				   &extent_item_pos);
	if (ret)
		goto out;

	ULIST_ITER_INIT(&ref_uiter);
	while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) {
		ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val,
					     tree_mod_seq_elem.seq, &roots);
		if (ret)
			break;
		ULIST_ITER_INIT(&root_uiter);
		while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
			pr_debug("root %llu references leaf %llu, data list "
				 "%#llx\n", root_node->val, ref_node->val,
				 ref_node->aux);
			ret = iterate_leaf_refs((struct extent_inode_elem *)
						(uintptr_t)ref_node->aux,
						root_node->val,
						extent_item_objectid,
						iterate, ctx);
		}
		ulist_free(roots);
	}

	free_leaf_list(refs);
out:
	if (!search_commit_root) {
		btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem);
		btrfs_end_transaction(trans, fs_info->extent_root);
	} else {
		up_read(&fs_info->commit_root_sem);
	}

	return ret;
}