Btrfs: allow splitting of hole em's when dropping extent cache
I noticed while running multi-threaded fsync tests that sometimes fsck would complain about an improper gap. This happens because we fail to add a hole extent to the file, which was happening when we'd split a hole EM because btrfs_drop_extent_cache was just discarding the whole em instead of splitting it. So this patch fixes this by allowing us to split a hole em properly, which means that added holes actually get logged properly and we no longer see this fsck error. Thankfully we're tolerant of these sort of problems so a user would not see any adverse effects of this bug, other than fsck complaining. Thanks, Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
parent
ed8c4913da
commit
ee20a98314
1 changed files with 41 additions and 23 deletions
|
@ -596,20 +596,29 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
|||
if (no_splits)
|
||||
goto next;
|
||||
|
||||
if (em->block_start < EXTENT_MAP_LAST_BYTE &&
|
||||
em->start < start) {
|
||||
if (em->start < start) {
|
||||
split->start = em->start;
|
||||
split->len = start - em->start;
|
||||
split->orig_start = em->orig_start;
|
||||
split->block_start = em->block_start;
|
||||
|
||||
if (compressed)
|
||||
split->block_len = em->block_len;
|
||||
else
|
||||
split->block_len = split->len;
|
||||
split->ram_bytes = em->ram_bytes;
|
||||
split->orig_block_len = max(split->block_len,
|
||||
em->orig_block_len);
|
||||
if (em->block_start < EXTENT_MAP_LAST_BYTE) {
|
||||
split->orig_start = em->orig_start;
|
||||
split->block_start = em->block_start;
|
||||
|
||||
if (compressed)
|
||||
split->block_len = em->block_len;
|
||||
else
|
||||
split->block_len = split->len;
|
||||
split->orig_block_len = max(split->block_len,
|
||||
em->orig_block_len);
|
||||
split->ram_bytes = em->ram_bytes;
|
||||
} else {
|
||||
split->orig_start = split->start;
|
||||
split->block_len = 0;
|
||||
split->block_start = em->block_start;
|
||||
split->orig_block_len = 0;
|
||||
split->ram_bytes = split->len;
|
||||
}
|
||||
|
||||
split->generation = gen;
|
||||
split->bdev = em->bdev;
|
||||
split->flags = flags;
|
||||
|
@ -620,8 +629,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
|||
split = split2;
|
||||
split2 = NULL;
|
||||
}
|
||||
if (em->block_start < EXTENT_MAP_LAST_BYTE &&
|
||||
testend && em->start + em->len > start + len) {
|
||||
if (testend && em->start + em->len > start + len) {
|
||||
u64 diff = start + len - em->start;
|
||||
|
||||
split->start = start + len;
|
||||
|
@ -630,18 +638,28 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end,
|
|||
split->flags = flags;
|
||||
split->compress_type = em->compress_type;
|
||||
split->generation = gen;
|
||||
split->orig_block_len = max(em->block_len,
|
||||
em->orig_block_len);
|
||||
split->ram_bytes = em->ram_bytes;
|
||||
|
||||
if (compressed) {
|
||||
split->block_len = em->block_len;
|
||||
split->block_start = em->block_start;
|
||||
split->orig_start = em->orig_start;
|
||||
if (em->block_start < EXTENT_MAP_LAST_BYTE) {
|
||||
split->orig_block_len = max(em->block_len,
|
||||
em->orig_block_len);
|
||||
|
||||
split->ram_bytes = em->ram_bytes;
|
||||
if (compressed) {
|
||||
split->block_len = em->block_len;
|
||||
split->block_start = em->block_start;
|
||||
split->orig_start = em->orig_start;
|
||||
} else {
|
||||
split->block_len = split->len;
|
||||
split->block_start = em->block_start
|
||||
+ diff;
|
||||
split->orig_start = em->orig_start;
|
||||
}
|
||||
} else {
|
||||
split->block_len = split->len;
|
||||
split->block_start = em->block_start + diff;
|
||||
split->orig_start = em->orig_start;
|
||||
split->ram_bytes = split->len;
|
||||
split->orig_start = split->start;
|
||||
split->block_len = 0;
|
||||
split->block_start = em->block_start;
|
||||
split->orig_block_len = 0;
|
||||
}
|
||||
|
||||
ret = add_extent_mapping(em_tree, split, modified);
|
||||
|
|
Loading…
Reference in a new issue