diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-08-20 08:51:50 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:06 -0400 |
commit | 7c2fe32a238eb12422beca5cbd5194a594baa559 (patch) | |
tree | a95bada9d991780e0611e94529e63c8178f4f3be | |
parent | 902b22f341efa00be802418a0a8c57bddcd269a6 (diff) | |
download | op-kernel-dev-7c2fe32a238eb12422beca5cbd5194a594baa559.zip op-kernel-dev-7c2fe32a238eb12422beca5cbd5194a594baa559.tar.gz |
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>
-rw-r--r-- | fs/btrfs/extent_map.c | 7 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 21 |
2 files changed, 24 insertions, 4 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 954b047..78ced11 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c @@ -207,7 +207,14 @@ int add_extent_mapping(struct extent_map_tree *tree, int ret = 0; struct extent_map *merge = NULL; 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); rb = tree_insert(&tree->map, em->start, &em->rb_node); if (rb) { diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6510789..6c77804 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -641,8 +641,9 @@ int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end) if (ret == -ENOENT || ret == -EFBIG) ret = 0; csum = 0; - printk("no csum found for inode %lu start %Lu\n", inode->i_ino, - start); + if (printk_ratelimit()) + printk("no csum found for inode %lu start %Lu\n", inode->i_ino, + start); goto out; } 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); hole_size = block_end - hole_start; - btrfs_wait_ordered_range(inode, hole_start, hole_size); - lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); + while(1) { + 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); btrfs_set_trans_block_group(trans, inode); |