diff options
author | Lukas Czerner <lczerner@redhat.com> | 2011-06-06 00:05:17 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2011-06-06 00:05:17 -0400 |
commit | f17722f917b2f21497deb6edc62fb1683daa08e6 (patch) | |
tree | 10509e066829e685b25d74239f490345d28603d2 /fs/ext4/ext4_extents.h | |
parent | 5def1360252b974faeb438775c19c14338bc1903 (diff) |
ext4: Fix max file size and logical block counting of extent format file
Kazuya Mio reported that he was able to hit BUG_ON(next == lblock)
in ext4_ext_put_gap_in_cache() while creating a sparse file in extent
format and fill the tail of file up to its end. We will hit the BUG_ON
when we write the last block (2^32-1) into the sparse file.
The root cause of the problem lies in the fact that we specifically set
s_maxbytes so that block at s_maxbytes fit into on-disk extent format,
which is 32 bit long. However, we are not storing start and end block
number, but rather start block number and length in blocks. It means
that in order to cover extent from 0 to EXT_MAX_BLOCK we need
EXT_MAX_BLOCK+1 to fit into len (because we counting block 0 as well) -
and it does not.
The only way to fix it without changing the meaning of the struct
ext4_extent members is, as Kazuya Mio suggested, to lower s_maxbytes
by one fs block so we can cover the whole extent we can get by the
on-disk extent format.
Also in many places EXT_MAX_BLOCK is used as length instead of maximum
logical block number as the name suggests, it is all a bit messy. So
this commit renames it to EXT_MAX_BLOCKS and change its usage in some
places to actually be maximum number of blocks in the extent.
The bug which this commit fixes can be reproduced as follows:
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-2))
sync
dd if=/dev/zero of=/mnt/mp1/file bs=<blocksize> count=1 seek=$((2**32-1))
Reported-by: Kazuya Mio <k-mio@sx.jp.nec.com>
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/ext4_extents.h')
-rw-r--r-- | fs/ext4/ext4_extents.h | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/fs/ext4/ext4_extents.h b/fs/ext4/ext4_extents.h index 2e29abb30f76..476414644387 100644 --- a/fs/ext4/ext4_extents.h +++ b/fs/ext4/ext4_extents.h | |||
@@ -133,8 +133,11 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *, | |||
133 | #define EXT_BREAK 1 | 133 | #define EXT_BREAK 1 |
134 | #define EXT_REPEAT 2 | 134 | #define EXT_REPEAT 2 |
135 | 135 | ||
136 | /* Maximum logical block in a file; ext4_extent's ee_block is __le32 */ | 136 | /* |
137 | #define EXT_MAX_BLOCK 0xffffffff | 137 | * Maximum number of logical blocks in a file; ext4_extent's ee_block is |
138 | * __le32. | ||
139 | */ | ||
140 | #define EXT_MAX_BLOCKS 0xffffffff | ||
138 | 141 | ||
139 | /* | 142 | /* |
140 | * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an | 143 | * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an |