diff options
author | Amit Arora <aarora@in.ibm.com> | 2007-07-18 09:02:56 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2007-07-18 09:02:56 -0400 |
commit | 749269facaf87f6e516c3af12763e03181b9c139 (patch) | |
tree | 5c8a2091d4b1ce7636de404a1366bd174b4634fd | |
parent | 56055d3ae4cc7fa6d2b10885f20269de8a989ed7 (diff) |
Change on-disk format to support 2^15 uninitialized extents
This change was suggested by Andreas Dilger.
This patch changes the EXT_MAX_LEN value and extent code which marks/checks
uninitialized extents. With this change it will be possible to have
initialized extents with 2^15 blocks (earlier the max blocks we could have
was 2^15 - 1). This way we can have better extent-to-block alignment.
Now, maximum number of blocks we can have in an initialized extent is 2^15
and in an uninitialized extent is 2^15 - 1.
Signed-off-by: Amit Arora <aarora@in.ibm.com>
-rw-r--r-- | fs/ext4/extents.c | 28 | ||||
-rw-r--r-- | include/linux/ext4_fs_extents.h | 31 |
2 files changed, 52 insertions, 7 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index ded3d469f978..77146b826a13 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -1107,7 +1107,7 @@ static int | |||
1107 | ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | 1107 | ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, |
1108 | struct ext4_extent *ex2) | 1108 | struct ext4_extent *ex2) |
1109 | { | 1109 | { |
1110 | unsigned short ext1_ee_len, ext2_ee_len; | 1110 | unsigned short ext1_ee_len, ext2_ee_len, max_len; |
1111 | 1111 | ||
1112 | /* | 1112 | /* |
1113 | * Make sure that either both extents are uninitialized, or | 1113 | * Make sure that either both extents are uninitialized, or |
@@ -1116,6 +1116,11 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | |||
1116 | if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2)) | 1116 | if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2)) |
1117 | return 0; | 1117 | return 0; |
1118 | 1118 | ||
1119 | if (ext4_ext_is_uninitialized(ex1)) | ||
1120 | max_len = EXT_UNINIT_MAX_LEN; | ||
1121 | else | ||
1122 | max_len = EXT_INIT_MAX_LEN; | ||
1123 | |||
1119 | ext1_ee_len = ext4_ext_get_actual_len(ex1); | 1124 | ext1_ee_len = ext4_ext_get_actual_len(ex1); |
1120 | ext2_ee_len = ext4_ext_get_actual_len(ex2); | 1125 | ext2_ee_len = ext4_ext_get_actual_len(ex2); |
1121 | 1126 | ||
@@ -1128,7 +1133,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, | |||
1128 | * as an RO_COMPAT feature, refuse to merge to extents if | 1133 | * as an RO_COMPAT feature, refuse to merge to extents if |
1129 | * this can result in the top bit of ee_len being set. | 1134 | * this can result in the top bit of ee_len being set. |
1130 | */ | 1135 | */ |
1131 | if (ext1_ee_len + ext2_ee_len > EXT_MAX_LEN) | 1136 | if (ext1_ee_len + ext2_ee_len > max_len) |
1132 | return 0; | 1137 | return 0; |
1133 | #ifdef AGGRESSIVE_TEST | 1138 | #ifdef AGGRESSIVE_TEST |
1134 | if (le16_to_cpu(ex1->ee_len) >= 4) | 1139 | if (le16_to_cpu(ex1->ee_len) >= 4) |
@@ -1815,7 +1820,11 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, | |||
1815 | 1820 | ||
1816 | ex->ee_block = cpu_to_le32(block); | 1821 | ex->ee_block = cpu_to_le32(block); |
1817 | ex->ee_len = cpu_to_le16(num); | 1822 | ex->ee_len = cpu_to_le16(num); |
1818 | if (uninitialized) | 1823 | /* |
1824 | * Do not mark uninitialized if all the blocks in the | ||
1825 | * extent have been removed. | ||
1826 | */ | ||
1827 | if (uninitialized && num) | ||
1819 | ext4_ext_mark_uninitialized(ex); | 1828 | ext4_ext_mark_uninitialized(ex); |
1820 | 1829 | ||
1821 | err = ext4_ext_dirty(handle, inode, path + depth); | 1830 | err = ext4_ext_dirty(handle, inode, path + depth); |
@@ -2308,6 +2317,19 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode, | |||
2308 | /* allocate new block */ | 2317 | /* allocate new block */ |
2309 | goal = ext4_ext_find_goal(inode, path, iblock); | 2318 | goal = ext4_ext_find_goal(inode, path, iblock); |
2310 | 2319 | ||
2320 | /* | ||
2321 | * See if request is beyond maximum number of blocks we can have in | ||
2322 | * a single extent. For an initialized extent this limit is | ||
2323 | * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is | ||
2324 | * EXT_UNINIT_MAX_LEN. | ||
2325 | */ | ||
2326 | if (max_blocks > EXT_INIT_MAX_LEN && | ||
2327 | create != EXT4_CREATE_UNINITIALIZED_EXT) | ||
2328 | max_blocks = EXT_INIT_MAX_LEN; | ||
2329 | else if (max_blocks > EXT_UNINIT_MAX_LEN && | ||
2330 | create == EXT4_CREATE_UNINITIALIZED_EXT) | ||
2331 | max_blocks = EXT_UNINIT_MAX_LEN; | ||
2332 | |||
2311 | /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */ | 2333 | /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */ |
2312 | newex.ee_block = cpu_to_le32(iblock); | 2334 | newex.ee_block = cpu_to_le32(iblock); |
2313 | newex.ee_len = cpu_to_le16(max_blocks); | 2335 | newex.ee_len = cpu_to_le16(max_blocks); |
diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h index edf49ec89eac..81406f3655d4 100644 --- a/include/linux/ext4_fs_extents.h +++ b/include/linux/ext4_fs_extents.h | |||
@@ -141,7 +141,25 @@ typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *, | |||
141 | 141 | ||
142 | #define EXT_MAX_BLOCK 0xffffffff | 142 | #define EXT_MAX_BLOCK 0xffffffff |
143 | 143 | ||
144 | #define EXT_MAX_LEN ((1UL << 15) - 1) | 144 | /* |
145 | * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an | ||
146 | * initialized extent. This is 2^15 and not (2^16 - 1), since we use the | ||
147 | * MSB of ee_len field in the extent datastructure to signify if this | ||
148 | * particular extent is an initialized extent or an uninitialized (i.e. | ||
149 | * preallocated). | ||
150 | * EXT_UNINIT_MAX_LEN is the maximum number of blocks we can have in an | ||
151 | * uninitialized extent. | ||
152 | * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an | ||
153 | * uninitialized one. In other words, if MSB of ee_len is set, it is an | ||
154 | * uninitialized extent with only one special scenario when ee_len = 0x8000. | ||
155 | * In this case we can not have an uninitialized extent of zero length and | ||
156 | * thus we make it as a special case of initialized extent with 0x8000 length. | ||
157 | * This way we get better extent-to-group alignment for initialized extents. | ||
158 | * Hence, the maximum number of blocks we can have in an *initialized* | ||
159 | * extent is 2^15 (32768) and in an *uninitialized* extent is 2^15-1 (32767). | ||
160 | */ | ||
161 | #define EXT_INIT_MAX_LEN (1UL << 15) | ||
162 | #define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1) | ||
145 | 163 | ||
146 | 164 | ||
147 | #define EXT_FIRST_EXTENT(__hdr__) \ | 165 | #define EXT_FIRST_EXTENT(__hdr__) \ |
@@ -190,17 +208,22 @@ ext4_ext_invalidate_cache(struct inode *inode) | |||
190 | 208 | ||
191 | static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext) | 209 | static inline void ext4_ext_mark_uninitialized(struct ext4_extent *ext) |
192 | { | 210 | { |
193 | ext->ee_len |= cpu_to_le16(0x8000); | 211 | /* We can not have an uninitialized extent of zero length! */ |
212 | BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0); | ||
213 | ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN); | ||
194 | } | 214 | } |
195 | 215 | ||
196 | static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext) | 216 | static inline int ext4_ext_is_uninitialized(struct ext4_extent *ext) |
197 | { | 217 | { |
198 | return (int)(le16_to_cpu((ext)->ee_len) & 0x8000); | 218 | /* Extent with ee_len of 0x8000 is treated as an initialized extent */ |
219 | return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN); | ||
199 | } | 220 | } |
200 | 221 | ||
201 | static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) | 222 | static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) |
202 | { | 223 | { |
203 | return (int)(le16_to_cpu((ext)->ee_len) & 0x7FFF); | 224 | return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ? |
225 | le16_to_cpu(ext->ee_len) : | ||
226 | (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN)); | ||
204 | } | 227 | } |
205 | 228 | ||
206 | extern int ext4_extent_tree_init(handle_t *, struct inode *); | 229 | extern int ext4_extent_tree_init(handle_t *, struct inode *); |