Hi Liubo, I couldn't apply your V4 patch against the btrfs-next HEAD. Do you have a github branch which I can checkout?
Thanks, Itaru On Wed, Oct 31, 2012 at 9:55 PM, Liu Bo <bo.li....@oracle.com> wrote: > 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....@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 <l...@cn.fujitsu.com> >>> Signed-off-by: Liu Bo <bo.li....@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 majord...@vger.kernel.org >>> More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html