diff options
| -rw-r--r-- | fs/ext4/ext4.h | 3 | ||||
| -rw-r--r-- | fs/ext4/extents.c | 20 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 76 |
3 files changed, 69 insertions, 30 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index fc1c0375c9f2..5c31d6ac9500 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -2602,6 +2602,9 @@ extern struct ext4_ext_path *ext4_ext_find_extent(struct inode *, ext4_lblk_t, | |||
| 2602 | struct ext4_ext_path *); | 2602 | struct ext4_ext_path *); |
| 2603 | extern void ext4_ext_drop_refs(struct ext4_ext_path *); | 2603 | extern void ext4_ext_drop_refs(struct ext4_ext_path *); |
| 2604 | extern int ext4_ext_check_inode(struct inode *inode); | 2604 | extern int ext4_ext_check_inode(struct inode *inode); |
| 2605 | extern int ext4_find_delalloc_range(struct inode *inode, | ||
| 2606 | ext4_lblk_t lblk_start, | ||
| 2607 | ext4_lblk_t lblk_end); | ||
| 2605 | extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); | 2608 | extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); |
| 2606 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 2609 | extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
| 2607 | __u64 start, __u64 len); | 2610 | __u64 start, __u64 len); |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index cae8ae3c1746..be0b1b3eed97 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -2076,8 +2076,18 @@ static int ext4_fill_fiemap_extents(struct inode *inode, | |||
| 2076 | break; | 2076 | break; |
| 2077 | } | 2077 | } |
| 2078 | 2078 | ||
| 2079 | /* This is possible iff next == next_del == EXT_MAX_BLOCKS */ | 2079 | /* |
| 2080 | if (next == next_del) { | 2080 | * This is possible iff next == next_del == EXT_MAX_BLOCKS. |
| 2081 | * we need to check next == EXT_MAX_BLOCKS because it is | ||
| 2082 | * possible that an extent is with unwritten and delayed | ||
| 2083 | * status due to when an extent is delayed allocated and | ||
| 2084 | * is allocated by fallocate status tree will track both of | ||
| 2085 | * them in a extent. | ||
| 2086 | * | ||
| 2087 | * So we could return a unwritten and delayed extent, and | ||
| 2088 | * its block is equal to 'next'. | ||
| 2089 | */ | ||
| 2090 | if (next == next_del && next == EXT_MAX_BLOCKS) { | ||
| 2081 | flags |= FIEMAP_EXTENT_LAST; | 2091 | flags |= FIEMAP_EXTENT_LAST; |
| 2082 | if (unlikely(next_del != EXT_MAX_BLOCKS || | 2092 | if (unlikely(next_del != EXT_MAX_BLOCKS || |
| 2083 | next != EXT_MAX_BLOCKS)) { | 2093 | next != EXT_MAX_BLOCKS)) { |
| @@ -3522,9 +3532,9 @@ out: | |||
| 3522 | * | 3532 | * |
| 3523 | * Return 1 if there is a delalloc block in the range, otherwise 0. | 3533 | * Return 1 if there is a delalloc block in the range, otherwise 0. |
| 3524 | */ | 3534 | */ |
| 3525 | static int ext4_find_delalloc_range(struct inode *inode, | 3535 | int ext4_find_delalloc_range(struct inode *inode, |
| 3526 | ext4_lblk_t lblk_start, | 3536 | ext4_lblk_t lblk_start, |
| 3527 | ext4_lblk_t lblk_end) | 3537 | ext4_lblk_t lblk_end) |
| 3528 | { | 3538 | { |
| 3529 | struct extent_status es; | 3539 | struct extent_status es; |
| 3530 | 3540 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 084b8212cf95..576b586b61aa 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -526,20 +526,26 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
| 526 | retval = ext4_ind_map_blocks(handle, inode, map, flags & | 526 | retval = ext4_ind_map_blocks(handle, inode, map, flags & |
| 527 | EXT4_GET_BLOCKS_KEEP_SIZE); | 527 | EXT4_GET_BLOCKS_KEEP_SIZE); |
| 528 | } | 528 | } |
| 529 | if (retval > 0) { | ||
| 530 | int ret; | ||
| 531 | unsigned long long status; | ||
| 532 | |||
| 533 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? | ||
| 534 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; | ||
| 535 | if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && | ||
| 536 | ext4_find_delalloc_range(inode, map->m_lblk, | ||
| 537 | map->m_lblk + map->m_len - 1)) | ||
| 538 | status |= EXTENT_STATUS_DELAYED; | ||
| 539 | ret = ext4_es_insert_extent(inode, map->m_lblk, | ||
| 540 | map->m_len, map->m_pblk, status); | ||
| 541 | if (ret < 0) | ||
| 542 | retval = ret; | ||
| 543 | } | ||
| 529 | if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) | 544 | if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) |
| 530 | up_read((&EXT4_I(inode)->i_data_sem)); | 545 | up_read((&EXT4_I(inode)->i_data_sem)); |
| 531 | 546 | ||
| 532 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { | 547 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { |
| 533 | int ret; | 548 | int ret = check_block_validity(inode, map); |
| 534 | if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { | ||
| 535 | /* delayed alloc may be allocated by fallocate and | ||
| 536 | * coverted to initialized by directIO. | ||
| 537 | * we need to handle delayed extent here. | ||
| 538 | */ | ||
| 539 | down_write((&EXT4_I(inode)->i_data_sem)); | ||
| 540 | goto delayed_mapped; | ||
| 541 | } | ||
| 542 | ret = check_block_validity(inode, map); | ||
| 543 | if (ret != 0) | 549 | if (ret != 0) |
| 544 | return ret; | 550 | return ret; |
| 545 | } | 551 | } |
| @@ -608,18 +614,23 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
| 608 | (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)) | 614 | (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)) |
| 609 | ext4_da_update_reserve_space(inode, retval, 1); | 615 | ext4_da_update_reserve_space(inode, retval, 1); |
| 610 | } | 616 | } |
| 611 | if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { | 617 | if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) |
| 612 | ext4_clear_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED); | 618 | ext4_clear_inode_state(inode, EXT4_STATE_DELALLOC_RESERVED); |
| 613 | 619 | ||
| 614 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { | 620 | if (retval > 0) { |
| 615 | int ret; | 621 | int ret; |
| 616 | delayed_mapped: | 622 | unsigned long long status; |
| 617 | /* delayed allocation blocks has been allocated */ | 623 | |
| 618 | ret = ext4_es_remove_extent(inode, map->m_lblk, | 624 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? |
| 619 | map->m_len); | 625 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; |
| 620 | if (ret < 0) | 626 | if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && |
| 621 | retval = ret; | 627 | ext4_find_delalloc_range(inode, map->m_lblk, |
| 622 | } | 628 | map->m_lblk + map->m_len - 1)) |
| 629 | status |= EXTENT_STATUS_DELAYED; | ||
| 630 | ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, | ||
| 631 | map->m_pblk, status); | ||
| 632 | if (ret < 0) | ||
| 633 | retval = ret; | ||
| 623 | } | 634 | } |
| 624 | 635 | ||
| 625 | up_write((&EXT4_I(inode)->i_data_sem)); | 636 | up_write((&EXT4_I(inode)->i_data_sem)); |
| @@ -1765,6 +1776,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
| 1765 | retval = ext4_ind_map_blocks(NULL, inode, map, 0); | 1776 | retval = ext4_ind_map_blocks(NULL, inode, map, 0); |
| 1766 | 1777 | ||
| 1767 | if (retval == 0) { | 1778 | if (retval == 0) { |
| 1779 | int ret; | ||
| 1768 | /* | 1780 | /* |
| 1769 | * XXX: __block_prepare_write() unmaps passed block, | 1781 | * XXX: __block_prepare_write() unmaps passed block, |
| 1770 | * is it OK? | 1782 | * is it OK? |
| @@ -1772,16 +1784,20 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
| 1772 | /* If the block was allocated from previously allocated cluster, | 1784 | /* If the block was allocated from previously allocated cluster, |
| 1773 | * then we dont need to reserve it again. */ | 1785 | * then we dont need to reserve it again. */ |
| 1774 | if (!(map->m_flags & EXT4_MAP_FROM_CLUSTER)) { | 1786 | if (!(map->m_flags & EXT4_MAP_FROM_CLUSTER)) { |
| 1775 | retval = ext4_da_reserve_space(inode, iblock); | 1787 | ret = ext4_da_reserve_space(inode, iblock); |
| 1776 | if (retval) | 1788 | if (ret) { |
| 1777 | /* not enough space to reserve */ | 1789 | /* not enough space to reserve */ |
| 1790 | retval = ret; | ||
| 1778 | goto out_unlock; | 1791 | goto out_unlock; |
| 1792 | } | ||
| 1779 | } | 1793 | } |
| 1780 | 1794 | ||
| 1781 | retval = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, | 1795 | ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, |
| 1782 | ~0, EXTENT_STATUS_DELAYED); | 1796 | ~0, EXTENT_STATUS_DELAYED); |
| 1783 | if (retval) | 1797 | if (ret) { |
| 1798 | retval = ret; | ||
| 1784 | goto out_unlock; | 1799 | goto out_unlock; |
| 1800 | } | ||
| 1785 | 1801 | ||
| 1786 | /* Clear EXT4_MAP_FROM_CLUSTER flag since its purpose is served | 1802 | /* Clear EXT4_MAP_FROM_CLUSTER flag since its purpose is served |
| 1787 | * and it should not appear on the bh->b_state. | 1803 | * and it should not appear on the bh->b_state. |
| @@ -1791,6 +1807,16 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
| 1791 | map_bh(bh, inode->i_sb, invalid_block); | 1807 | map_bh(bh, inode->i_sb, invalid_block); |
| 1792 | set_buffer_new(bh); | 1808 | set_buffer_new(bh); |
| 1793 | set_buffer_delay(bh); | 1809 | set_buffer_delay(bh); |
| 1810 | } else if (retval > 0) { | ||
| 1811 | int ret; | ||
| 1812 | unsigned long long status; | ||
| 1813 | |||
| 1814 | status = map->m_flags & EXT4_MAP_UNWRITTEN ? | ||
| 1815 | EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; | ||
| 1816 | ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, | ||
| 1817 | map->m_pblk, status); | ||
| 1818 | if (ret != 0) | ||
| 1819 | retval = ret; | ||
| 1794 | } | 1820 | } |
| 1795 | 1821 | ||
| 1796 | out_unlock: | 1822 | out_unlock: |
