On 13.04.2012 04:53, Tsutomu Itoh wrote:
> Hi, Arne,
>
> (2012/04/13 0:54), Arne Jansen wrote:
>> This is an implementation of snapshot deletion using the readahead
>> framework. Multiple snapshots can be deleted at once and the trees
>> are not enumerated sequentially but in parallel in many branches.
>> This way readahead can reorder the request to better utilize all
>> disks. For a more detailed description see inline comments.
>>
>> Signed-off-by: Arne Jansen<sensille@xxxxxxx>
>> ---
[snip]
>> +/*
>> + * read the saved state from the droptree inode and prepare everything so
>> + * it gets started by droptree_restart
>> + */
>> +static int droptree_read_state(struct btrfs_fs_info *fs_info,
>> + struct inode *inode,
>> + struct reada_control *top_rc,
>> + struct list_head *droplist)
>> +{
>> + struct io_ctl io_ctl;
>> + u32 version;
>> + u64 generation;
>> + struct droptree_node **stack;
>> + int ret = 0;
>> +
>> + stack = kmalloc(sizeof(*stack) * BTRFS_MAX_LEVEL, GFP_NOFS);
>> + if (!stack)
>> + return -ENOMEM;
>> +
>> + io_ctl_init(&io_ctl, inode, fs_info->tree_root);
>> + io_ctl.check_crcs = 0;
>> + io_ctl_prepare_pages(&io_ctl, inode, 1);
>> +
>> + version = io_ctl_get_u32(&io_ctl);
>> + if (version != DROPTREE_VERSION) {
>> + printk(KERN_ERR "btrfs: snapshot deletion state has been saved "
>> + "with a different version, ignored\n");
>> + ret = -EINVAL;
>> + goto out;
>> + }
>> + /* FIXME generation is currently not needed */
>> + generation = io_ctl_get_u64(&io_ctl);
>> +
>> + while (1) {
>> + struct btrfs_key key;
>> + int ret;
>> + struct btrfs_root *del_root;
>> + struct droptree_root *dr;
>> + int level;
>> + int max_level;
>> + struct droptree_node *root_dn;
>> +
>> + key.objectid = io_ctl_get_u64(&io_ctl);
>> + if (key.objectid == 0)
>> + break;
>> +
>> + key.type = BTRFS_ROOT_ITEM_KEY;
>> + key.offset = io_ctl_get_u64(&io_ctl);
>> + max_level = level = io_ctl_get_u8(&io_ctl);
>> +
>> + BUG_ON(level< 0 || level>= BTRFS_MAX_LEVEL); /* incons. fs */
>> + del_root = btrfs_read_fs_root_no_radix(fs_info->tree_root,
>> + &key);
>> + if (IS_ERR(del_root)) {
>> + ret = PTR_ERR(del_root);
>> + BUG(); /* inconsistent fs */
>> + }
>> +
>> + root_dn = droptree_alloc_node(NULL);
>> + /*
>> + * FIXME in this phase is should still be possible to undo
>> + * everything and return a failure. Same goes for the allocation
>> + * failures below
>> + */
>> + BUG_ON(!root_dn); /* can't back out */
>> + dr = droptree_add_droproot(droplist, root_dn, del_root);
>> + BUG_ON(!dr); /* can't back out */
>> +
>> + stack[level] = root_dn;
>> +
>> + while (1) {
>> + u64 start;
>> + u64 len;
>> + u64 nritems;
>> + u32 *map;
>> + int n;
>> + int i;
>> + int parent_slot;
>> + struct droptree_node *dn;
>> +
>> + parent_slot = io_ctl_get_u16(&io_ctl);
>> + if (parent_slot == DROPTREE_STATE_GO_UP) {
>> + ++level;
>> + BUG_ON(level> max_level); /* incons. fs */
>> + continue;
>> + }
>> + if (parent_slot == DROPTREE_STATE_GO_DOWN) {
>> + --level;
>> + BUG_ON(level< 0); /* incons. fs */
>> + continue;
>> + }
>> + if (parent_slot == DROPTREE_STATE_END)
>> + break;
>> + start = io_ctl_get_u64(&io_ctl);
>> + if (start == 0)
>> + break;
>> +
>> + len = io_ctl_get_u64(&io_ctl);
>> + nritems = io_ctl_get_u16(&io_ctl);
>> + n = DT_BITS_TO_U32(nritems);
>> + BUG_ON(n> 999999); /* incons. fs */
>> + BUG_ON(n == 0); /* incons. fs */
>> +
>> + map = kmalloc(n * sizeof(u32), GFP_NOFS);
>> + BUG_ON(!map); /* can't back out */
>> +
>> + for (i = 0; i< n; ++i)
>> + map[i] = io_ctl_get_u32(&io_ctl);
>> +
>> + if (level == max_level) {
>> + /* only for root node */
>> + dn = stack[level];
>> + } else {
>> + dn = droptree_alloc_node(dr);
>> + BUG_ON(!dn); /* can't back out */
>> + dn->parent = stack[level + 1];
>> + dn->parent_slot = parent_slot;
>> + list_add_tail(&dn->next,
>> + &stack[level+1]->children);
>> + stack[level] = dn;
>> + }
>> + dn->level = level;
>> + dn->start = start;
>> + dn->len = len;
>> + dn->map = map;
>> + dn->nritems = nritems;
>> + dn->generation = 0;
>> + }
>> + ret = droptree_reada_root(top_rc, dr);
>> + BUG_ON(ret); /* can't back out */
>> + }
>> +out:
>> + io_ctl_drop_pages(&io_ctl);
>> + io_ctl_free(&io_ctl);
>> + kfree(stack);
>> +
>> + return ret;
>> +}
>> +
>> +/*
>> + * called from transaction.c with a list of roots to delete
>> + */
>> +void droptree_drop_list(struct btrfs_fs_info *fs_info, struct list_head *list)
>> +{
>> + struct btrfs_root *root = fs_info->tree_root;
>> + struct inode *inode = NULL;
>> + struct btrfs_path *path = NULL;
>> + int ret;
>> + struct btrfs_trans_handle *trans;
>> + u64 alloc_hint = 0;
>> + u64 prealloc;
>> + loff_t oldsize;
>> + long max_nodes;
>> + int i;
>> + struct list_head droplist;
>> + struct droptree_root *dr;
>> + struct droptree_root *dtmp;
>> + int running_roots = 0;
>> + struct reada_control *top_rc = NULL;
>> +
>> + if (btrfs_fs_closing(fs_info))
>> + return;
>> +
>> + inode = droptree_get_inode(fs_info);
>
>> + if (IS_ERR(inode))
>
> if (IS_ERR_OR_NULL(inode))
got it, thanks for catching it.
-Arne
>
> Thanks,
> Tsutomu
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html