Ejemplo n.º 1
0
static noinline int commit_fs_roots(struct btrfs_trans_handle *trans,
                                    struct btrfs_root *root)
{
    struct btrfs_root *gang[8];
    struct btrfs_fs_info *fs_info = root->fs_info;
    int i;
    int ret;
    int err = 0;

    while (1) {
        ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix,
                                         (void **)gang, 0,
                                         ARRAY_SIZE(gang),
                                         BTRFS_ROOT_TRANS_TAG);
        if (ret == 0)
            break;
        for (i = 0; i < ret; i++) {
            root = gang[i];
            radix_tree_tag_clear(&fs_info->fs_roots_radix,
                                 (unsigned long)root->root_key.objectid,
                                 BTRFS_ROOT_TRANS_TAG);

            btrfs_free_log(trans, root);
            btrfs_update_reloc_root(trans, root);
            btrfs_orphan_commit_root(trans, root);

            if (root->commit_root != root->node) {
                switch_commit_root(root);
                btrfs_set_root_node(&root->root_item,
                                    root->node);
            }

            err = btrfs_update_root(trans, fs_info->tree_root,
                                    &root->root_key,
                                    &root->root_item);
            if (err)
                break;
        }
    }
    return err;
}
Ejemplo n.º 2
0
/*
 * at transaction commit time we need to schedule the old roots for
 * deletion via btrfs_drop_snapshot.  This runs through all the
 * reference counted roots that were modified in the current
 * transaction and puts them into the drop list
 */
static noinline int add_dirty_roots(struct btrfs_trans_handle *trans,
                                    struct radix_tree_root *radix,
                                    struct list_head *list)
{
    struct btrfs_dirty_root *dirty;
    struct btrfs_root *gang[8];
    struct btrfs_root *root;
    int i;
    int ret;
    int err = 0;
    u32 refs;

    while (1) {
        ret = radix_tree_gang_lookup_tag(radix, (void **)gang, 0,
                                         ARRAY_SIZE(gang),
                                         BTRFS_ROOT_TRANS_TAG);
        if (ret == 0)
            break;
        for (i = 0; i < ret; i++) {
            root = gang[i];
            radix_tree_tag_clear(radix,
                                 (unsigned long)root->root_key.objectid,
                                 BTRFS_ROOT_TRANS_TAG);

            BUG_ON(!root->ref_tree);
            dirty = root->dirty_root;

            btrfs_free_log(trans, root);
            btrfs_free_reloc_root(trans, root);

            if (root->commit_root == root->node) {
                WARN_ON(root->node->start !=
                        btrfs_root_bytenr(&root->root_item));

                free_extent_buffer(root->commit_root);
                root->commit_root = NULL;
                root->dirty_root = NULL;

                spin_lock(&root->list_lock);
                list_del_init(&dirty->root->dead_list);
                spin_unlock(&root->list_lock);

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

                /* make sure to update the root on disk
                 * so we get any updates to the block used
                 * counts
                 */
                err = btrfs_update_root(trans,
                                        root->fs_info->tree_root,
                                        &root->root_key,
                                        &root->root_item);
                continue;
            }

            memset(&root->root_item.drop_progress, 0,
                   sizeof(struct btrfs_disk_key));
            root->root_item.drop_level = 0;
            root->commit_root = NULL;
            root->dirty_root = NULL;
            root->root_key.offset = root->fs_info->generation;
            btrfs_set_root_bytenr(&root->root_item,
                                  root->node->start);
            btrfs_set_root_level(&root->root_item,
                                 btrfs_header_level(root->node));
            btrfs_set_root_generation(&root->root_item,
                                      root->root_key.offset);

            err = btrfs_insert_root(trans, root->fs_info->tree_root,
                                    &root->root_key,
                                    &root->root_item);
            if (err)
                break;

            refs = btrfs_root_refs(&dirty->root->root_item);
            btrfs_set_root_refs(&dirty->root->root_item, refs - 1);
            err = btrfs_update_root(trans, root->fs_info->tree_root,
                                    &dirty->root->root_key,
                                    &dirty->root->root_item);

            BUG_ON(err);
            if (refs == 1) {
                list_add(&dirty->list, list);
            } else {
                WARN_ON(1);
                free_extent_buffer(dirty->root->node);
                kfree(dirty->root);
                kfree(dirty);
            }
        }
    }
    return err;
}