On Thu, Nov 01, 2012 at 08:08:52PM +0900, Itaru Kitayama wrote: > Hi Liubo, > > I couldn't apply your V4 patch against the btrfs-next HEAD. Do you have > a github branch which I can checkout? >
The current btrfs-next HEAD actually have included this v4 patch, so just pull btrfs-next and give it a shot :) thanks, liubo > 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