Btrfs: Fix add_extent_mapping to check for duplicates across the whole range
add_extent_mapping was allowing the insertion of overlapping extents. This never used to happen because it only inserted the extents from disk and those were never overlapping. But, with the data=ordered code, the disk and memory representations of the file are not the same. add_extent_mapping needs to ensure a new extent does not overlap before it inserts. Signed-off-by: Chris Mason <chris.mason@oracle.com>
This commit is contained in:
Родитель
902b22f341
Коммит
7c2fe32a23
|
@ -207,7 +207,14 @@ int add_extent_mapping(struct extent_map_tree *tree,
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct extent_map *merge = NULL;
|
struct extent_map *merge = NULL;
|
||||||
struct rb_node *rb;
|
struct rb_node *rb;
|
||||||
|
struct extent_map *exist;
|
||||||
|
|
||||||
|
exist = lookup_extent_mapping(tree, em->start, em->len);
|
||||||
|
if (exist) {
|
||||||
|
free_extent_map(exist);
|
||||||
|
ret = -EEXIST;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
assert_spin_locked(&tree->lock);
|
assert_spin_locked(&tree->lock);
|
||||||
rb = tree_insert(&tree->map, em->start, &em->rb_node);
|
rb = tree_insert(&tree->map, em->start, &em->rb_node);
|
||||||
if (rb) {
|
if (rb) {
|
||||||
|
|
|
@ -641,8 +641,9 @@ int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
|
||||||
if (ret == -ENOENT || ret == -EFBIG)
|
if (ret == -ENOENT || ret == -EFBIG)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
csum = 0;
|
csum = 0;
|
||||||
printk("no csum found for inode %lu start %Lu\n", inode->i_ino,
|
if (printk_ratelimit())
|
||||||
start);
|
printk("no csum found for inode %lu start %Lu\n", inode->i_ino,
|
||||||
|
start);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
read_extent_buffer(path->nodes[0], &csum, (unsigned long)item,
|
read_extent_buffer(path->nodes[0], &csum, (unsigned long)item,
|
||||||
|
@ -1653,8 +1654,20 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
|
||||||
btrfs_truncate_page(inode->i_mapping, inode->i_size);
|
btrfs_truncate_page(inode->i_mapping, inode->i_size);
|
||||||
|
|
||||||
hole_size = block_end - hole_start;
|
hole_size = block_end - hole_start;
|
||||||
btrfs_wait_ordered_range(inode, hole_start, hole_size);
|
while(1) {
|
||||||
lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
|
struct btrfs_ordered_extent *ordered;
|
||||||
|
btrfs_wait_ordered_range(inode, hole_start, hole_size);
|
||||||
|
|
||||||
|
lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS);
|
||||||
|
ordered = btrfs_lookup_ordered_extent(inode, hole_start);
|
||||||
|
if (ordered) {
|
||||||
|
unlock_extent(io_tree, hole_start,
|
||||||
|
block_end - 1, GFP_NOFS);
|
||||||
|
btrfs_put_ordered_extent(ordered);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
trans = btrfs_start_transaction(root, 1);
|
trans = btrfs_start_transaction(root, 1);
|
||||||
btrfs_set_trans_block_group(trans, inode);
|
btrfs_set_trans_block_group(trans, inode);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче