diff -ru -X linux-2.2.12/exclude.lst linux-2.2.12.orig/CREDITS linux-2.2.12/CREDITS --- linux-2.2.12.orig/CREDITS Fri Oct 15 00:05:25 1999 +++ linux-2.2.12/CREDITS Wed Oct 6 21:01:41 1999 @@ -457,6 +457,14 @@ S: Warrendale, Pennsylvania 15086 S: USA +N: Andreas Dilger +E: adilger@enel.ucalgary.ca +W: http://www-mddsp.enel.ucalgary.ca/People/adilger/ +D: Ext2 filesystem online resize capability +S: 630 Schooner Cove N.W. +S: Calgary, AB +S: Canada T3L 1Z1 + N: Alex deVries E: puffin@redhat.com D: Various SGI parts, bits of HAL2 and Newport diff -ru -X linux-2.2.12/exclude.lst linux-2.2.12.orig/fs/ext2/balloc.c linux-2.2.12/fs/ext2/balloc.c --- linux-2.2.12.orig/fs/ext2/balloc.c Fri Oct 15 00:02:03 1999 +++ linux-2.2.12/fs/ext2/balloc.c Wed Oct 6 21:00:40 1999 @@ -629,13 +629,13 @@ unsigned long ext2_count_free_blocks (struct super_block * sb) { -#ifdef EXT2FS_DEBUG struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; int bitmap_nr; struct ext2_group_desc * gdp; int i; + if (test_opt (sb, DEBUG) && test_opt (sb, CHECK_STRICT)) { lock_super (sb); es = sb->u.ext2_sb.s_es; desc_count = 0; @@ -656,13 +656,14 @@ i, le16_to_cpu(gdp->bg_free_blocks_count), x); bitmap_count += x; } - printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", - le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count); + printk ("ext2_count_free_blocks: stored = %u, computed gdt = %lu, " + "bitmap = %lu\n", le32_to_cpu(es->s_free_blocks_count), + desc_count, bitmap_count); unlock_super (sb); return bitmap_count; -#else + } + else return le32_to_cpu(sb->u.ext2_sb.s_es->s_free_blocks_count); -#endif } static inline int block_in_use (unsigned long block, diff -ru -X linux-2.2.12/exclude.lst linux-2.2.12.orig/fs/ext2/super.c linux-2.2.12/fs/ext2/super.c --- linux-2.2.12.orig/fs/ext2/super.c Fri Oct 15 00:02:04 1999 +++ linux-2.2.12/fs/ext2/super.c Wed Oct 6 21:00:40 1999 @@ -14,6 +14,7 @@ * * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 + * Online resize by Andreas Dilger (adilger@enel.ucalgary.ca), July 1999 */ #include @@ -37,6 +38,10 @@ static char error_buf[1024]; +#ifndef min +# define min(m,n) ((m) < (n) ? (m) : (n)) +#endif + void ext2_error (struct super_block * sb, const char * function, const char * fmt, ...) { @@ -146,7 +151,9 @@ */ static int parse_options (char * options, unsigned long * sb_block, unsigned short *resuid, unsigned short * resgid, - unsigned long * mount_options) + unsigned long * mount_options, + unsigned long * n_blocks_count, + unsigned long * resgdt) { char * this_char; char * value; @@ -220,6 +227,26 @@ else if (!strcmp (this_char, "nogrpid") || !strcmp (this_char, "sysvgroups")) clear_opt (*mount_options, GRPID); +#ifdef CONFIG_EXT2_RESIZE + else if (!strcmp (this_char, "resize")) { + printk ("EXT2-fs: parse_options: resize=%s\n", value); + if (!value || !*value){ + printk ("EXT2-fs: resize requires number of " + "blocks\n"); + return 0; + } + *n_blocks_count = simple_strtoul (value, &value, 0); + if (*value == ':') { + value++; + *resgdt = simple_strtoul (value, &value, 0); + } + if (*value) { + printk ("EXT2-fs: invalid resize option: %s\n", + value); + return 0; + } + } +#endif /* CONFIG_EXT2_RESIZE */ else if (!strcmp (this_char, "resgid")) { if (!value || !*value) { printk ("EXT2-fs: the resgid option requires " @@ -305,10 +332,10 @@ mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); sb->s_dirt = 1; if (test_opt (sb, DEBUG)) - printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " + printk ("[EXT II FS %s, %s, bs=%lu, bc=%lu, gc=%lu, " "bpg=%lu, ipg=%lu, mo=%04lx]\n", EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, - sb->u.ext2_sb.s_frag_size, + le32_to_cpu(es->s_blocks_count), sb->u.ext2_sb.s_groups_count, EXT2_BLOCKS_PER_GROUP(sb), EXT2_INODES_PER_GROUP(sb), @@ -343,7 +370,7 @@ if (le32_to_cpu(gdp->bg_block_bitmap) < block || le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb)) { - ext2_error (sb, "ext2_check_descriptors", + ext2_warning (sb, "ext2_check_descriptors", "Block bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap)); @@ -352,7 +379,7 @@ if (le32_to_cpu(gdp->bg_inode_bitmap) < block || le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb)) { - ext2_error (sb, "ext2_check_descriptors", + ext2_warning (sb, "ext2_check_descriptors", "Inode bitmap for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap)); @@ -362,7 +389,7 @@ le32_to_cpu(gdp->bg_inode_table) + sb->u.ext2_sb.s_itb_per_group >= block + EXT2_BLOCKS_PER_GROUP(sb)) { - ext2_error (sb, "ext2_check_descriptors", + ext2_warning (sb, "ext2_check_descriptors", "Inode table for group %d" " not in group (block %lu)!", i, (unsigned long) le32_to_cpu(gdp->bg_inode_table)); @@ -374,6 +401,295 @@ return 1; } +static int ext2_read_descriptors (struct super_block * sb, + unsigned long logic_sb_block, + unsigned long blocks_count) +{ + int db_start; + int db_count; + unsigned long groups_count; + unsigned long o_groups_count; + struct buffer_head ** group_desc = NULL; + struct buffer_head ** o_group_desc; + int i, j; + + o_group_desc = sb->u.ext2_sb.s_group_desc; + o_groups_count = sb->u.ext2_sb.s_groups_count; + + /* If we already have some groups loaded, start on the next one. */ + db_start = sb->u.ext2_sb.s_db_per_group + o_groups_count ? 1 : 0; + groups_count = (blocks_count - + le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block) + + EXT2_BLOCKS_PER_GROUP(sb) - 1) / + EXT2_BLOCKS_PER_GROUP(sb); + db_count = (groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / + EXT2_DESC_PER_BLOCK(sb); + if (test_opt (sb, DEBUG)) { + printk ("EXT2-fs: ext2_read_descriptors: o_groups_count=%lu, " + "groups_count=%lu, blocks_count=%lu\n", o_groups_count, + groups_count, blocks_count); + printk ("EXT2-fs: ext2_read_descriptors: db_orig=%lu, " + "db_start=%d, db_count=%d\n", + sb->u.ext2_sb.s_db_per_group, db_start, db_count); + } + + if (db_start != db_count) { + group_desc = (struct buffer_head **) kmalloc (db_count * + sizeof (struct buffer_head *), GFP_KERNEL); + if (group_desc == NULL) { + ext2_warning (sb, "ext2_read_descriptors", + "not enough memory for %d groups\n", + db_count); + return 0; + } + for (i = db_start; i < db_count; i++) { /* Add group blocks */ + group_desc[i] = bread (sb->s_dev, + logic_sb_block + i + 1, + sb->s_blocksize); + if (!group_desc[i]) { + for (j = db_start; j < i; j++) + brelse (group_desc[j]); + kfree_s (group_desc, db_count * + sizeof (struct buffer_head *)); + ext2_warning (sb, "ext2_read_descriptors", + "unable to read group block %d\n", + i); + return 0; + } + } +#ifdef CONFIG_EXT2_SHRINK + for (i = db_count; i < db_start; i++) /* Remove group blocks */ + brelse (o_group_desc[i]); +#endif /* CONFIG_EXT2_SHRINK */ + + /* + * Copy over old descriptor blocks previously loaded, if any. + * We need to set s_group_desc and s_groups_count now so that + * ext2_check_descriptors() will check the new groups as well. + * FIXME: is it ok to memcpy() 0 bytes to a NULL pointer? + */ + memcpy (group_desc, o_group_desc, + min(sb->u.ext2_sb.s_db_per_group, db_count) * + sizeof (struct buffer_head *)); + sb->u.ext2_sb.s_group_desc = group_desc; + } + sb->u.ext2_sb.s_groups_count = groups_count; + + if (!ext2_check_descriptors (sb)) { + sb->u.ext2_sb.s_groups_count = o_groups_count; + sb->u.ext2_sb.s_group_desc = o_group_desc; + for (j = db_start; j < db_count; j++) + brelse (group_desc[j]); + if (group_desc != NULL) + kfree_s (group_desc, + db_count * sizeof (struct buffer_head *)); + return 0; + } + + if (o_group_desc && o_group_desc != sb->u.ext2_sb.s_group_desc) + kfree_s (o_group_desc, sb->u.ext2_sb.s_db_per_group * + sizeof (struct buffer_head *)); + + sb->u.ext2_sb.s_db_per_group = db_count; + + return 1; +} + +#ifdef CONFIG_EXT2_RESIZE +static int ext2_update_group (struct super_block * sb, + unsigned int block_group, + unsigned int reserved, + unsigned int resgdt) +{ + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + int blocks, m_blocks; + int inodes; + int shrink = reserved > 100 ? 1 : 0; + + lock_super(sb); + es = sb->u.ext2_sb.s_es; + gdp = ext2_get_group_desc (sb, block_group, NULL); + + inodes = le32_to_cpu(gdp->bg_free_inodes_count); + blocks = le32_to_cpu(gdp->bg_free_blocks_count); + m_blocks = ((inodes * EXT2_INODE_SIZE(sb)) + EXT2_BLOCK_SIZE(sb) - 1) / + EXT2_BLOCK_SIZE(sb) + 3 + sb->u.ext2_sb.s_db_per_group + + resgdt + blocks; + +#ifdef CONFIG_EXT2_SHRINK + if (shrink) { /* Can only free if all blocks/inodes in group unused */ + int last = (le32_to_cpu(es->s_blocks_count) - + le32_to_cpu(es->s_first_data_block)) % + EXT2_BLOCKS_PER_GROUP(sb); + if (block_group != sb->u.ext2_sb.s_groups_count - 1) { + ext2_warning(sb, "ext2_update_group", + "unable to remove group %u - " + "it isn't the last group", block_group); + unlock_super (sb); + return -EBUSY; + } + if (inodes != le32_to_cpu(es->s_inodes_per_group) || + m_blocks != last) { + ext2_warning(sb, "ext2_update_group", + "unable to remove group %u - " + "%u blocks, %u inodes in use", block_group, + le32_to_cpu(es->s_inodes_per_group) - inodes, + last - m_blocks); + unlock_super (sb); + return -EBUSY; + } + inodes = -inodes; + blocks = -blocks; + m_blocks = -m_blocks; + reserved -= 100; + } +#endif /* CONFIG_EXT2_SHRINK */ + + es->s_free_inodes_count = + cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + inodes); + es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) + + inodes); + + es->s_free_blocks_count = + cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) + blocks); + es->s_blocks_count = cpu_to_le32(le32_to_cpu(es->s_blocks_count) + + m_blocks); + es->s_r_blocks_count = cpu_to_le32(le32_to_cpu(es->s_r_blocks_count) + + m_blocks * reserved / 100); + + mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + unlock_super(sb); + + if (test_opt (sb, DEBUG)) { + printk ("EXT2-fs: ext2_update_group: %s group %u: " + "%u inodes, %u blocks (%u free), %d (%d%%) reserved\n", + shrink ? "removing" : "adding", block_group, inodes, + m_blocks, blocks, m_blocks * reserved / 100, reserved); + printk ("EXT2-fs: ext2_update_group: %u inodes (%u free), " + "%u blocks (%u free)\n", + le32_to_cpu(es->s_inodes_count), + le32_to_cpu(es->s_free_inodes_count), + le32_to_cpu(es->s_blocks_count), + le32_to_cpu(es->s_free_blocks_count)); + } + + return 1; +} + +static int ext2_resize_fs (struct super_block * sb, + struct ext2_super_block * es, + unsigned long n_blocks_count, + unsigned long resgdt) +{ + unsigned long o_blocks_count; + unsigned long o_groups_count; + unsigned long last, add; + unsigned long reserved; + struct buffer_head * bh; + struct inode inode; + unsigned long i; + int stat = 1; + + o_blocks_count = le32_to_cpu(es->s_blocks_count); + o_groups_count = sb->u.ext2_sb.s_groups_count; + + if (test_opt (sb, DEBUG)) + printk ("EXT2-fs: ext2_resize_fs: from %lu to %lu blocks\n", + o_blocks_count, n_blocks_count); + + if (n_blocks_count == o_blocks_count) + return 1; + + /* See if the device is actually as big as what was requested */ + bh = bread (sb->s_dev, n_blocks_count - 1, EXT2_BLOCK_SIZE(sb)); + if (!bh) { + ext2_warning (sb, "ext2_resize_fs", + "unable to read last block, resize aborted"); + return -ENOSPC; + } + brelse (bh); + + /* For reserved percentage calculation, we avoid 32-bit overflow. */ + reserved = o_blocks_count > 10000000 ? + (es->s_r_blocks_count + o_blocks_count / 200) / (o_blocks_count / 100) : + (es->s_r_blocks_count * 100 + o_blocks_count / 2) / o_blocks_count; + +#ifdef CONFIG_EXT2_SHRINK + /* Free only whole groups for now, it is easier */ + while (n_blocks_count < es->s_blocks_count && + (stat = ext2_update_group (sb, o_groups_count - 1, + reserved + 100, resgdt)) > 0) + --o_groups_count; + if (stat < 0) + return stat; +#endif /* CONFIG_EXT2_SHRINK */ + + lock_super (sb); + if (!ext2_read_descriptors (sb, sb->u.ext2_sb.s_sbh->b_blocknr, + n_blocks_count)) { + ext2_warning (sb, "ext2_resize_fs", + "group descriptor error, resize aborted"); + unlock_super (sb); + return -EINVAL; + } + + /* Handle the remaining blocks in the last partial group. */ + last = (o_blocks_count - + le32_to_cpu(sb->u.ext2_sb.s_es->s_first_data_block)) % + EXT2_BLOCKS_PER_GROUP(sb); + if (last != 0) { /* The last group isn't full yet */ + /* Shouldn't happen because we currently free only whole + * groups in ext2_update_groups() + */ + if (n_blocks_count < o_blocks_count) { + ext2_error (sb, "ext2_resize_fs", + "shrinking FS, but last group has blocks!"); + unlock_super (sb); + return -EBUSY; + } + add = EXT2_BLOCKS_PER_GROUP(sb) - last; + if (add + o_blocks_count > n_blocks_count) + add = n_blocks_count - o_blocks_count; + es->s_blocks_count += add; + es->s_r_blocks_count += add * reserved / 100; + mark_buffer_dirty (sb->u.ext2_sb.s_sbh, 1); + sb->s_dirt = 1; + unlock_super (sb); + /* + * Fake out an inode enough to "free" the new blocks in this + * group. Turn off quotas for this inode so it doesn't get + * confused by freeing blocks that don't really exist yet. + */ + inode.i_sb = sb; + for (i = 0; i < MAXQUOTAS; i++) + inode.i_dquot[i] = NODQUOT; + ext2_free_blocks (&inode, o_blocks_count, add); + if (test_opt (sb, DEBUG)) + printk ("EXT2-fs: ext2_resize_fs: added %lu new blocks " + "to %lu current blocks\n", + add, o_blocks_count); + } + else + unlock_super (sb); + + /* + * Update superblock with remaining new group block/inode counts + */ + for (i = o_groups_count; + i < sb->u.ext2_sb.s_groups_count && + (stat = ext2_update_group (sb, i, reserved, resgdt)) > 0; i++) + /* empty loop */; + if (le32_to_cpu(es->s_blocks_count) != n_blocks_count) + ext2_warning (sb, "ext2_resize_fs", + "new block count does not match specified size" + "(%u != %lu)", le32_to_cpu(es->s_blocks_count), + n_blocks_count); + return stat; +} +#endif /* CONFIG_EXT2_RESIZE */ + #define log2(n) ffz(~(n)) struct super_block * ext2_read_super (struct super_block * sb, void * data, @@ -385,12 +701,13 @@ unsigned short resuid = EXT2_DEF_RESUID; unsigned short resgid = EXT2_DEF_RESGID; unsigned long logic_sb_block = 1; + unsigned long n_blocks_count = 0; + unsigned long resgdt = 0; unsigned long offset = 0; kdev_t dev = sb->s_dev; int blocksize = BLOCK_SIZE; int hblock; - int db_count; - int i, j; + int i; /* * See what the current blocksize for the device is, and @@ -408,7 +725,7 @@ sb->u.ext2_sb.s_mount_opt = 0; set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, - &sb->u.ext2_sb.s_mount_opt)) { + &sb->u.ext2_sb.s_mount_opt, &n_blocks_count, &resgdt)) { sb->s_dev = 0; return NULL; } @@ -583,35 +900,13 @@ goto failed_mount; } - sb->u.ext2_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_first_data_block) + - EXT2_BLOCKS_PER_GROUP(sb) - 1) / - EXT2_BLOCKS_PER_GROUP(sb); - db_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / - EXT2_DESC_PER_BLOCK(sb); - sb->u.ext2_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL); - if (sb->u.ext2_sb.s_group_desc == NULL) { - printk ("EXT2-fs: not enough memory\n"); - goto failed_mount; - } - for (i = 0; i < db_count; i++) { - sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, - sb->s_blocksize); - if (!sb->u.ext2_sb.s_group_desc[i]) { - for (j = 0; j < i; j++) - brelse (sb->u.ext2_sb.s_group_desc[j]); - kfree_s (sb->u.ext2_sb.s_group_desc, - db_count * sizeof (struct buffer_head *)); - printk ("EXT2-fs: unable to read group descriptors\n"); - goto failed_mount; - } - } - if (!ext2_check_descriptors (sb)) { - for (j = 0; j < db_count; j++) - brelse (sb->u.ext2_sb.s_group_desc[j]); - kfree_s (sb->u.ext2_sb.s_group_desc, - db_count * sizeof (struct buffer_head *)); - printk ("EXT2-fs: group descriptors corrupted !\n"); + sb->u.ext2_sb.s_db_per_group = 0; + sb->u.ext2_sb.s_groups_count = 0; + sb->u.ext2_sb.s_group_desc = NULL; + if (!ext2_read_descriptors (sb, logic_sb_block, + le32_to_cpu(es->s_blocks_count))) { + ext2_error (sb, "ext2_read_super", + "group descriptor error, unable to mount"); goto failed_mount; } for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { @@ -622,7 +917,6 @@ } sb->u.ext2_sb.s_loaded_inode_bitmaps = 0; sb->u.ext2_sb.s_loaded_block_bitmaps = 0; - sb->u.ext2_sb.s_db_per_group = db_count; unlock_super (sb); /* * set up enough so that it can read an inode @@ -632,16 +926,23 @@ sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO), NULL); if (!sb->s_root) { sb->s_dev = 0; - for (i = 0; i < db_count; i++) + for (i = 0; i < sb->u.ext2_sb.s_db_per_group; i++) if (sb->u.ext2_sb.s_group_desc[i]) brelse (sb->u.ext2_sb.s_group_desc[i]); kfree_s (sb->u.ext2_sb.s_group_desc, - db_count * sizeof (struct buffer_head *)); + sb->u.ext2_sb.s_db_per_group * + sizeof (struct buffer_head *)); brelse (bh); printk ("EXT2-fs: get root inode failed\n"); MOD_DEC_USE_COUNT; return NULL; } +#ifdef CONFIG_EXT2_RESIZE + if (n_blocks_count != 0 && + !ext2_resize_fs (sb, es, n_blocks_count, resgdt)) + ext2_warning (sb, "ext2_read_super", + "filesystem resize failed\n"); +#endif /* CONFIG_EXT2_RESIZE */ ext2_setup_super (sb, es); return sb; } @@ -688,6 +989,8 @@ struct ext2_super_block * es; unsigned short resuid = sb->u.ext2_sb.s_resuid; unsigned short resgid = sb->u.ext2_sb.s_resgid; + unsigned long n_blocks_count = 0; + unsigned long resgdt = 0; unsigned long new_mount_opt; unsigned long tmp; @@ -696,14 +999,15 @@ */ new_mount_opt = EXT2_MOUNT_CHECK_NORMAL; if (!parse_options (data, &tmp, &resuid, &resgid, - &new_mount_opt)) + &new_mount_opt, &n_blocks_count, &resgdt)) return -EINVAL; sb->u.ext2_sb.s_mount_opt = new_mount_opt; sb->u.ext2_sb.s_resuid = resuid; sb->u.ext2_sb.s_resgid = resgid; es = sb->u.ext2_sb.s_es; - if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY) && + n_blocks_count == 0) return 0; if (*flags & MS_RDONLY) { if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || @@ -727,6 +1031,19 @@ */ sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state); sb->s_flags &= ~MS_RDONLY; +#ifdef CONFIG_EXT2_RESIZE + if (n_blocks_count != 0) { + int stat; + sb->u.ext2_sb.s_mount_state |= EXT2_VALID_FS; + if ((stat = ext2_resize_fs (sb, es, n_blocks_count, + resgdt)) < 0) { + ext2_warning (sb, "ext2_remount", + "filesystem resize failed\n"); + sb->u.ext2_sb.s_mount_state &= ~EXT2_VALID_FS; + return stat; + } + } +#endif /* CONFIG_EXT2_RESIZE */ ext2_setup_super (sb, es); } return 0; diff -ru -X linux-2.2.12/exclude.lst linux-2.2.12.orig/include/linux/ext2_fs.h linux-2.2.12/include/linux/ext2_fs.h --- linux-2.2.12.orig/include/linux/ext2_fs.h Fri Oct 15 00:02:25 1999 +++ linux-2.2.12/include/linux/ext2_fs.h Wed Oct 6 21:00:53 1999 @@ -61,6 +61,7 @@ #define EXT2_ACL_DATA_INO 4 /* ACL inode */ #define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */ /* First non-reserved inode for old ext2 filesystems */ #define EXT2_GOOD_OLD_FIRST_INO 11