diff options
author | Zheng Liu <wenqing.lz@taobao.com> | 2013-02-18 00:29:59 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-02-18 00:29:59 -0500 |
commit | d100eef2440fea13e4f09e88b1c8bcbca64beb9f (patch) | |
tree | 2451dc4582b43a30b414c89108b75148d48c9b57 /fs/ext4/inode.c | |
parent | f7fec032aa782d3fd7e51fbdf08aa3a296c01500 (diff) |
ext4: lookup block mapping in extent status tree
After tracking all extent status, we already have a extent cache in
memory. Every time we want to lookup a block mapping, we can first
try to lookup it in extent status tree to avoid a potential disk I/O.
A new function called ext4_es_lookup_extent is defined to finish this
work. When we try to lookup a block mapping, we always call
ext4_map_blocks and/or ext4_da_map_blocks. So in these functions we
first try to lookup a block mapping in extent status tree.
A new flag EXT4_GET_BLOCKS_NO_PUT_HOLE is used in ext4_da_map_blocks
in order not to put a hole into extent status tree because this hole
will be converted to delayed extent in the tree immediately.
Signed-off-by: Zheng Liu <wenqing.lz@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Cc: Jan kara <jack@suse.cz>
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r-- | fs/ext4/inode.c | 66 |
1 files changed, 64 insertions, 2 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 576b586b61aa..95a0c62c5683 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -507,12 +507,33 @@ static pgoff_t ext4_num_dirty_pages(struct inode *inode, pgoff_t idx, | |||
507 | int ext4_map_blocks(handle_t *handle, struct inode *inode, | 507 | int ext4_map_blocks(handle_t *handle, struct inode *inode, |
508 | struct ext4_map_blocks *map, int flags) | 508 | struct ext4_map_blocks *map, int flags) |
509 | { | 509 | { |
510 | struct extent_status es; | ||
510 | int retval; | 511 | int retval; |
511 | 512 | ||
512 | map->m_flags = 0; | 513 | map->m_flags = 0; |
513 | ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u," | 514 | ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u," |
514 | "logical block %lu\n", inode->i_ino, flags, map->m_len, | 515 | "logical block %lu\n", inode->i_ino, flags, map->m_len, |
515 | (unsigned long) map->m_lblk); | 516 | (unsigned long) map->m_lblk); |
517 | |||
518 | /* Lookup extent status tree firstly */ | ||
519 | if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { | ||
520 | if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { | ||
521 | map->m_pblk = ext4_es_pblock(&es) + | ||
522 | map->m_lblk - es.es_lblk; | ||
523 | map->m_flags |= ext4_es_is_written(&es) ? | ||
524 | EXT4_MAP_MAPPED : EXT4_MAP_UNWRITTEN; | ||
525 | retval = es.es_len - (map->m_lblk - es.es_lblk); | ||
526 | if (retval > map->m_len) | ||
527 | retval = map->m_len; | ||
528 | map->m_len = retval; | ||
529 | } else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) { | ||
530 | retval = 0; | ||
531 | } else { | ||
532 | BUG_ON(1); | ||
533 | } | ||
534 | goto found; | ||
535 | } | ||
536 | |||
516 | /* | 537 | /* |
517 | * Try to see if we can get the block without requesting a new | 538 | * Try to see if we can get the block without requesting a new |
518 | * file system block. | 539 | * file system block. |
@@ -544,6 +565,7 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
544 | if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) | 565 | if (!(flags & EXT4_GET_BLOCKS_NO_LOCK)) |
545 | up_read((&EXT4_I(inode)->i_data_sem)); | 566 | up_read((&EXT4_I(inode)->i_data_sem)); |
546 | 567 | ||
568 | found: | ||
547 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { | 569 | if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { |
548 | int ret = check_block_validity(inode, map); | 570 | int ret = check_block_validity(inode, map); |
549 | if (ret != 0) | 571 | if (ret != 0) |
@@ -1743,6 +1765,7 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
1743 | struct ext4_map_blocks *map, | 1765 | struct ext4_map_blocks *map, |
1744 | struct buffer_head *bh) | 1766 | struct buffer_head *bh) |
1745 | { | 1767 | { |
1768 | struct extent_status es; | ||
1746 | int retval; | 1769 | int retval; |
1747 | sector_t invalid_block = ~((sector_t) 0xffff); | 1770 | sector_t invalid_block = ~((sector_t) 0xffff); |
1748 | 1771 | ||
@@ -1753,6 +1776,42 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
1753 | ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u," | 1776 | ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u," |
1754 | "logical block %lu\n", inode->i_ino, map->m_len, | 1777 | "logical block %lu\n", inode->i_ino, map->m_len, |
1755 | (unsigned long) map->m_lblk); | 1778 | (unsigned long) map->m_lblk); |
1779 | |||
1780 | /* Lookup extent status tree firstly */ | ||
1781 | if (ext4_es_lookup_extent(inode, iblock, &es)) { | ||
1782 | |||
1783 | if (ext4_es_is_hole(&es)) { | ||
1784 | retval = 0; | ||
1785 | down_read((&EXT4_I(inode)->i_data_sem)); | ||
1786 | goto add_delayed; | ||
1787 | } | ||
1788 | |||
1789 | /* | ||
1790 | * Delayed extent could be allocated by fallocate. | ||
1791 | * So we need to check it. | ||
1792 | */ | ||
1793 | if (ext4_es_is_delayed(&es) && !ext4_es_is_unwritten(&es)) { | ||
1794 | map_bh(bh, inode->i_sb, invalid_block); | ||
1795 | set_buffer_new(bh); | ||
1796 | set_buffer_delay(bh); | ||
1797 | return 0; | ||
1798 | } | ||
1799 | |||
1800 | map->m_pblk = ext4_es_pblock(&es) + iblock - es.es_lblk; | ||
1801 | retval = es.es_len - (iblock - es.es_lblk); | ||
1802 | if (retval > map->m_len) | ||
1803 | retval = map->m_len; | ||
1804 | map->m_len = retval; | ||
1805 | if (ext4_es_is_written(&es)) | ||
1806 | map->m_flags |= EXT4_MAP_MAPPED; | ||
1807 | else if (ext4_es_is_unwritten(&es)) | ||
1808 | map->m_flags |= EXT4_MAP_UNWRITTEN; | ||
1809 | else | ||
1810 | BUG_ON(1); | ||
1811 | |||
1812 | return retval; | ||
1813 | } | ||
1814 | |||
1756 | /* | 1815 | /* |
1757 | * Try to see if we can get the block without requesting a new | 1816 | * Try to see if we can get the block without requesting a new |
1758 | * file system block. | 1817 | * file system block. |
@@ -1771,10 +1830,13 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
1771 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; | 1830 | map->m_flags |= EXT4_MAP_FROM_CLUSTER; |
1772 | retval = 0; | 1831 | retval = 0; |
1773 | } else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) | 1832 | } else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) |
1774 | retval = ext4_ext_map_blocks(NULL, inode, map, 0); | 1833 | retval = ext4_ext_map_blocks(NULL, inode, map, |
1834 | EXT4_GET_BLOCKS_NO_PUT_HOLE); | ||
1775 | else | 1835 | else |
1776 | retval = ext4_ind_map_blocks(NULL, inode, map, 0); | 1836 | retval = ext4_ind_map_blocks(NULL, inode, map, |
1837 | EXT4_GET_BLOCKS_NO_PUT_HOLE); | ||
1777 | 1838 | ||
1839 | add_delayed: | ||
1778 | if (retval == 0) { | 1840 | if (retval == 0) { |
1779 | int ret; | 1841 | int ret; |
1780 | /* | 1842 | /* |