Btrfs: Keep extent mappings in ram until pending ordered extents are done
It was possible for stale mappings from disk to be used instead of the
new pending ordered extent. This adds a flag to the extent map struct
to keep it pinned until the pending ordered extent is actually on disk.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 8803abc..08dbe73 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -144,6 +144,7 @@
em->len = ins.offset;
em->block_start = ins.objectid;
em->bdev = root->fs_info->fs_devices->latest_bdev;
+ set_bit(EXTENT_FLAG_PINNED, &em->flags);
while(1) {
spin_lock(&em_tree->lock);
ret = add_extent_mapping(em_tree, em);
@@ -483,6 +484,8 @@
struct btrfs_trans_handle *trans;
struct btrfs_ordered_extent *ordered_extent;
struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+ struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
+ struct extent_map *em;
u64 alloc_hint = 0;
struct list_head list;
struct btrfs_key ins;
@@ -524,6 +527,17 @@
ordered_extent->len,
ordered_extent->len, 0);
BUG_ON(ret);
+
+
+ spin_lock(&em_tree->lock);
+ em = lookup_extent_mapping(em_tree, ordered_extent->file_offset,
+ ordered_extent->len);
+ if (em) {
+ clear_bit(EXTENT_FLAG_PINNED, &em->flags);
+ free_extent_map(em);
+ }
+ spin_unlock(&em_tree->lock);
+
btrfs_drop_extent_cache(inode, ordered_extent->file_offset,
ordered_extent->file_offset +
ordered_extent->len - 1);
@@ -538,6 +552,7 @@
btrfs_ordered_update_i_size(inode, ordered_extent);
btrfs_remove_ordered_extent(inode, ordered_extent);
+
/* once for us */
btrfs_put_ordered_extent(ordered_extent);
/* once for the tree */