@@ -1756,6 +1756,99 @@ int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
1756
1756
return err ;
1757
1757
} /* ext4_group_extend */
1758
1758
1759
+
1760
+ static int num_desc_blocks (struct super_block * sb , ext4_group_t groups )
1761
+ {
1762
+ return (groups + EXT4_DESC_PER_BLOCK (sb ) - 1 ) / EXT4_DESC_PER_BLOCK (sb );
1763
+ }
1764
+
1765
+ /*
1766
+ * Release the resize inode and drop the resize_inode feature if there
1767
+ * are no more reserved gdt blocks, and then convert the file system
1768
+ * to enable meta_bg
1769
+ */
1770
+ static int ext4_convert_meta_bg (struct super_block * sb , struct inode * inode )
1771
+ {
1772
+ handle_t * handle ;
1773
+ struct ext4_sb_info * sbi = EXT4_SB (sb );
1774
+ struct ext4_super_block * es = sbi -> s_es ;
1775
+ struct ext4_inode_info * ei = 0 ;
1776
+ ext4_fsblk_t nr ;
1777
+ int i , ret , err = 0 ;
1778
+ int credits = 1 ;
1779
+
1780
+ ext4_msg (sb , KERN_INFO , "Converting file system to meta_bg" );
1781
+ if (EXT4_HAS_COMPAT_FEATURE (sb , EXT4_FEATURE_COMPAT_RESIZE_INODE )) {
1782
+ if (es -> s_reserved_gdt_blocks ) {
1783
+ ext4_error (sb , "Unexpected non-zero "
1784
+ "s_reserved_gdt_blocks" );
1785
+ return - EPERM ;
1786
+ }
1787
+ if (!inode ) {
1788
+ ext4_error (sb , "Unexpected NULL resize_inode" );
1789
+ return - EPERM ;
1790
+ }
1791
+ ei = EXT4_I (inode );
1792
+
1793
+ /* Do a quick sanity check of the resize inode */
1794
+ if (inode -> i_blocks != 1 << (inode -> i_blkbits - 9 ))
1795
+ goto invalid_resize_inode ;
1796
+ for (i = 0 ; i < EXT4_N_BLOCKS ; i ++ ) {
1797
+ if (i == EXT4_DIND_BLOCK ) {
1798
+ if (ei -> i_data [i ])
1799
+ continue ;
1800
+ else
1801
+ goto invalid_resize_inode ;
1802
+ }
1803
+ if (ei -> i_data [i ])
1804
+ goto invalid_resize_inode ;
1805
+ }
1806
+ credits += 3 ; /* block bitmap, bg descriptor, resize inode */
1807
+ }
1808
+
1809
+ handle = ext4_journal_start_sb (sb , credits );
1810
+ if (IS_ERR (handle ))
1811
+ return PTR_ERR (handle );
1812
+
1813
+ err = ext4_journal_get_write_access (handle , sbi -> s_sbh );
1814
+ if (err )
1815
+ goto errout ;
1816
+
1817
+ EXT4_CLEAR_COMPAT_FEATURE (sb , EXT4_FEATURE_COMPAT_RESIZE_INODE );
1818
+ EXT4_SET_INCOMPAT_FEATURE (sb , EXT4_FEATURE_INCOMPAT_META_BG );
1819
+ sbi -> s_es -> s_first_meta_bg =
1820
+ cpu_to_le32 (num_desc_blocks (sb , sbi -> s_groups_count ));
1821
+
1822
+ err = ext4_handle_dirty_super (handle , sb );
1823
+ if (err ) {
1824
+ ext4_std_error (sb , err );
1825
+ goto errout ;
1826
+ }
1827
+
1828
+ if (inode ) {
1829
+ nr = le32_to_cpu (ei -> i_data [EXT4_DIND_BLOCK ]);
1830
+ ext4_free_blocks (handle , inode , NULL , nr , 1 ,
1831
+ EXT4_FREE_BLOCKS_METADATA |
1832
+ EXT4_FREE_BLOCKS_FORGET );
1833
+ ei -> i_data [EXT4_DIND_BLOCK ] = 0 ;
1834
+ inode -> i_blocks = 0 ;
1835
+
1836
+ err = ext4_mark_inode_dirty (handle , inode );
1837
+ if (err )
1838
+ ext4_std_error (sb , err );
1839
+ }
1840
+
1841
+ errout :
1842
+ ret = ext4_journal_stop (handle );
1843
+ if (!err )
1844
+ err = ret ;
1845
+ return ret ;
1846
+
1847
+ invalid_resize_inode :
1848
+ ext4_error (sb , "corrupted/inconsistent resize inode" );
1849
+ return - EINVAL ;
1850
+ }
1851
+
1759
1852
/*
1760
1853
* ext4_resize_fs() resizes a fs to new size specified by @n_blocks_count
1761
1854
*
@@ -1772,13 +1865,14 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1772
1865
ext4_grpblk_t add , offset ;
1773
1866
unsigned long n_desc_blocks ;
1774
1867
unsigned long o_desc_blocks ;
1775
- unsigned long desc_blocks ;
1776
1868
ext4_group_t o_group ;
1777
1869
ext4_group_t n_group ;
1778
1870
ext4_fsblk_t o_blocks_count ;
1871
+ ext4_fsblk_t n_blocks_count_retry = 0 ;
1779
1872
int err = 0 , flexbg_size = 1 << sbi -> s_log_groups_per_flex ;
1780
1873
int meta_bg ;
1781
1874
1875
+ retry :
1782
1876
o_blocks_count = ext4_blocks_count (es );
1783
1877
1784
1878
if (test_opt (sb , DEBUG ))
@@ -1798,11 +1892,8 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1798
1892
ext4_get_group_no_and_offset (sb , n_blocks_count - 1 , & n_group , & offset );
1799
1893
ext4_get_group_no_and_offset (sb , o_blocks_count - 1 , & o_group , & offset );
1800
1894
1801
- n_desc_blocks = (n_group + EXT4_DESC_PER_BLOCK (sb )) /
1802
- EXT4_DESC_PER_BLOCK (sb );
1803
- o_desc_blocks = (sbi -> s_groups_count + EXT4_DESC_PER_BLOCK (sb ) - 1 ) /
1804
- EXT4_DESC_PER_BLOCK (sb );
1805
- desc_blocks = n_desc_blocks - o_desc_blocks ;
1895
+ n_desc_blocks = num_desc_blocks (sb , n_group + 1 );
1896
+ o_desc_blocks = num_desc_blocks (sb , sbi -> s_groups_count );
1806
1897
1807
1898
meta_bg = EXT4_HAS_INCOMPAT_FEATURE (sb , EXT4_FEATURE_INCOMPAT_META_BG );
1808
1899
@@ -1812,20 +1903,37 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1812
1903
"simultaneously" );
1813
1904
return - EINVAL ;
1814
1905
}
1815
- if (le16_to_cpu (es -> s_reserved_gdt_blocks ) < desc_blocks ) {
1816
- ext4_warning (sb ,
1817
- "No reserved GDT blocks, can't resize" );
1818
- return - EPERM ;
1906
+ if (n_desc_blocks > o_desc_blocks +
1907
+ le16_to_cpu (es -> s_reserved_gdt_blocks )) {
1908
+ n_blocks_count_retry = n_blocks_count ;
1909
+ n_desc_blocks = o_desc_blocks +
1910
+ le16_to_cpu (es -> s_reserved_gdt_blocks );
1911
+ n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK (sb );
1912
+ n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP (sb );
1913
+ n_group -- ; /* set to last group number */
1819
1914
}
1820
- resize_inode = ext4_iget (sb , EXT4_RESIZE_INO );
1915
+
1916
+ if (!resize_inode )
1917
+ resize_inode = ext4_iget (sb , EXT4_RESIZE_INO );
1821
1918
if (IS_ERR (resize_inode )) {
1822
1919
ext4_warning (sb , "Error opening resize inode" );
1823
1920
return PTR_ERR (resize_inode );
1824
1921
}
1825
- } else if (!meta_bg ) {
1826
- ext4_warning (sb , "File system features do not permit "
1827
- "online resize" );
1828
- return - EPERM ;
1922
+ }
1923
+
1924
+ if ((!resize_inode && !meta_bg ) || n_group == o_group ) {
1925
+ err = ext4_convert_meta_bg (sb , resize_inode );
1926
+ if (err )
1927
+ goto out ;
1928
+ if (resize_inode ) {
1929
+ iput (resize_inode );
1930
+ resize_inode = NULL ;
1931
+ }
1932
+ if (n_blocks_count_retry ) {
1933
+ n_blocks_count = n_blocks_count_retry ;
1934
+ n_blocks_count_retry = 0 ;
1935
+ goto retry ;
1936
+ }
1829
1937
}
1830
1938
1831
1939
/* See if the device is actually as big as what was requested */
@@ -1876,13 +1984,21 @@ int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count)
1876
1984
break ;
1877
1985
}
1878
1986
1987
+ if (!err && n_blocks_count_retry ) {
1988
+ n_blocks_count = n_blocks_count_retry ;
1989
+ n_blocks_count_retry = 0 ;
1990
+ free_flex_gd (flex_gd );
1991
+ flex_gd = NULL ;
1992
+ goto retry ;
1993
+ }
1994
+
1879
1995
out :
1880
1996
if (flex_gd )
1881
1997
free_flex_gd (flex_gd );
1882
1998
if (resize_inode != NULL )
1883
1999
iput (resize_inode );
1884
2000
if (test_opt (sb , DEBUG ))
1885
- ext4_msg (sb , KERN_DEBUG , "resized filesystem from %llu "
1886
- "upto %llu blocks" , o_blocks_count , n_blocks_count );
2001
+ ext4_msg (sb , KERN_DEBUG , "resized filesystem to %llu" ,
2002
+ n_blocks_count );
1887
2003
return err ;
1888
2004
}
0 commit comments