2005-03-17 17:24:22

by Stephen C. Tweedie

[permalink] [raw]
Subject: [Patch] ext2/3 file limits to avoid overflowing i_blocks

[Patch] ext2/3 file limits to avoid overflowing i_blocks

ext2/3 can currently overflow i_blocks past the maximum 2^32 sector
(2TB) limit. The ext[23]_max_size functions try to enforce an upper
limit of 2^32-1 blocks by limiting the file size to 2TB-blocksize, but
this fails to account for indirect block metadata and the possibility of
an extended attribute block also being accounted against i_blocks.

The new file size limit of 0x1ff7fffd000 allows a file to grow to
2^32-blocksize sectors, assuming 4k blocksize. (We don't have to worry
about smaller blocksizes as those have indirect tree limits that don't
let their size grow near this upper bound in the first place.)

Signed-off-by: Stephen Tweedie <[email protected]>

--- linux-2.6-ext3/fs/ext2/super.c.=K0001=.orig
+++ linux-2.6-ext3/fs/ext2/super.c
@@ -518,12 +518,18 @@ static int ext2_check_descriptors (struc
static loff_t ext2_max_size(int bits)
{
loff_t res = EXT2_NDIR_BLOCKS;
+ /* This constant is calculated to be the largest file size for a
+ * dense, 4k-blocksize file such that the total number of
+ * sectors in the file, including data and all indirect blocks,
+ * does not exceed 2^32. */
+ const loff_t upper_limit = 0x1ff7fffd000LL;
+
res += 1LL << (bits-2);
res += 1LL << (2*(bits-2));
res += 1LL << (3*(bits-2));
res <<= bits;
- if (res > (512LL << 32) - (1 << bits))
- res = (512LL << 32) - (1 << bits);
+ if (res > upper_limit)
+ res = upper_limit;
return res;
}

--- linux-2.6-ext3/fs/ext3/super.c.=K0001=.orig
+++ linux-2.6-ext3/fs/ext3/super.c
@@ -1193,12 +1193,18 @@ static void ext3_orphan_cleanup (struct
static loff_t ext3_max_size(int bits)
{
loff_t res = EXT3_NDIR_BLOCKS;
+ /* This constant is calculated to be the largest file size for a
+ * dense, 4k-blocksize file such that the total number of
+ * sectors in the file, including data and all indirect blocks,
+ * does not exceed 2^32. */
+ const loff_t upper_limit = 0x1ff7fffd000LL;
+
res += 1LL << (bits-2);
res += 1LL << (2*(bits-2));
res += 1LL << (3*(bits-2));
res <<= bits;
- if (res > (512LL << 32) - (1 << bits))
- res = (512LL << 32) - (1 << bits);
+ if (res > upper_limit)
+ res = upper_limit;
return res;
}


Attachments:
ext3-file-limit.patch (2.22 kB)

2005-03-17 17:40:19

by Stephen C. Tweedie

[permalink] [raw]
Subject: e2fsprogs bug [was Re: ext2/3 file limits to avoid overflowing i_blocks]

Hi,

On Thu, 2005-03-17 at 17:23, Stephen C. Tweedie wrote:

> I wrote a small program to calculate the total indirect tree overhead
> for any given file size, and 0x1ff7fffe000 turned out to be the largest
> file we can get without the total i_blocks overflowing 2^32.
>
> But in testing, that *just* wrapped --- we need to limit the file to be
> one page smaller than that to deal with the possibility of an EA/ACL
> block being accounted against i_blocks.

On a side, issue, e2fsck was unable to find any problem on that
filesystem after the i_blocks had wrapped exactly to zero.

The bug seems to be in e2fsck/pass1.c: we do the numblocks checking
inside process_block(), which is called as an inode block iteration
function in check_blocks(). Then, later, check_blocks() does

if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
pb.num_blocks++;

pb.num_blocks *= (fs->blocksize / 512);

but without any further testing to see if pb.num_blocks has exceeded the
max_blocks. So by the time we've got to the end of check_blocks(),
we're testing the wrapped i_blocks on disk against the wrapped
num_blocks in memory, and so e2fsck fails to notice anything wrong.

The fix may be as simple as just moving the

if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
pb.num_blocks++;

earlier in the function; Ted, do you see any problems with that?

--Stephen