3.16.70-rc1 review patch.  If anyone has any objections, please let me know.

------------------

From: Jan Kara <j...@suse.cz>

commit 1c2d14212b15a60300a2d4f6364753e87394c521 upstream.

When ext2 filesystem is created with 64k block size, ext2_max_size()
will return value less than 0. Also, we cannot write any file in this fs
since the sb->maxbytes is less than 0. The core of the problem is that
the size of block index tree for such large block size is more than
i_blocks can carry. So fix the computation to count with this
possibility.

File size limits computed with the new function for the full range of
possible block sizes look like:

bits file_size
10     17247252480
11    275415851008
12   2196873666560
13   2197948973056
14   2198486220800
15   2198754754560
16   2198888906752

Reported-by: yangerkun <yanger...@huawei.com>
Signed-off-by: Jan Kara <j...@suse.cz>
Signed-off-by: Ben Hutchings <b...@decadent.org.uk>
---
 fs/ext2/super.c | 39 +++++++++++++++++++++++++--------------
 1 file changed, 25 insertions(+), 14 deletions(-)

--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -701,7 +701,8 @@ static loff_t ext2_max_size(int bits)
 {
        loff_t res = EXT2_NDIR_BLOCKS;
        int meta_blocks;
-       loff_t upper_limit;
+       unsigned int upper_limit;
+       unsigned int ppb = 1 << (bits-2);
 
        /* This is calculated to be the largest file size for a
         * dense, file such that the total number of
@@ -715,24 +716,34 @@ static loff_t ext2_max_size(int bits)
        /* total blocks in file system block size */
        upper_limit >>= (bits - 9);
 
-
-       /* indirect blocks */
-       meta_blocks = 1;
-       /* double indirect blocks */
-       meta_blocks += 1 + (1LL << (bits-2));
-       /* tripple indirect blocks */
-       meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2)));
-
-       upper_limit -= meta_blocks;
-       upper_limit <<= bits;
-
+       /* Compute how many blocks we can address by block tree */
        res += 1LL << (bits-2);
        res += 1LL << (2*(bits-2));
        res += 1LL << (3*(bits-2));
+       /* Does block tree limit file size? */
+       if (res < upper_limit)
+               goto check_lfs;
+
+       res = upper_limit;
+       /* How many metadata blocks are needed for addressing upper_limit? */
+       upper_limit -= EXT2_NDIR_BLOCKS;
+       /* indirect blocks */
+       meta_blocks = 1;
+       upper_limit -= ppb;
+       /* double indirect blocks */
+       if (upper_limit < ppb * ppb) {
+               meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb);
+               res -= meta_blocks;
+               goto check_lfs;
+       }
+       meta_blocks += 1 + ppb;
+       upper_limit -= ppb * ppb;
+       /* tripple indirect blocks for the rest */
+       meta_blocks += 1 + DIV_ROUND_UP(upper_limit, ppb) +
+               DIV_ROUND_UP(upper_limit, ppb*ppb);
+       res -= meta_blocks;
+check_lfs:
        res <<= bits;
-       if (res > upper_limit)
-               res = upper_limit;
-
        if (res > MAX_LFS_FILESIZE)
                res = MAX_LFS_FILESIZE;
 

Reply via email to