diff options
-rw-r--r-- | fs/btrfs/extent_map.c | 3 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 1 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 21 |
3 files changed, 20 insertions, 5 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 8d1364d..b8cbc8d 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -407,7 +407,8 @@ int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); rb_erase(&em->rb_node, &tree->map); - list_del_init(&em->list); + if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) + list_del_init(&em->list); em->in_tree = 0; return ret; } diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index 8e6294b..6792255 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h @@ -13,6 +13,7 @@ #define EXTENT_FLAG_COMPRESSED 1 #define EXTENT_FLAG_VACANCY 2 /* no file extent item found */ #define EXTENT_FLAG_PREALLOC 3 /* pre-allocated extent */ +#define EXTENT_FLAG_LOGGING 4 /* Logging this extent */ struct extent_map { struct rb_node rb_node; diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 038a522..ed1f7ce 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2945,6 +2945,9 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, list_del_init(&em->list); if (em->generation <= test_gen) continue; + /* Need a ref to keep it from getting evicted from cache */ + atomic_inc(&em->refs); + set_bit(EXTENT_FLAG_LOGGING, &em->flags); list_add_tail(&em->list, &extents); } @@ -2954,13 +2957,18 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, em = list_entry(extents.next, struct extent_map, list); list_del_init(&em->list); + clear_bit(EXTENT_FLAG_LOGGING, &em->flags); /* * If we had an error we just need to delete everybody from our * private list. */ - if (ret) + if (ret) { + free_extent_map(em); continue; + } + + write_unlock(&tree->lock); /* * If the previous EM and the last extent we left off on aren't @@ -2971,21 +2979,26 @@ static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, ret = copy_items(trans, inode, dst_path, args.src, args.start_slot, args.nr, LOG_INODE_ALL); - if (ret) + if (ret) { + free_extent_map(em); + write_lock(&tree->lock); continue; + } btrfs_release_path(path); args.nr = 0; } ret = log_one_extent(trans, inode, root, em, path, dst_path, &args); + free_extent_map(em); + write_lock(&tree->lock); } + WARN_ON(!list_empty(&extents)); + write_unlock(&tree->lock); if (!ret && args.nr) ret = copy_items(trans, inode, dst_path, args.src, args.start_slot, args.nr, LOG_INODE_ALL); btrfs_release_path(path); - WARN_ON(!list_empty(&extents)); - write_unlock(&tree->lock); return ret; } |