Messages in this thread Patch in this message | | | Subject | [Patch] ext2/3 file limits to avoid overflowing i_blocks | From | "Stephen C. Tweedie" <> | Date | Thu, 17 Mar 2005 17:23:41 +0000 |
| |
Hi all,
As discussed before, we can overflow i_blocks in ext2/ext3 inodes by growing a file up to 2TB. That gives us 2^32 sectors of data in the file; but once you add on the indirect tree and possible EA/ACL metadata, i_blocks will wrap beyond 2^32. Consensus seemed to be that the best way to avoid this was simply to stop files getting so large that this was a problem in the first place; anything else would lead to complications if a sparse file tried to overflow that 2^32 sector limit while filling in holes.
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.
So this patch has been tested, at least on ext3, by letting a file grow densely to its maximum size permitted by the kernel; at 0x1ff7fffe000, stat shows the file to have wrapped back exactly to 0 st_blocks, but with the limit at 0x1ff7fffd000, du shows it occupying the expected 2TB-blocksize bytes.
Cheers, Stephen
[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 <sct@redhat.com>
--- 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; } | |