Add stable boundary to the series file
[ext4-patch-queue.git] / uninitialized-block-groups.patch
blobb7790da952243c5472c5811f777aa32efea1ba2f
1 Ext4: Uninitialized Block Groups
3 From: Andreas Dilger <adilger@clusterfs.com>
5 In pass1 of e2fsck, every inode table in the fileystem is scanned and checked,
6 regardless of whether it is in use. This is this the most time consuming part
7 of the filesystem check. The unintialized block group feature can greatly
8 reduce e2fsck time by eliminating checking of uninitialized inodes.
10 With this feature, there is a a high water mark of used inodes for each block
11 group. Block and inode bitmaps can be uninitialized on disk via a flag in the
12 group descriptor to avoid reading or scanning them at e2fsck time. A checksum
13 of each group descriptor is used to ensure that corruption in the group
14 descriptor's bit flags does not cause incorrect operation.
16 The feature is enabled through a mkfs option
18 mke2fs /dev/ -O uninit_groups
20 A patch adding support for uninitialized block groups to e2fsprogs tools has
21 been posted to the linux-ext4 mailing list.
23 The patches have been stress tested with fsstress and fsx. In performance
24 tests testing e2fsck time, we have seen that e2fsck time on ext3 grows
25 linearly with the total number of inodes in the filesytem. In ext4 with the
26 uninitialized block groups feature, the e2fsck time is constant, based
27 solely on the number of used inodes rather than the total inode count.
28 Since typical ext4 filesystems only use 1-10% of their inodes, this feature can
29 greatly reduce e2fsck time for users. With performance improvement of 2-20
30 times, depending on how full the filesystem is.
32 The attached graph shows the major improvements in e2fsck times in filesystems
33 with a large total inode count, but few inodes in use.
35 In each group descriptor if we have
37 EXT4_BG_INODE_UNINIT set in bg_flags:
38 Inode table is not initialized/used in this group. So we can skip
39 the consistency check during fsck.
40 EXT4_BG_BLOCK_UNINIT set in bg_flags:
41 No block in the group is used. So we can skip the block bitmap
42 verification for this group.
44 We also add two new fields to group descriptor as a part of
45 uninitialized group patch.
47 __le16 bg_itable_unused; /* Unused inodes count */
48 __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */
51 bg_itable_unused:
53 If we have EXT4_BG_INODE_UNINIT not set in bg_flags
54 then bg_itable_unused will give the offset within
55 the inode table till the inodes are used. This can be
56 used by fsck to skip list of inodes that are marked unused.
59 bg_checksum:
60 Now that we depend on bg_flags and bg_itable_unused to determine
61 the block and inode usage, we need to make sure group descriptor
62 is not corrupt. We add checksum to group descriptor to
63 detect corruption. If the descriptor is found to be corrupt, we
64 mark all the blocks and inodes in the group used.
67 Signed-off-by: Avantika Mathur <mathur@us.ibm.com>
68 Signed-off-by: Andreas Dilger <adilger@clusterfs.com>
69 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
70 Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
71 ---
73 fs/Kconfig | 1
74 fs/ext4/balloc.c | 112 +++++++++++++++++++++++++++++++++++-
75 fs/ext4/group.h | 27 ++++++++
76 fs/ext4/ialloc.c | 146 +++++++++++++++++++++++++++++++++++++++++++++---
77 fs/ext4/resize.c | 21 ------
78 fs/ext4/super.c | 47 +++++++++++++++
79 include/linux/ext4_fs.h | 16 +++--
80 7 files changed, 335 insertions(+), 35 deletions(-)
81 create mode 100644 fs/ext4/group.h
84 Index: linux-2.6.23-rc9/fs/Kconfig
85 ===================================================================
86 --- linux-2.6.23-rc9.orig/fs/Kconfig 2007-10-05 10:20:04.000000000 -0700
87 +++ linux-2.6.23-rc9/fs/Kconfig 2007-10-05 10:20:20.000000000 -0700
88 @@ -140,6 +140,7 @@ config EXT4DEV_FS
89 tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)"
90 depends on EXPERIMENTAL
91 select JBD2
92 + select CRC16
93 help
94 Ext4dev is a predecessor filesystem of the next generation
95 extended fs ext4, based on ext3 filesystem code. It will be
96 Index: linux-2.6.23-rc9/fs/ext4/balloc.c
97 ===================================================================
98 --- linux-2.6.23-rc9.orig/fs/ext4/balloc.c 2007-10-05 10:20:04.000000000 -0700
99 +++ linux-2.6.23-rc9/fs/ext4/balloc.c 2007-10-05 10:21:22.000000000 -0700
100 @@ -20,6 +20,7 @@
101 #include <linux/quotaops.h>
102 #include <linux/buffer_head.h>
104 +#include "group.h"
106 * balloc.c contains the blocks allocation and deallocation routines
108 @@ -42,6 +43,94 @@ void ext4_get_group_no_and_offset(struct
112 +/* Initializes an uninitialized block bitmap if given, and returns the
113 + * number of blocks free in the group. */
114 +unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
115 + int block_group, struct ext4_group_desc *gdp)
117 + unsigned long start;
118 + int bit, bit_max;
119 + unsigned free_blocks, group_blocks;
120 + struct ext4_sb_info *sbi = EXT4_SB(sb);
122 + if (bh) {
123 + J_ASSERT_BH(bh, buffer_locked(bh));
125 + /* If checksum is bad mark all blocks used to prevent allocation
126 + * essentially implementing a per-group read-only flag. */
127 + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
128 + ext4_error(sb, __FUNCTION__,
129 + "Checksum bad for group %u\n", block_group);
130 + gdp->bg_free_blocks_count = 0;
131 + gdp->bg_free_inodes_count = 0;
132 + gdp->bg_itable_unused = 0;
133 + memset(bh->b_data, 0xff, sb->s_blocksize);
134 + return 0;
136 + memset(bh->b_data, 0, sb->s_blocksize);
139 + /* Check for superblock and gdt backups in this group */
140 + bit_max = ext4_bg_has_super(sb, block_group);
142 + if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
143 + block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
144 + sbi->s_desc_per_block) {
145 + if (bit_max) {
146 + bit_max += ext4_bg_num_gdb(sb, block_group);
147 + bit_max +=
148 + le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
150 + } else { /* For META_BG_BLOCK_GROUPS */
151 + int group_rel = (block_group -
152 + le32_to_cpu(sbi->s_es->s_first_meta_bg)) %
153 + EXT4_DESC_PER_BLOCK(sb);
154 + if (group_rel == 0 || group_rel == 1 ||
155 + (group_rel == EXT4_DESC_PER_BLOCK(sb) - 1))
156 + bit_max += 1;
159 + if (block_group == sbi->s_groups_count - 1) {
160 + /*
161 + * Even though mke2fs always initialize first and last group
162 + * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
163 + * to make sure we calculate the right free blocks
164 + */
165 + group_blocks = ext4_blocks_count(sbi->s_es) -
166 + le32_to_cpu(sbi->s_es->s_first_data_block) -
167 + (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count -1));
168 + } else {
169 + group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
172 + free_blocks = group_blocks - bit_max;
174 + if (bh) {
175 + for (bit = 0; bit < bit_max; bit++)
176 + ext4_set_bit(bit, bh->b_data);
178 + start = block_group * EXT4_BLOCKS_PER_GROUP(sb) +
179 + le32_to_cpu(sbi->s_es->s_first_data_block);
181 + /* Set bits for block and inode bitmaps, and inode table */
182 + ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data);
183 + ext4_set_bit(ext4_inode_bitmap(sb, gdp) - start, bh->b_data);
184 + for (bit = le32_to_cpu(gdp->bg_inode_table) - start,
185 + bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++)
186 + ext4_set_bit(bit, bh->b_data);
188 + /*
189 + * Also if the number of blocks within the group is
190 + * less than the blocksize * 8 ( which is the size
191 + * of bitmap ), set rest of the block bitmap to 1
192 + */
193 + mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
196 + return free_blocks - sbi->s_itb_per_group - 2;
201 * The free blocks are managed by bitmaps. A file system contains several
202 * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
203 @@ -110,16 +199,29 @@ struct ext4_group_desc * ext4_get_group_
205 * Return buffer_head on success or NULL in case of failure.
207 -static struct buffer_head *
208 +struct buffer_head *
209 read_block_bitmap(struct super_block *sb, unsigned int block_group)
211 struct ext4_group_desc * desc;
212 struct buffer_head * bh = NULL;
214 - desc = ext4_get_group_desc (sb, block_group, NULL);
215 + desc = ext4_get_group_desc(sb, block_group, NULL);
216 if (!desc)
217 goto error_out;
218 - bh = sb_bread(sb, ext4_block_bitmap(sb, desc));
219 + if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
220 + bh = sb_getblk(sb, ext4_block_bitmap(sb, desc));
221 + if (!buffer_uptodate(bh)) {
222 + lock_buffer(bh);
223 + if (!buffer_uptodate(bh)) {
224 + ext4_init_block_bitmap(sb, bh, block_group,
225 + desc);
226 + set_buffer_uptodate(bh);
228 + unlock_buffer(bh);
230 + } else {
231 + bh = sb_bread(sb, ext4_block_bitmap(sb, desc));
233 if (!bh)
234 ext4_error (sb, "read_block_bitmap",
235 "Cannot read block bitmap - "
236 @@ -586,6 +688,7 @@ do_more:
237 desc->bg_free_blocks_count =
238 cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
239 group_freed);
240 + desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
241 spin_unlock(sb_bgl_lock(sbi, block_group));
242 percpu_counter_mod(&sbi->s_freeblocks_counter, count);
244 @@ -1644,8 +1747,11 @@ allocated:
245 ret_block, goal_hits, goal_attempts);
247 spin_lock(sb_bgl_lock(sbi, group_no));
248 + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
249 + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
250 gdp->bg_free_blocks_count =
251 cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
252 + gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp);
253 spin_unlock(sb_bgl_lock(sbi, group_no));
254 percpu_counter_mod(&sbi->s_freeblocks_counter, -num);
256 Index: linux-2.6.23-rc9/fs/ext4/group.h
257 ===================================================================
258 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
259 +++ linux-2.6.23-rc9/fs/ext4/group.h 2007-10-05 10:20:20.000000000 -0700
260 @@ -0,0 +1,27 @@
262 + * linux/fs/ext4/group.h
264 + * Copyright (C) 2007 Cluster File Systems, Inc
266 + * Author: Andreas Dilger <adilger@clusterfs.com>
267 + */
269 +#ifndef _LINUX_EXT4_GROUP_H
270 +#define _LINUX_EXT4_GROUP_H
272 +extern __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 group,
273 + struct ext4_group_desc *gdp);
274 +extern int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 group,
275 + struct ext4_group_desc *gdp);
276 +struct buffer_head *read_block_bitmap(struct super_block *sb,
277 + unsigned int block_group);
278 +extern unsigned ext4_init_block_bitmap(struct super_block *sb,
279 + struct buffer_head *bh, int group,
280 + struct ext4_group_desc *desc);
281 +#define ext4_free_blocks_after_init(sb, group, desc) \
282 + ext4_init_block_bitmap(sb, NULL, group, desc)
283 +extern unsigned ext4_init_inode_bitmap(struct super_block *sb,
284 + struct buffer_head *bh, int group,
285 + struct ext4_group_desc *desc);
286 +extern void mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
287 +#endif /* _LINUX_EXT4_GROUP_H */
288 Index: linux-2.6.23-rc9/fs/ext4/ialloc.c
289 ===================================================================
290 --- linux-2.6.23-rc9.orig/fs/ext4/ialloc.c 2007-10-05 10:20:04.000000000 -0700
291 +++ linux-2.6.23-rc9/fs/ext4/ialloc.c 2007-10-05 10:20:20.000000000 -0700
292 @@ -28,6 +28,7 @@
294 #include "xattr.h"
295 #include "acl.h"
296 +#include "group.h"
299 * ialloc.c contains the inodes allocation and deallocation routines
300 @@ -43,6 +44,52 @@
301 * the free blocks count in the block.
305 + * To avoid calling the atomic setbit hundreds or thousands of times, we only
306 + * need to use it within a single byte (to ensure we get endianness right).
307 + * We can use memset for the rest of the bitmap as there are no other users.
308 + */
309 +void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
311 + int i;
313 + if (start_bit >= end_bit)
314 + return;
316 + ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
317 + for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
318 + ext4_set_bit(i, bitmap);
319 + if (i < end_bit)
320 + memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
323 +/* Initializes an uninitialized inode bitmap */
324 +unsigned ext4_init_inode_bitmap(struct super_block *sb,
325 + struct buffer_head *bh, int block_group,
326 + struct ext4_group_desc *gdp)
328 + struct ext4_sb_info *sbi = EXT4_SB(sb);
330 + J_ASSERT_BH(bh, buffer_locked(bh));
332 + /* If checksum is bad mark all blocks and inodes use to prevent
333 + * allocation, essentially implementing a per-group read-only flag. */
334 + if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
335 + ext4_error(sb, __FUNCTION__, "Checksum bad for group %u\n",
336 + block_group);
337 + gdp->bg_free_blocks_count = 0;
338 + gdp->bg_free_inodes_count = 0;
339 + gdp->bg_itable_unused = 0;
340 + memset(bh->b_data, 0xff, sb->s_blocksize);
341 + return 0;
344 + memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
345 + mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb),
346 + bh->b_data);
348 + return EXT4_INODES_PER_GROUP(sb);
352 * Read the inode allocation bitmap for a given block_group, reading
353 @@ -59,8 +106,20 @@ read_inode_bitmap(struct super_block * s
354 desc = ext4_get_group_desc(sb, block_group, NULL);
355 if (!desc)
356 goto error_out;
358 - bh = sb_bread(sb, ext4_inode_bitmap(sb, desc));
359 + if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
360 + bh = sb_getblk(sb, ext4_inode_bitmap(sb, desc));
361 + if (!buffer_uptodate(bh)) {
362 + lock_buffer(bh);
363 + if (!buffer_uptodate(bh)) {
364 + ext4_init_inode_bitmap(sb, bh, block_group,
365 + desc);
366 + set_buffer_uptodate(bh);
368 + unlock_buffer(bh);
370 + } else {
371 + bh = sb_bread(sb, ext4_inode_bitmap(sb, desc));
373 if (!bh)
374 ext4_error(sb, "read_inode_bitmap",
375 "Cannot read inode bitmap - "
376 @@ -169,6 +228,8 @@ void ext4_free_inode (handle_t *handle,
377 if (is_directory)
378 gdp->bg_used_dirs_count = cpu_to_le16(
379 le16_to_cpu(gdp->bg_used_dirs_count) - 1);
380 + gdp->bg_checksum = ext4_group_desc_csum(sbi,
381 + block_group, gdp);
382 spin_unlock(sb_bgl_lock(sbi, block_group));
383 percpu_counter_inc(&sbi->s_freeinodes_counter);
384 if (is_directory)
385 @@ -438,7 +499,7 @@ struct inode *ext4_new_inode(handle_t *h
386 struct ext4_sb_info *sbi;
387 int err = 0;
388 struct inode *ret;
389 - int i;
390 + int i, free = 0;
392 /* Cannot create files in a deleted directory */
393 if (!dir || !dir->i_nlink)
394 @@ -520,11 +581,13 @@ repeat_in_this_group:
395 goto out;
397 got:
398 - ino += group * EXT4_INODES_PER_GROUP(sb) + 1;
399 - if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
400 - ext4_error (sb, "ext4_new_inode",
401 - "reserved inode or inode > inodes count - "
402 - "block_group = %d, inode=%lu", group, ino);
403 + ino++;
404 + if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
405 + ino > EXT4_INODES_PER_GROUP(sb)) {
406 + ext4_error(sb, __FUNCTION__,
407 + "reserved inode or inode > inodes count - "
408 + "block_group = %d, inode=%lu", group,
409 + ino + group * EXT4_INODES_PER_GROUP(sb));
410 err = -EIO;
411 goto fail;
413 @@ -532,13 +595,78 @@ got:
414 BUFFER_TRACE(bh2, "get_write_access");
415 err = ext4_journal_get_write_access(handle, bh2);
416 if (err) goto fail;
418 + /* We may have to initialize the block bitmap if it isn't already */
419 + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
420 + gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
421 + struct buffer_head *block_bh = read_block_bitmap(sb, group);
423 + BUFFER_TRACE(block_bh, "get block bitmap access");
424 + err = ext4_journal_get_write_access(handle, block_bh);
425 + if (err) {
426 + brelse(block_bh);
427 + goto fail;
430 + free = 0;
431 + spin_lock(sb_bgl_lock(sbi, group));
432 + /* recheck and clear flag under lock if we still need to */
433 + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
434 + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
435 + free = ext4_free_blocks_after_init(sb, group, gdp);
436 + gdp->bg_free_blocks_count = cpu_to_le16(free);
438 + spin_unlock(sb_bgl_lock(sbi, group));
440 + /* Don't need to dirty bitmap block if we didn't change it */
441 + if (free) {
442 + BUFFER_TRACE(block_bh, "dirty block bitmap");
443 + err = ext4_journal_dirty_metadata(handle, block_bh);
446 + brelse(block_bh);
447 + if (err)
448 + goto fail;
451 spin_lock(sb_bgl_lock(sbi, group));
452 + /* If we didn't allocate from within the initialized part of the inode
453 + * table then we need to initialize up to this inode. */
454 + if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
455 + if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
456 + gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
458 + /* When marking the block group with
459 + * ~EXT4_BG_INODE_UNINIT we don't want to depend
460 + * on the value of bg_itable_unsed even though
461 + * mke2fs could have initialized the same for us.
462 + * Instead we calculated the value below
463 + */
465 + free = 0;
466 + } else {
467 + free = EXT4_INODES_PER_GROUP(sb) -
468 + le16_to_cpu(gdp->bg_itable_unused);
471 + /*
472 + * Check the relative inode number against the last used
473 + * relative inode number in this group. if it is greater
474 + * we need to update the bg_itable_unused count
476 + */
477 + if (ino > free)
478 + gdp->bg_itable_unused =
479 + cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino);
482 gdp->bg_free_inodes_count =
483 cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
484 if (S_ISDIR(mode)) {
485 gdp->bg_used_dirs_count =
486 cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
488 + gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
489 spin_unlock(sb_bgl_lock(sbi, group));
490 BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata");
491 err = ext4_journal_dirty_metadata(handle, bh2);
492 @@ -560,7 +688,7 @@ got:
493 inode->i_gid = current->fsgid;
494 inode->i_mode = mode;
496 - inode->i_ino = ino;
497 + inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb);
498 /* This is the optimal IO size (for stat), not the fs block size */
499 inode->i_blocks = 0;
500 inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime =
501 Index: linux-2.6.23-rc9/fs/ext4/resize.c
502 ===================================================================
503 --- linux-2.6.23-rc9.orig/fs/ext4/resize.c 2007-10-05 10:20:04.000000000 -0700
504 +++ linux-2.6.23-rc9/fs/ext4/resize.c 2007-10-05 10:20:20.000000000 -0700
505 @@ -16,6 +16,7 @@
506 #include <linux/errno.h>
507 #include <linux/slab.h>
509 +#include "group.h"
511 #define outside(b, first, last) ((b) < (first) || (b) >= (last))
512 #define inside(b, first, last) ((b) >= (first) && (b) < (last))
513 @@ -140,25 +141,6 @@ static struct buffer_head *bclean(handle
517 - * To avoid calling the atomic setbit hundreds or thousands of times, we only
518 - * need to use it within a single byte (to ensure we get endianness right).
519 - * We can use memset for the rest of the bitmap as there are no other users.
520 - */
521 -static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
523 - int i;
525 - if (start_bit >= end_bit)
526 - return;
528 - ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
529 - for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
530 - ext4_set_bit(i, bitmap);
531 - if (i < end_bit)
532 - memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
536 * Set up the block and inode bitmaps, and the inode table for the new group.
537 * This doesn't need to be part of the main transaction, since we are only
538 * changing blocks outside the actual filesystem. We still do journaling to
539 @@ -842,6 +824,7 @@ int ext4_group_add(struct super_block *s
540 ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */
541 gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
542 gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb));
543 + gdp->bg_checksum = ext4_group_desc_csum(sbi, input->group, gdp);
546 * Make the new blocks and inodes valid next. We do this before
547 Index: linux-2.6.23-rc9/fs/ext4/super.c
548 ===================================================================
549 --- linux-2.6.23-rc9.orig/fs/ext4/super.c 2007-10-05 10:20:04.000000000 -0700
550 +++ linux-2.6.23-rc9/fs/ext4/super.c 2007-10-05 10:20:20.000000000 -0700
551 @@ -37,12 +37,14 @@
552 #include <linux/quotaops.h>
553 #include <linux/seq_file.h>
554 #include <linux/log2.h>
555 +#include <linux/crc16.h>
557 #include <asm/uaccess.h>
559 #include "xattr.h"
560 #include "acl.h"
561 #include "namei.h"
562 +#include "group.h"
564 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
565 unsigned long journal_devnum);
566 @@ -1237,6 +1239,43 @@ static int ext4_setup_super(struct super
567 return res;
570 +__le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
571 + struct ext4_group_desc *gdp)
573 + __u16 crc = 0;
575 + if (sbi->s_es->s_feature_ro_compat &
576 + cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
577 + int offset = offsetof(struct ext4_group_desc, bg_checksum);
578 + __le32 le_group = cpu_to_le32(block_group);
580 + crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
581 + crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
582 + crc = crc16(crc, (__u8 *)gdp, offset);
583 + offset += sizeof(gdp->bg_checksum); /* skip checksum */
584 + /* for checksum of struct ext4_group_desc do the rest...*/
585 + if ((sbi->s_es->s_feature_incompat &
586 + cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
587 + offset < le16_to_cpu(sbi->s_es->s_desc_size))
588 + crc = crc16(crc, (__u8 *)gdp + offset,
589 + le16_to_cpu(sbi->s_es->s_desc_size) -
590 + offset);
593 + return cpu_to_le16(crc);
596 +int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
597 + struct ext4_group_desc *gdp)
599 + if ((sbi->s_es->s_feature_ro_compat &
600 + cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
601 + (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
602 + return 0;
604 + return 1;
607 /* Called at mount-time, super-block is locked */
608 static int ext4_check_descriptors (struct super_block * sb)
610 @@ -1291,6 +1330,14 @@ static int ext4_check_descriptors (struc
611 i, inode_table);
612 return 0;
614 + if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
615 + ext4_error(sb, __FUNCTION__,
616 + "Checksum for group %d failed (%u!=%u)\n", i,
617 + le16_to_cpu(ext4_group_desc_csum(sbi, i,
618 + gdp)),
619 + le16_to_cpu(gdp->bg_checksum));
620 + return 0;
622 first_block += EXT4_BLOCKS_PER_GROUP(sb);
623 gdp = (struct ext4_group_desc *)
624 ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
625 Index: linux-2.6.23-rc9/include/linux/ext4_fs.h
626 ===================================================================
627 --- linux-2.6.23-rc9.orig/include/linux/ext4_fs.h 2007-10-05 10:20:04.000000000 -0700
628 +++ linux-2.6.23-rc9/include/linux/ext4_fs.h 2007-10-05 10:20:20.000000000 -0700
629 @@ -105,19 +105,25 @@
631 struct ext4_group_desc
633 - __le32 bg_block_bitmap; /* Blocks bitmap block */
634 - __le32 bg_inode_bitmap; /* Inodes bitmap block */
635 + __le32 bg_block_bitmap; /* Blocks bitmap block */
636 + __le32 bg_inode_bitmap; /* Inodes bitmap block */
637 __le32 bg_inode_table; /* Inodes table block */
638 __le16 bg_free_blocks_count; /* Free blocks count */
639 __le16 bg_free_inodes_count; /* Free inodes count */
640 __le16 bg_used_dirs_count; /* Directories count */
641 - __u16 bg_flags;
642 - __u32 bg_reserved[3];
643 + __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */
644 + __u32 bg_reserved[2]; /* Likely block/inode bitmap checksum */
645 + __le16 bg_itable_unused; /* Unused inodes count */
646 + __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */
647 __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
648 __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
649 __le32 bg_inode_table_hi; /* Inodes table block MSB */
652 +#define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */
653 +#define EXT4_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */
654 +#define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
656 #ifdef __KERNEL__
657 #include <linux/ext4_fs_i.h>
658 #include <linux/ext4_fs_sb.h>
659 @@ -665,6 +671,7 @@ static inline int ext4_valid_inum(struct
660 #define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
661 #define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
662 #define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
663 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
664 #define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
665 #define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
667 @@ -684,6 +691,7 @@ static inline int ext4_valid_inum(struct
668 EXT4_FEATURE_INCOMPAT_64BIT)
669 #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
670 EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
671 + EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
672 EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
673 EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
674 EXT4_FEATURE_RO_COMPAT_BTREE_DIR)