diff options
| -rw-r--r-- | fs/btrfs/inode.c | 56 |
1 files changed, 43 insertions, 13 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f81a48c47fe0..4f8fb1130cf3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -7540,6 +7540,27 @@ static struct extent_map *create_io_em(struct inode *inode, u64 start, u64 len, | |||
| 7540 | return em; | 7540 | return em; |
| 7541 | } | 7541 | } |
| 7542 | 7542 | ||
| 7543 | |||
| 7544 | static int btrfs_get_blocks_direct_read(struct extent_map *em, | ||
| 7545 | struct buffer_head *bh_result, | ||
| 7546 | struct inode *inode, | ||
| 7547 | u64 start, u64 len) | ||
| 7548 | { | ||
| 7549 | if (em->block_start == EXTENT_MAP_HOLE || | ||
| 7550 | test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) | ||
| 7551 | return -ENOENT; | ||
| 7552 | |||
| 7553 | len = min(len, em->len - (start - em->start)); | ||
| 7554 | |||
| 7555 | bh_result->b_blocknr = (em->block_start + (start - em->start)) >> | ||
| 7556 | inode->i_blkbits; | ||
| 7557 | bh_result->b_size = len; | ||
| 7558 | bh_result->b_bdev = em->bdev; | ||
| 7559 | set_buffer_mapped(bh_result); | ||
| 7560 | |||
| 7561 | return 0; | ||
| 7562 | } | ||
| 7563 | |||
| 7543 | static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | 7564 | static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, |
| 7544 | struct buffer_head *bh_result, int create) | 7565 | struct buffer_head *bh_result, int create) |
| 7545 | { | 7566 | { |
| @@ -7608,11 +7629,29 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
| 7608 | goto unlock_err; | 7629 | goto unlock_err; |
| 7609 | } | 7630 | } |
| 7610 | 7631 | ||
| 7611 | /* Just a good old fashioned hole, return */ | 7632 | if (!create) { |
| 7612 | if (!create && (em->block_start == EXTENT_MAP_HOLE || | 7633 | ret = btrfs_get_blocks_direct_read(em, bh_result, inode, |
| 7613 | test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { | 7634 | start, len); |
| 7635 | /* Can be negative only if we read from a hole */ | ||
| 7636 | if (ret < 0) { | ||
| 7637 | ret = 0; | ||
| 7638 | free_extent_map(em); | ||
| 7639 | goto unlock_err; | ||
| 7640 | } | ||
| 7641 | /* | ||
| 7642 | * We need to unlock only the end area that we aren't using. | ||
| 7643 | * The rest is going to be unlocked by the endio routine. | ||
| 7644 | */ | ||
| 7645 | lockstart = start + bh_result->b_size; | ||
| 7646 | if (lockstart < lockend) { | ||
| 7647 | clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, | ||
| 7648 | lockend, unlock_bits, 1, 0, | ||
| 7649 | &cached_state); | ||
| 7650 | } else { | ||
| 7651 | free_extent_state(cached_state); | ||
| 7652 | } | ||
| 7614 | free_extent_map(em); | 7653 | free_extent_map(em); |
| 7615 | goto unlock_err; | 7654 | return 0; |
| 7616 | } | 7655 | } |
| 7617 | 7656 | ||
| 7618 | /* | 7657 | /* |
| @@ -7624,12 +7663,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, | |||
| 7624 | * just use the extent. | 7663 | * just use the extent. |
| 7625 | * | 7664 | * |
| 7626 | */ | 7665 | */ |
| 7627 | if (!create) { | ||
| 7628 | len = min(len, em->len - (start - em->start)); | ||
| 7629 | lockstart = start + len; | ||
| 7630 | goto unlock; | ||
| 7631 | } | ||
| 7632 | |||
| 7633 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || | 7666 | if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || |
| 7634 | ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) && | 7667 | ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) && |
| 7635 | em->block_start != EXTENT_MAP_HOLE)) { | 7668 | em->block_start != EXTENT_MAP_HOLE)) { |
| @@ -7716,10 +7749,7 @@ unlock: | |||
| 7716 | clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, | 7749 | clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, |
| 7717 | lockend, unlock_bits, 1, 0, | 7750 | lockend, unlock_bits, 1, 0, |
| 7718 | &cached_state); | 7751 | &cached_state); |
| 7719 | } else { | ||
| 7720 | free_extent_state(cached_state); | ||
| 7721 | } | 7752 | } |
| 7722 | |||
| 7723 | free_extent_map(em); | 7753 | free_extent_map(em); |
| 7724 | 7754 | ||
| 7725 | return 0; | 7755 | return 0; |
