diff options
-rw-r--r-- | fs/ext4/extents.c | 108 |
1 files changed, 85 insertions, 23 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 892662334be9..6c5a70a7b573 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1813,39 +1813,101 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, | |||
1813 | } | 1813 | } |
1814 | depth = ext_depth(inode); | 1814 | depth = ext_depth(inode); |
1815 | ex = path[depth].p_ext; | 1815 | ex = path[depth].p_ext; |
1816 | eh = path[depth].p_hdr; | ||
1816 | if (unlikely(path[depth].p_hdr == NULL)) { | 1817 | if (unlikely(path[depth].p_hdr == NULL)) { |
1817 | EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth); | 1818 | EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth); |
1818 | return -EIO; | 1819 | return -EIO; |
1819 | } | 1820 | } |
1820 | 1821 | ||
1821 | /* try to insert block into found extent and return */ | 1822 | /* try to insert block into found extent and return */ |
1822 | if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO) | 1823 | if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)) { |
1823 | && ext4_can_extents_be_merged(inode, ex, newext)) { | ||
1824 | ext_debug("append [%d]%d block to %u:[%d]%d (from %llu)\n", | ||
1825 | ext4_ext_is_uninitialized(newext), | ||
1826 | ext4_ext_get_actual_len(newext), | ||
1827 | le32_to_cpu(ex->ee_block), | ||
1828 | ext4_ext_is_uninitialized(ex), | ||
1829 | ext4_ext_get_actual_len(ex), | ||
1830 | ext4_ext_pblock(ex)); | ||
1831 | err = ext4_ext_get_access(handle, inode, path + depth); | ||
1832 | if (err) | ||
1833 | return err; | ||
1834 | 1824 | ||
1835 | /* | 1825 | /* |
1836 | * ext4_can_extents_be_merged should have checked that either | 1826 | * Try to see whether we should rather test the extent on |
1837 | * both extents are uninitialized, or both aren't. Thus we | 1827 | * right from ex, or from the left of ex. This is because |
1838 | * need to check only one of them here. | 1828 | * ext4_ext_find_extent() can return either extent on the |
1829 | * left, or on the right from the searched position. This | ||
1830 | * will make merging more effective. | ||
1839 | */ | 1831 | */ |
1840 | if (ext4_ext_is_uninitialized(ex)) | 1832 | if (ex < EXT_LAST_EXTENT(eh) && |
1841 | uninitialized = 1; | 1833 | (le32_to_cpu(ex->ee_block) + |
1842 | ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) | 1834 | ext4_ext_get_actual_len(ex) < |
1835 | le32_to_cpu(newext->ee_block))) { | ||
1836 | ex += 1; | ||
1837 | goto prepend; | ||
1838 | } else if ((ex > EXT_FIRST_EXTENT(eh)) && | ||
1839 | (le32_to_cpu(newext->ee_block) + | ||
1840 | ext4_ext_get_actual_len(newext) < | ||
1841 | le32_to_cpu(ex->ee_block))) | ||
1842 | ex -= 1; | ||
1843 | |||
1844 | /* Try to append newex to the ex */ | ||
1845 | if (ext4_can_extents_be_merged(inode, ex, newext)) { | ||
1846 | ext_debug("append [%d]%d block to %u:[%d]%d" | ||
1847 | "(from %llu)\n", | ||
1848 | ext4_ext_is_uninitialized(newext), | ||
1849 | ext4_ext_get_actual_len(newext), | ||
1850 | le32_to_cpu(ex->ee_block), | ||
1851 | ext4_ext_is_uninitialized(ex), | ||
1852 | ext4_ext_get_actual_len(ex), | ||
1853 | ext4_ext_pblock(ex)); | ||
1854 | err = ext4_ext_get_access(handle, inode, | ||
1855 | path + depth); | ||
1856 | if (err) | ||
1857 | return err; | ||
1858 | |||
1859 | /* | ||
1860 | * ext4_can_extents_be_merged should have checked | ||
1861 | * that either both extents are uninitialized, or | ||
1862 | * both aren't. Thus we need to check only one of | ||
1863 | * them here. | ||
1864 | */ | ||
1865 | if (ext4_ext_is_uninitialized(ex)) | ||
1866 | uninitialized = 1; | ||
1867 | ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) | ||
1843 | + ext4_ext_get_actual_len(newext)); | 1868 | + ext4_ext_get_actual_len(newext)); |
1844 | if (uninitialized) | 1869 | if (uninitialized) |
1845 | ext4_ext_mark_uninitialized(ex); | 1870 | ext4_ext_mark_uninitialized(ex); |
1846 | eh = path[depth].p_hdr; | 1871 | eh = path[depth].p_hdr; |
1847 | nearex = ex; | 1872 | nearex = ex; |
1848 | goto merge; | 1873 | goto merge; |
1874 | } | ||
1875 | |||
1876 | prepend: | ||
1877 | /* Try to prepend newex to the ex */ | ||
1878 | if (ext4_can_extents_be_merged(inode, newext, ex)) { | ||
1879 | ext_debug("prepend %u[%d]%d block to %u:[%d]%d" | ||
1880 | "(from %llu)\n", | ||
1881 | le32_to_cpu(newext->ee_block), | ||
1882 | ext4_ext_is_uninitialized(newext), | ||
1883 | ext4_ext_get_actual_len(newext), | ||
1884 | le32_to_cpu(ex->ee_block), | ||
1885 | ext4_ext_is_uninitialized(ex), | ||
1886 | ext4_ext_get_actual_len(ex), | ||
1887 | ext4_ext_pblock(ex)); | ||
1888 | err = ext4_ext_get_access(handle, inode, | ||
1889 | path + depth); | ||
1890 | if (err) | ||
1891 | return err; | ||
1892 | |||
1893 | /* | ||
1894 | * ext4_can_extents_be_merged should have checked | ||
1895 | * that either both extents are uninitialized, or | ||
1896 | * both aren't. Thus we need to check only one of | ||
1897 | * them here. | ||
1898 | */ | ||
1899 | if (ext4_ext_is_uninitialized(ex)) | ||
1900 | uninitialized = 1; | ||
1901 | ex->ee_block = newext->ee_block; | ||
1902 | ext4_ext_store_pblock(ex, ext4_ext_pblock(newext)); | ||
1903 | ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) | ||
1904 | + ext4_ext_get_actual_len(newext)); | ||
1905 | if (uninitialized) | ||
1906 | ext4_ext_mark_uninitialized(ex); | ||
1907 | eh = path[depth].p_hdr; | ||
1908 | nearex = ex; | ||
1909 | goto merge; | ||
1910 | } | ||
1849 | } | 1911 | } |
1850 | 1912 | ||
1851 | depth = ext_depth(inode); | 1913 | depth = ext_depth(inode); |