linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Liu Bo <bo.li.liu@oracle.com>
To: Itaru Kitayama <kitayama@cl.bb4u.ne.jp>
Cc: linux-btrfs@vger.kernel.org
Subject: Re: [PATCH 1/2 v4] Btrfs: snapshot-aware defrag
Date: Wed, 31 Oct 2012 20:55:28 +0800	[thread overview]
Message-ID: <50911FC0.4080104@oracle.com> (raw)
In-Reply-To: <CANW9uyu0NyFj57AVp2X-Hc=AjXdwyP=wieOcteEbj2_Mx_F95w@mail.gmail.com>

On 10/31/2012 08:13 PM, Itaru Kitayama wrote:
> Hi LiuBo:
> 
> I am seeing another warning with your patch applied btrfs-next.
> 

Hi Itaru,

Thanks for testing, you seems to be using an old version, since in the new version
record_extent_backrefs() does not own a WARN_ON().

Could you please test it again with the new patches applied?

thanks,
liubo


> [ 5224.531560] ------------[ cut here ]------------
> [ 5224.531565] WARNING: at fs/btrfs/inode.c:2054
> record_extent_backrefs+0x87/0xe0()
> [ 5224.531567] Hardware name: Bochs
> [ 5224.531568] Modules linked in: microcode ppdev psmouse nfsd nfs_acl
> auth_rpcgss serio_raw nfs fscache lockd binfmt_misc sunrpc cirrus
> parport_pc ttm drm_kms_helper drm sysimgblt i2c_piix4 sysfillrect
> syscopyarea i2c_core lp parport floppy
> [ 5224.531591] Pid: 2485, comm: btrfs-endio-wri Tainted: G        W
> 3.7.0-rc1-v11+ #53
> [ 5224.531592] Call Trace:
> [ 5224.531598]  [<ffffffff81061c63>] warn_slowpath_common+0x93/0xc0
> [ 5224.531600]  [<ffffffff81061caa>] warn_slowpath_null+0x1a/0x20
> [ 5224.531603]  [<ffffffff81322287>] record_extent_backrefs+0x87/0xe0
> [ 5224.531606]  [<ffffffff8132d10b>] btrfs_finish_ordered_io+0x8bb/0xa80
> [ 5224.531611]  [<ffffffff810ce300>] ? trace_hardirqs_off_caller+0xb0/0x140
> [ 5224.531614]  [<ffffffff8132d2e5>] finish_ordered_fn+0x15/0x20
> [ 5224.531617]  [<ffffffff8134beb7>] worker_loop+0x157/0x580
> [ 5224.531620]  [<ffffffff8134bd60>] ? btrfs_queue_worker+0x2f0/0x2f0
> [ 5224.531624]  [<ffffffff81090aa8>] kthread+0xe8/0xf0
> [ 5224.531627]  [<ffffffff810ce3c2>] ? get_lock_stats+0x22/0x70
> [ 5224.531630]  [<ffffffff810909c0>] ? kthread_create_on_node+0x160/0x160
> [ 5224.531634]  [<ffffffff817c1c6c>] ret_from_fork+0x7c/0xb0
> [ 5224.531636]  [<ffffffff810909c0>] ? kthread_create_on_node+0x160/0x160
> [ 5224.531638] ---[ end trace 0256d2b5a195208c ]---
> 
> I've compared some of the old extents logical addresses with the corresponding
> object ids and offsets from the extent tree; some are just 8k off from
> the found extents
> and some keys are totally off.
> 
> Itaru
> 
> On Sat, Oct 27, 2012 at 7:28 PM, Liu Bo <bo.li.liu@oracle.com> wrote:
>> This comes from one of btrfs's project ideas,
>> As we defragment files, we break any sharing from other snapshots.
>> The balancing code will preserve the sharing, and defrag needs to grow this
>> as well.
>>
>> Now we're able to fill the blank with this patch, in which we make full use of
>> backref walking stuff.
>>
>> Here is the basic idea,
>> o  set the writeback ranges started by defragment with flag EXTENT_DEFRAG
>> o  at endio, after we finish updating fs tree, we use backref walking to find
>>    all parents of the ranges and re-link them with the new COWed file layout by
>>    adding corresponding backrefs.
>>
>> Originally patch by Li Zefan <lizf@cn.fujitsu.com>
>> Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
>> ---
>> v3->v4:
>>       - fix duplicated refs bugs detected by mounting with autodefrag, thanks
>>         for the bug report from Mitch and Chris.
>>
>>  fs/btrfs/inode.c |  609 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 files changed, 609 insertions(+), 0 deletions(-)
>>
>> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
>> index 85a1e50..35e6993 100644
>> --- a/fs/btrfs/inode.c
>> +++ b/fs/btrfs/inode.c
>> @@ -54,6 +54,7 @@
>>  #include "locking.h"
>>  #include "free-space-cache.h"
>>  #include "inode-map.h"
>> +#include "backref.h"
>>
>>  struct btrfs_iget_args {
>>         u64 ino;
>> @@ -1839,6 +1840,600 @@ out:
>>         return ret;
>>  }
>>
>> +/* snapshot-aware defrag */
>> +struct sa_defrag_extent_backref {
>> +       struct rb_node node;
>> +       struct old_sa_defrag_extent *old;
>> +       u64 root_id;
>> +       u64 inum;
>> +       u64 file_pos;
>> +       u64 extent_offset;
>> +       u64 num_bytes;
>> +       u64 generation;
>> +};
>> +
>> +struct old_sa_defrag_extent {
>> +       struct list_head list;
>> +       struct new_sa_defrag_extent *new;
>> +
>> +       u64 extent_offset;
>> +       u64 bytenr;
>> +       u64 offset;
>> +       u64 len;
>> +       int count;
>> +};
>> +
>> +struct new_sa_defrag_extent {
>> +       struct rb_root root;
>> +       struct list_head head;
>> +       struct btrfs_path *path;
>> +       struct inode *inode;
>> +       u64 file_pos;
>> +       u64 len;
>> +       u64 bytenr;
>> +       u64 disk_len;
>> +       u8 compress_type;
>> +};
>> +
>> +static int backref_comp(struct sa_defrag_extent_backref *b1,
>> +                       struct sa_defrag_extent_backref *b2)
>> +{
>> +       if (b1->root_id < b2->root_id)
>> +               return -1;
>> +       else if (b1->root_id > b2->root_id)
>> +               return 1;
>> +
>> +       if (b1->inum < b2->inum)
>> +               return -1;
>> +       else if (b1->inum > b2->inum)
>> +               return 1;
>> +
>> +       if (b1->file_pos < b2->file_pos)
>> +               return -1;
>> +       else if (b1->file_pos > b2->file_pos)
>> +               return 1;
>> +
>> +       return 0;
>> +}
>> +
>> +static void backref_insert(struct rb_root *root,
>> +                          struct sa_defrag_extent_backref *backref)
>> +{
>> +       struct rb_node **p = &root->rb_node;
>> +       struct rb_node *parent = NULL;
>> +       struct sa_defrag_extent_backref *entry;
>> +       int ret;
>> +
>> +       while (*p) {
>> +               parent = *p;
>> +               entry = rb_entry(parent, struct sa_defrag_extent_backref, node);
>> +
>> +               ret = backref_comp(backref, entry);
>> +               if (ret < 0)
>> +                       p = &(*p)->rb_left;
>> +               else
>> +                       /*
>> +                        * Since space can be shared, so there can be
>> +                        * some backrefs(extent tree to fs/file tree)
>> +                        * whoes fs/file extents map to the same address.
>> +                        * If so, we just put it after what we've found.
>> +                        */
>> +                       p = &(*p)->rb_right;
>> +       }
>> +
>> +       rb_link_node(&backref->node, parent, p);
>> +       rb_insert_color(&backref->node, root);
>> +}
>> +
>> +/*
>> + * Note the backref might has changed, and in this case we just return 0.
>> + */
>> +static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
>> +                                      void *ctx)
>> +{
>> +       struct btrfs_file_extent_item *extent;
>> +       struct btrfs_fs_info *fs_info;
>> +       struct old_sa_defrag_extent *old = ctx;
>> +       struct new_sa_defrag_extent *new = old->new;
>> +       struct btrfs_path *path = new->path;
>> +       struct btrfs_key key;
>> +       struct btrfs_root *root;
>> +       struct sa_defrag_extent_backref *backref;
>> +       struct extent_buffer *leaf;
>> +       struct inode *inode = new->inode;
>> +       int slot;
>> +       int ret;
>> +       u64 extent_offset;
>> +       u64 num_bytes;
>> +
>> +       if (BTRFS_I(inode)->root->root_key.objectid == root_id &&
>> +           inum == btrfs_ino(inode))
>> +               return 0;
>> +
>> +       key.objectid = root_id;
>> +       key.type = BTRFS_ROOT_ITEM_KEY;
>> +       key.offset = (u64)-1;
>> +
>> +       fs_info = BTRFS_I(inode)->root->fs_info;
>> +       root = btrfs_read_fs_root_no_name(fs_info, &key);
>> +       if (IS_ERR(root)) {
>> +               if (PTR_ERR(root) == -ENOENT)
>> +                       return 0;
>> +               WARN_ON(1);
>> +               pr_debug("inum=%llu, offset=%llu, root_id=%llu\n",
>> +                        inum, offset, root_id);
>> +               return PTR_ERR(root);
>> +       }
>> +
>> +       key.objectid = inum;
>> +       key.type = BTRFS_EXTENT_DATA_KEY;
>> +       if (offset > (u64)-1 << 32)
>> +               key.offset = 0;
>> +       else
>> +               key.offset = offset;
>> +
>> +       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
>> +       if (ret < 0) {
>> +               WARN_ON(1);
>> +               return ret;
>> +       }
>> +
>> +       while (1) {
>> +               cond_resched();
>> +
>> +               leaf = path->nodes[0];
>> +               slot = path->slots[0];
>> +
>> +               if (slot >= btrfs_header_nritems(leaf)) {
>> +                       ret = btrfs_next_leaf(root, path);
>> +                       if (ret < 0) {
>> +                               goto out;
>> +                       } else if (ret > 0) {
>> +                               ret = 0;
>> +                               goto out;
>> +                       }
>> +                       continue;
>> +               }
>> +
>> +               path->slots[0]++;
>> +
>> +               btrfs_item_key_to_cpu(leaf, &key, slot);
>> +
>> +               if (key.objectid > inum)
>> +                       goto out;
>> +
>> +               if (key.objectid < inum || key.type != BTRFS_EXTENT_DATA_KEY)
>> +                       continue;
>> +
>> +               extent = btrfs_item_ptr(leaf, slot,
>> +                                       struct btrfs_file_extent_item);
>> +
>> +               if (btrfs_file_extent_disk_bytenr(leaf, extent) != old->bytenr)
>> +                       continue;
>> +
>> +               extent_offset = btrfs_file_extent_offset(leaf, extent);
>> +               if (key.offset - extent_offset != offset)
>> +                       continue;
>> +
>> +               num_bytes = btrfs_file_extent_num_bytes(leaf, extent);
>> +               if (extent_offset >= old->extent_offset + old->offset +
>> +                   old->len || extent_offset + num_bytes <=
>> +                   old->extent_offset + old->offset)
>> +                       continue;
>> +
>> +               break;
>> +       }
>> +
>> +       backref = kmalloc(sizeof(*backref), GFP_NOFS);
>> +       if (!backref) {
>> +               ret = -ENOENT;
>> +               goto out;
>> +       }
>> +
>> +       backref->root_id = root_id;
>> +       backref->inum = inum;
>> +       backref->file_pos = offset + extent_offset;
>> +       backref->num_bytes = num_bytes;
>> +       backref->extent_offset = extent_offset;
>> +       backref->generation = btrfs_file_extent_generation(leaf, extent);
>> +       backref->old = old;
>> +       backref_insert(&new->root, backref);
>> +       old->count++;
>> +out:
>> +       btrfs_release_path(path);
>> +       WARN_ON(ret);
>> +       return ret;
>> +}
>> +
>> +static noinline bool record_extent_backrefs(struct btrfs_path *path,
>> +                                  struct new_sa_defrag_extent *new)
>> +{
>> +       struct btrfs_fs_info *fs_info = BTRFS_I(new->inode)->root->fs_info;
>> +       struct old_sa_defrag_extent *old, *tmp;
>> +       int ret;
>> +
>> +       new->path = path;
>> +
>> +       list_for_each_entry_safe(old, tmp, &new->head, list) {
>> +               ret = iterate_inodes_from_logical(old->bytenr, fs_info,
>> +                                                 path, record_one_backref,
>> +                                                 old);
>> +               BUG_ON(ret < 0 && ret != -ENOENT);
>> +
>> +               /* no backref to be processed for this extent */
>> +               if (!old->count) {
>> +                       list_del(&old->list);
>> +                       kfree(old);
>> +               }
>> +       }
>> +
>> +       if (list_empty(&new->head))
>> +               return false;
>> +
>> +       return true;
>> +}
>> +
>> +/*
>> + * Note the backref might has changed, and in this case we just return 0.
>> + */
>> +static noinline int relink_extent_backref(struct btrfs_path *path,
>> +                                struct sa_defrag_extent_backref *prev,
>> +                                struct sa_defrag_extent_backref *backref)
>> +{
>> +       struct btrfs_file_extent_item *extent;
>> +       struct btrfs_file_extent_item *item;
>> +       struct btrfs_ordered_extent *ordered;
>> +       struct btrfs_trans_handle *trans;
>> +       struct btrfs_fs_info *fs_info;
>> +       struct btrfs_root *root;
>> +       struct btrfs_key key;
>> +       struct extent_buffer *leaf;
>> +       struct old_sa_defrag_extent *old = backref->old;
>> +       struct new_sa_defrag_extent *new = old->new;
>> +       struct inode *src_inode = new->inode;
>> +       struct inode *inode;
>> +       struct extent_state *cached = NULL;
>> +       int ret = 0;
>> +       u64 start;
>> +       u64 len;
>> +       u64 lock_start;
>> +       u64 lock_end;
>> +       bool merge = false;
>> +
>> +       if (prev && prev->root_id == backref->root_id &&
>> +           prev->inum == backref->inum &&
>> +           prev->file_pos + prev->num_bytes == backref->file_pos)
>> +               merge = true;
>> +
>> +       key.objectid = backref->root_id;
>> +       key.type = BTRFS_ROOT_ITEM_KEY;
>> +       key.offset = (u64)-1;
>> +
>> +       fs_info = BTRFS_I(src_inode)->root->fs_info;
>> +       root = btrfs_read_fs_root_no_name(fs_info, &key);
>> +       if (IS_ERR(root)) {
>> +               if (PTR_ERR(root) == -ENOENT)
>> +                       return 0;
>> +               return PTR_ERR(root);
>> +       }
>> +
>> +       key.objectid = backref->inum;
>> +       key.type = BTRFS_INODE_ITEM_KEY;
>> +       key.offset = 0;
>> +
>> +       inode = btrfs_iget(fs_info->sb, &key, root, NULL);
>> +       if (IS_ERR_OR_NULL(inode) || is_bad_inode(inode)) {
>> +               if (inode && !IS_ERR(inode))
>> +                       iput(inode);
>> +               return 0;
>> +       }
>> +
>> +       lock_start = backref->file_pos;
>> +       lock_end = backref->file_pos + backref->num_bytes - 1;
>> +       lock_extent_bits(&BTRFS_I(inode)->io_tree, lock_start, lock_end,
>> +                        0, &cached);
>> +
>> +       ordered = btrfs_lookup_first_ordered_extent(inode, lock_end);
>> +       if (ordered) {
>> +               btrfs_put_ordered_extent(ordered);
>> +               goto out_unlock;
>> +       }
>> +
>> +       trans = btrfs_join_transaction(root);
>> +       if (IS_ERR(trans)) {
>> +               ret = PTR_ERR(trans);
>> +               goto out_unlock;
>> +       }
>> +
>> +       key.objectid = backref->inum;
>> +       key.type = BTRFS_EXTENT_DATA_KEY;
>> +       key.offset = backref->file_pos;
>> +
>> +       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
>> +       if (ret < 0) {
>> +               goto out_free_path;
>> +       } else if (ret > 0) {
>> +               ret = 0;
>> +               goto out_free_path;
>> +       }
>> +
>> +       extent = btrfs_item_ptr(path->nodes[0], path->slots[0],
>> +                               struct btrfs_file_extent_item);
>> +
>> +       if (btrfs_file_extent_generation(path->nodes[0], extent) !=
>> +           backref->generation)
>> +               goto out_free_path;
>> +
>> +       btrfs_release_path(path);
>> +
>> +       start = backref->file_pos;
>> +       if (backref->extent_offset < old->extent_offset + old->offset)
>> +               start += old->extent_offset + old->offset -
>> +                        backref->extent_offset;
>> +
>> +       len = min(backref->extent_offset + backref->num_bytes,
>> +                 old->extent_offset + old->offset + old->len);
>> +       len -= max(backref->extent_offset, old->extent_offset + old->offset);
>> +
>> +       ret = btrfs_drop_extents(trans, root, inode, start,
>> +                                start + len, 1);
>> +       if (ret)
>> +               goto out_free_path;
>> +again:
>> +       key.objectid = btrfs_ino(inode);
>> +       key.type = BTRFS_EXTENT_DATA_KEY;
>> +       key.offset = start;
>> +
>> +       if (merge) {
>> +               struct btrfs_file_extent_item *fi;
>> +               u64 extent_len;
>> +               struct btrfs_key found_key;
>> +
>> +               ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
>> +               if (ret < 0)
>> +                       goto out_free_path;
>> +
>> +               path->slots[0]--;
>> +               leaf = path->nodes[0];
>> +               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
>> +
>> +               fi = btrfs_item_ptr(leaf, path->slots[0],
>> +                                   struct btrfs_file_extent_item);
>> +               extent_len = btrfs_file_extent_num_bytes(leaf, fi);
>> +
>> +               if (btrfs_file_extent_disk_bytenr(leaf, fi) == new->bytenr &&
>> +                   btrfs_file_extent_type(leaf, fi) == BTRFS_FILE_EXTENT_REG &&
>> +                   !btrfs_file_extent_compression(leaf, fi) &&
>> +                   !btrfs_file_extent_encryption(leaf, fi) &&
>> +                   !btrfs_file_extent_other_encoding(leaf, fi) &&
>> +                   extent_len + found_key.offset == start) {
>> +                       btrfs_set_file_extent_num_bytes(leaf, fi,
>> +                                                       extent_len + len);
>> +                       btrfs_mark_buffer_dirty(leaf);
>> +                       inode_add_bytes(inode, len);
>> +
>> +                       ret = 1;
>> +                       goto out_free_path;
>> +               } else {
>> +                       merge = false;
>> +                       btrfs_release_path(path);
>> +                       goto again;
>> +               }
>> +       }
>> +
>> +       ret = btrfs_insert_empty_item(trans, root, path, &key,
>> +                                       sizeof(*extent));
>> +       if (ret) {
>> +               btrfs_abort_transaction(trans, root, ret);
>> +               goto out_free_path;
>> +       }
>> +
>> +       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, new->bytenr);
>> +       btrfs_set_file_extent_disk_num_bytes(leaf, item, new->disk_len);
>> +       btrfs_set_file_extent_offset(leaf, item, start - new->file_pos);
>> +       btrfs_set_file_extent_num_bytes(leaf, item, len);
>> +       btrfs_set_file_extent_ram_bytes(leaf, item, new->len);
>> +       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, new->compress_type);
>> +       btrfs_set_file_extent_encryption(leaf, item, 0);
>> +       btrfs_set_file_extent_other_encoding(leaf, item, 0);
>> +
>> +       btrfs_mark_buffer_dirty(leaf);
>> +       inode_add_bytes(inode, len);
>> +
>> +       ret = btrfs_inc_extent_ref(trans, root, new->bytenr,
>> +                       new->disk_len, 0,
>> +                       backref->root_id, backref->inum,
>> +                       new->file_pos, 0);      /* start - extent_offset */
>> +       if (ret) {
>> +               btrfs_abort_transaction(trans, root, ret);
>> +               goto out_free_path;
>> +       }
>> +
>> +       ret = 1;
>> +out_free_path:
>> +       btrfs_release_path(path);
>> +       btrfs_end_transaction(trans, root);
>> +out_unlock:
>> +       unlock_extent_cached(&BTRFS_I(inode)->io_tree, lock_start, lock_end,
>> +                            &cached, GFP_NOFS);
>> +       iput(inode);
>> +       return ret;
>> +}
>> +
>> +static void relink_file_extents(struct new_sa_defrag_extent *new)
>> +{
>> +       struct btrfs_path *path;
>> +       struct old_sa_defrag_extent *old, *tmp;
>> +       struct sa_defrag_extent_backref *backref;
>> +       struct sa_defrag_extent_backref *prev = NULL;
>> +       struct inode *inode;
>> +       struct btrfs_root *root;
>> +       struct rb_node *node;
>> +       int ret;
>> +
>> +       inode = new->inode;
>> +       root = BTRFS_I(inode)->root;
>> +
>> +       path = btrfs_alloc_path();
>> +       if (!path)
>> +               return;
>> +
>> +       if (!record_extent_backrefs(path, new)) {
>> +               btrfs_free_path(path);
>> +               goto out;
>> +       }
>> +       btrfs_release_path(path);
>> +
>> +       while (1) {
>> +               node = rb_first(&new->root);
>> +               if (!node)
>> +                       break;
>> +               rb_erase(node, &new->root);
>> +
>> +               backref = rb_entry(node, struct sa_defrag_extent_backref, node);
>> +
>> +               ret = relink_extent_backref(path, prev, backref);
>> +               WARN_ON(ret < 0);
>> +
>> +               kfree(prev);
>> +
>> +               if (ret == 1)
>> +                       prev = backref;
>> +               else
>> +                       prev = NULL;
>> +               cond_resched();
>> +       }
>> +       kfree(prev);
>> +
>> +       btrfs_free_path(path);
>> +
>> +       list_for_each_entry_safe(old, tmp, &new->head, list) {
>> +               list_del(&old->list);
>> +               kfree(old);
>> +       }
>> +out:
>> +       atomic_dec(&root->fs_info->defrag_running);
>> +       wake_up(&root->fs_info->transaction_wait);
>> +
>> +       kfree(new);
>> +}
>> +
>> +static struct new_sa_defrag_extent *
>> +record_old_file_extents(struct inode *inode,
>> +                       struct btrfs_ordered_extent *ordered)
>> +{
>> +       struct btrfs_root *root = BTRFS_I(inode)->root;
>> +       struct btrfs_path *path;
>> +       struct btrfs_key key;
>> +       struct old_sa_defrag_extent *old, *tmp;
>> +       struct new_sa_defrag_extent *new;
>> +       int ret;
>> +
>> +       new = kmalloc(sizeof(*new), GFP_NOFS);
>> +       if (!new)
>> +               return NULL;
>> +
>> +       new->inode = inode;
>> +       new->file_pos = ordered->file_offset;
>> +       new->len = ordered->len;
>> +       new->bytenr = ordered->start;
>> +       new->disk_len = ordered->disk_len;
>> +       new->compress_type = ordered->compress_type;
>> +       new->root = RB_ROOT;
>> +       INIT_LIST_HEAD(&new->head);
>> +
>> +       path = btrfs_alloc_path();
>> +       if (!path)
>> +               goto out_kfree;
>> +
>> +       key.objectid = btrfs_ino(inode);
>> +       key.type = BTRFS_EXTENT_DATA_KEY;
>> +       key.offset = new->file_pos;
>> +
>> +       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
>> +       if (ret < 0)
>> +               goto out_free_path;
>> +       if (ret > 0 && path->slots[0] > 0)
>> +               path->slots[0]--;
>> +
>> +       /* find out all the old extents for the file range */
>> +       while (1) {
>> +               struct btrfs_file_extent_item *extent;
>> +               struct extent_buffer *l;
>> +               int slot;
>> +               u64 num_bytes;
>> +               u64 offset;
>> +               u64 end;
>> +
>> +               l = path->nodes[0];
>> +               slot = path->slots[0];
>> +
>> +               if (slot >= btrfs_header_nritems(l)) {
>> +                       ret = btrfs_next_leaf(root, path);
>> +                       if (ret < 0)
>> +                               goto out_free_list;
>> +                       else if (ret > 0)
>> +                               break;
>> +                       continue;
>> +               }
>> +
>> +               btrfs_item_key_to_cpu(l, &key, slot);
>> +
>> +               if (key.objectid != btrfs_ino(inode))
>> +                       break;
>> +               if (key.type != BTRFS_EXTENT_DATA_KEY)
>> +                       break;
>> +               if (key.offset >= new->file_pos + new->len)
>> +                       break;
>> +
>> +               extent = btrfs_item_ptr(l, slot, struct btrfs_file_extent_item);
>> +
>> +               num_bytes = btrfs_file_extent_num_bytes(l, extent);
>> +               if (key.offset + num_bytes < new->file_pos)
>> +                       goto next;
>> +
>> +               old = kmalloc(sizeof(*old), GFP_NOFS);
>> +               if (!old)
>> +                       goto out_free_list;
>> +
>> +               offset = max(new->file_pos, key.offset);
>> +               end = min(new->file_pos + new->len, key.offset + num_bytes);
>> +
>> +               old->bytenr = btrfs_file_extent_disk_bytenr(l, extent);
>> +               BUG_ON(!old->bytenr);
>> +               old->extent_offset = btrfs_file_extent_offset(l, extent);
>> +               old->offset = offset - key.offset;
>> +               old->len = end - offset;
>> +               old->new = new;
>> +               old->count = 0;
>> +               list_add_tail(&old->list, &new->head);
>> +next:
>> +               path->slots[0]++;
>> +               cond_resched();
>> +       }
>> +
>> +       btrfs_free_path(path);
>> +       atomic_inc(&root->fs_info->defrag_running);
>> +
>> +       return new;
>> +
>> +out_free_list:
>> +       list_for_each_entry_safe(old, tmp, &new->head, list) {
>> +               list_del(&old->list);
>> +               kfree(old);
>> +       }
>> +out_free_path:
>> +       btrfs_free_path(path);
>> +out_kfree:
>> +       kfree(new);
>> +       return NULL;
>> +}
>> +
>>  /*
>>   * helper function for btrfs_finish_ordered_io, this
>>   * just reads in some of the csum leaves to prime them into ram
>> @@ -1856,6 +2451,7 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
>>         struct btrfs_trans_handle *trans = NULL;
>>         struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
>>         struct extent_state *cached_state = NULL;
>> +       struct new_sa_defrag_extent *new = NULL;
>>         int compress_type = 0;
>>         int ret;
>>         bool nolock;
>> @@ -1892,6 +2488,15 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
>>                          ordered_extent->file_offset + ordered_extent->len - 1,
>>                          0, &cached_state);
>>
>> +       ret = test_range_bit(io_tree, ordered_extent->file_offset,
>> +                       ordered_extent->file_offset + ordered_extent->len - 1,
>> +                       EXTENT_DEFRAG, 1, cached_state);
>> +       if (ret && btrfs_root_last_snapshot(&root->root_item) >=
>> +                                               BTRFS_I(inode)->generation) {
>> +               /* the inode is shared */
>> +               new = record_old_file_extents(inode, ordered_extent);
>> +       }
>> +
>>         if (nolock)
>>                 trans = btrfs_join_transaction_nolock(root);
>>         else
>> @@ -1965,6 +2570,10 @@ out:
>>          */
>>         btrfs_remove_ordered_extent(inode, ordered_extent);
>>
>> +       /* for snapshot-aware defrag */
>> +       if (new)
>> +               relink_file_extents(new);
>> +
>>         /* once for us */
>>         btrfs_put_ordered_extent(ordered_extent);
>>         /* once for the tree */
>> --
>> 1.7.7.6
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html


  reply	other threads:[~2012-10-31 12:55 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-10-27 10:28 [PATCH 1/2 v4] Btrfs: snapshot-aware defrag Liu Bo
2012-10-27 10:28 ` [PATCH 2/2] Btrfs: make snapshot-aware defrag as a mount option Liu Bo
2012-10-30 23:31   ` David Sterba
2012-10-31  0:34     ` Liu Bo
2012-10-31  0:44       ` David Sterba
2012-10-31 13:31         ` Liu Bo
2012-11-01 14:43   ` Chris Mason
2012-11-01 15:49     ` Liu Bo
2012-10-29 20:06 ` [PATCH 1/2 v4] Btrfs: snapshot-aware defrag Mitch Harder
2012-10-30  1:20   ` Liu Bo
2012-10-30 20:59     ` Mitch Harder
2012-10-31 12:13 ` Itaru Kitayama
2012-10-31 12:55   ` Liu Bo [this message]
2012-11-01 11:08     ` Itaru Kitayama
2012-11-01 11:21       ` Liu Bo
2012-11-01 14:05         ` Itaru Kitayama
2012-11-01 16:01           ` Liu Bo
     [not found]             ` <CANW9uyt9qE9384WnQq5ggZ2hb-DbahZe8KY5-WXRFSKTiedekg@mail.gmail.com>
2012-11-26 10:30               ` Liu Bo
2012-12-12 19:37         ` Mitch Harder
2012-12-13  1:28           ` Liu Bo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=50911FC0.4080104@oracle.com \
    --to=bo.li.liu@oracle.com \
    --cc=kitayama@cl.bb4u.ne.jp \
    --cc=linux-btrfs@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).