summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent_map.c3
-rw-r--r--fs/btrfs/extent_map.h1
-rw-r--r--fs/btrfs/tree-log.c21
3 files changed, 20 insertions, 5 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c
index 8d1364d385d6..b8cbc8d5c7f7 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 8e6294b51357..679225555f7b 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 038a5229404a..ed1f7ce7219a 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;
}