diff options
author | Josef Bacik <jbacik@fusionio.com> | 2013-07-11 10:34:59 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-08-09 19:30:09 -0400 |
commit | ee20a98314e52a6675e94d1a07ca205ffdf09a72 (patch) | |
tree | 7a4b93b7c6b3603795a36464944d8c479806e41c /fs | |
parent | ed8c4913da4951957bf8afc788522788881ff405 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/file.c | 62 |
1 files changed, 40 insertions, 22 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index a005fe2c072a..8e686a427ce2 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -596,20 +596,29 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
596 | if (no_splits) | 596 | if (no_splits) |
597 | goto next; | 597 | goto next; |
598 | 598 | ||
599 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | 599 | if (em->start < start) { |
600 | em->start < start) { | ||
601 | split->start = em->start; | 600 | split->start = em->start; |
602 | split->len = start - em->start; | 601 | split->len = start - em->start; |
603 | split->orig_start = em->orig_start; | ||
604 | split->block_start = em->block_start; | ||
605 | 602 | ||
606 | if (compressed) | 603 | if (em->block_start < EXTENT_MAP_LAST_BYTE) { |
607 | split->block_len = em->block_len; | 604 | split->orig_start = em->orig_start; |
608 | else | 605 | split->block_start = em->block_start; |
609 | split->block_len = split->len; | 606 | |
610 | split->ram_bytes = em->ram_bytes; | 607 | if (compressed) |
611 | split->orig_block_len = max(split->block_len, | 608 | split->block_len = em->block_len; |
612 | em->orig_block_len); | 609 | else |
610 | split->block_len = split->len; | ||
611 | split->orig_block_len = max(split->block_len, | ||
612 | em->orig_block_len); | ||
613 | split->ram_bytes = em->ram_bytes; | ||
614 | } else { | ||
615 | split->orig_start = split->start; | ||
616 | split->block_len = 0; | ||
617 | split->block_start = em->block_start; | ||
618 | split->orig_block_len = 0; | ||
619 | split->ram_bytes = split->len; | ||
620 | } | ||
621 | |||
613 | split->generation = gen; | 622 | split->generation = gen; |
614 | split->bdev = em->bdev; | 623 | split->bdev = em->bdev; |
615 | split->flags = flags; | 624 | split->flags = flags; |
@@ -620,8 +629,7 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
620 | split = split2; | 629 | split = split2; |
621 | split2 = NULL; | 630 | split2 = NULL; |
622 | } | 631 | } |
623 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | 632 | if (testend && em->start + em->len > start + len) { |
624 | testend && em->start + em->len > start + len) { | ||
625 | u64 diff = start + len - em->start; | 633 | u64 diff = start + len - em->start; |
626 | 634 | ||
627 | split->start = start + len; | 635 | split->start = start + len; |
@@ -630,18 +638,28 @@ void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, | |||
630 | split->flags = flags; | 638 | split->flags = flags; |
631 | split->compress_type = em->compress_type; | 639 | split->compress_type = em->compress_type; |
632 | split->generation = gen; | 640 | split->generation = gen; |
633 | split->orig_block_len = max(em->block_len, | 641 | |
642 | if (em->block_start < EXTENT_MAP_LAST_BYTE) { | ||
643 | split->orig_block_len = max(em->block_len, | ||
634 | em->orig_block_len); | 644 | em->orig_block_len); |
635 | split->ram_bytes = em->ram_bytes; | ||
636 | 645 | ||
637 | if (compressed) { | 646 | split->ram_bytes = em->ram_bytes; |
638 | split->block_len = em->block_len; | 647 | if (compressed) { |
639 | split->block_start = em->block_start; | 648 | split->block_len = em->block_len; |
640 | split->orig_start = em->orig_start; | 649 | split->block_start = em->block_start; |
650 | split->orig_start = em->orig_start; | ||
651 | } else { | ||
652 | split->block_len = split->len; | ||
653 | split->block_start = em->block_start | ||
654 | + diff; | ||
655 | split->orig_start = em->orig_start; | ||
656 | } | ||
641 | } else { | 657 | } else { |
642 | split->block_len = split->len; | 658 | split->ram_bytes = split->len; |
643 | split->block_start = em->block_start + diff; | 659 | split->orig_start = split->start; |
644 | split->orig_start = em->orig_start; | 660 | split->block_len = 0; |
661 | split->block_start = em->block_start; | ||
662 | split->orig_block_len = 0; | ||
645 | } | 663 | } |
646 | 664 | ||
647 | ret = add_extent_mapping(em_tree, split, modified); | 665 | ret = add_extent_mapping(em_tree, split, modified); |