4 fs/ext3/xattr.c | 597 +++++++++++++++++++++++++++++++++++++++++++++-
5 include/linux/ext3_fs.h | 2
6 include/linux/ext3_fs_i.h | 3
7 6 files changed, 615 insertions(+), 11 deletions(-)
9 --- linux-2.4.22-ac1/fs/ext3/ialloc.c~ext3-ea-in-inode-2.4.22-rh 2003-10-08 13:57:56.000000000 +0400
10 +++ linux-2.4.22-ac1-alexey/fs/ext3/ialloc.c 2003-10-08 15:13:31.000000000 +0400
11 @@ -715,6 +715,10 @@ have_bit_and_group:
12 inode->i_generation = sb->u.ext3_sb.s_next_generation++;
14 inode->u.ext3_i.i_state = EXT3_STATE_NEW;
15 + inode->u.ext3_i.i_extra_isize =
16 + (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) ?
17 + sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE : 0;
19 err = ext3_get_inode_loc_new(inode, &iloc, 1);
21 BUFFER_TRACE(iloc->bh, "get_write_access");
22 --- linux-2.4.22-ac1/fs/ext3/inode.c~ext3-ea-in-inode-2.4.22-rh 2003-10-08 13:57:57.000000000 +0400
23 +++ linux-2.4.22-ac1-alexey/fs/ext3/inode.c 2003-10-08 15:14:57.000000000 +0400
24 @@ -2229,6 +2229,12 @@ void ext3_read_inode(struct inode * inod
25 inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
26 INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
28 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
29 + inode->u.ext3_i.i_extra_isize =
30 + le16_to_cpu(raw_inode->i_extra_isize);
32 + inode->u.ext3_i.i_extra_isize = 0;
34 if (S_ISREG(inode->i_mode)) {
35 inode->i_op = &ext3_file_inode_operations;
36 inode->i_fop = &ext3_file_operations;
37 @@ -2277,6 +2283,8 @@ static int ext3_do_update_inode(handle_t
41 + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
42 + memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
43 raw_inode->i_mode = cpu_to_le16(inode->i_mode);
44 if(!(test_opt(inode->i_sb, NO_UID32))) {
45 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
46 @@ -2360,6 +2368,10 @@ static int ext3_do_update_inode(handle_t
47 else for (block = 0; block < EXT3_N_BLOCKS; block++)
48 raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
50 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
51 + raw_inode->i_extra_isize =
52 + cpu_to_le16(EXT3_I(inode)->i_extra_isize);
54 BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
55 rc = ext3_journal_dirty_metadata(handle, bh);
57 --- linux-2.4.22-ac1/fs/ext3/super.c~ext3-ea-in-inode-2.4.22-rh 2003-10-08 13:57:57.000000000 +0400
58 +++ linux-2.4.22-ac1-alexey/fs/ext3/super.c 2003-10-08 15:13:31.000000000 +0400
59 @@ -1299,8 +1299,10 @@ struct super_block * ext3_read_super (st
61 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
62 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
63 - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
65 + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
66 + (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
67 + (sbi->s_inode_size > blocksize)) {
69 "EXT3-fs: unsupported inode size: %d\n",
72 --- linux-2.4.22-ac1/fs/ext3/xattr.c~ext3-ea-in-inode-2.4.22-rh 2003-10-08 13:57:56.000000000 +0400
73 +++ linux-2.4.22-ac1-alexey/fs/ext3/xattr.c 2003-10-12 16:36:07.000000000 +0400
75 static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
76 struct ext3_xattr_header *);
78 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
79 + const void *, size_t, int);
81 #ifdef CONFIG_EXT3_FS_XATTR_SHARING
83 static int ext3_xattr_cache_insert(struct buffer_head *);
84 @@ -348,17 +351,12 @@ ext3_removexattr(struct dentry *dentry,
90 - * Copy an extended attribute into the buffer
91 - * provided, or compute the buffer size required.
92 - * Buffer is NULL to compute the size of the buffer required.
93 + * ext3_xattr_block_get()
95 - * Returns a negative error number on failure, or the number of bytes
96 - * used / required on success.
97 + * routine looks for attribute in EA block and returns it's value and size
100 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
101 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
102 void *buffer, size_t buffer_size)
104 struct buffer_head *bh = NULL;
105 @@ -447,6 +445,94 @@ cleanup:
109 + * ext3_xattr_ibody_get()
111 + * routine looks for attribute in inode body and returns it's value and size
114 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
115 + void *buffer, size_t buffer_size)
117 + int size, name_len = strlen(name), storage_size;
118 + struct ext3_xattr_entry *last;
119 + struct ext3_inode *raw_inode;
120 + struct ext3_iloc iloc;
124 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
127 + ret = ext3_get_inode_loc(inode, &iloc);
130 + raw_inode = iloc.raw_inode;
132 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
133 + EXT3_GOOD_OLD_INODE_SIZE -
134 + EXT3_I(inode)->i_extra_isize -
136 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
137 + EXT3_I(inode)->i_extra_isize;
138 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
142 + start += sizeof(__u32);
143 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
145 + last = (struct ext3_xattr_entry *) start;
146 + while (!IS_LAST_ENTRY(last)) {
147 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
148 + if (le32_to_cpu(last->e_value_size) > storage_size ||
149 + (char *) next >= end) {
150 + ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
151 + "inode %ld", inode->i_ino);
155 + if (name_index == last->e_name_index &&
156 + name_len == last->e_name_len &&
157 + !memcmp(name, last->e_name, name_len))
162 + /* can't find EA */
167 + size = le32_to_cpu(last->e_value_size);
170 + if (buffer_size >= size) {
171 + memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
181 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
182 + void *buffer, size_t buffer_size)
186 + /* try to find attribute in inode body */
187 + err = ext3_xattr_ibody_get(inode, name_index, name,
188 + buffer, buffer_size);
190 + /* search was unsuccessful, try to find EA in dedicated block */
191 + err = ext3_xattr_block_get(inode, name_index, name,
192 + buffer, buffer_size);
199 * Copy a list of attribute names into the buffer
200 @@ -457,7 +543,7 @@ cleanup:
201 * used / required on success.
204 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
205 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
207 struct buffer_head *bh = NULL;
208 struct ext3_xattr_entry *entry;
209 @@ -530,6 +616,131 @@ cleanup:
213 +/* ext3_xattr_ibody_list()
215 + * generate list of attributes stored in inode body
218 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
220 + struct ext3_xattr_entry *last;
221 + struct ext3_inode *raw_inode;
222 + char *start, *end, *buf;
223 + struct ext3_iloc iloc;
228 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
231 + ret = ext3_get_inode_loc(inode, &iloc);
234 + raw_inode = iloc.raw_inode;
236 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
237 + EXT3_GOOD_OLD_INODE_SIZE -
238 + EXT3_I(inode)->i_extra_isize -
240 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
241 + EXT3_I(inode)->i_extra_isize;
242 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
246 + start += sizeof(__u32);
247 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
249 + last = (struct ext3_xattr_entry *) start;
250 + while (!IS_LAST_ENTRY(last)) {
251 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
252 + struct ext3_xattr_handler *handler;
253 + if (le32_to_cpu(last->e_value_size) > storage_size ||
254 + (char *) next >= end) {
255 + ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
256 + "inode %ld", inode->i_ino);
260 + handler = ext3_xattr_handler(last->e_name_index);
262 + size += handler->list(NULL, inode, last->e_name,
272 + if (size > buffer_size)
276 + last = (struct ext3_xattr_entry *) start;
278 + while (!IS_LAST_ENTRY(last)) {
279 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
280 + struct ext3_xattr_handler *handler;
281 + handler = ext3_xattr_handler(last->e_name_index);
283 + buf += handler->list(buf, inode, last->e_name,
294 + * ext3_xattr_list()
296 + * Copy a list of attribute names into the buffer
297 + * provided, or compute the buffer size required.
298 + * Buffer is NULL to compute the size of the buffer required.
300 + * Returns a negative error number on failure, or the number of bytes
301 + * used / required on success.
304 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
307 + int size = buffer_size;
309 + /* get list of attributes stored in inode body */
310 + error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
312 + /* some error occured while collecting
313 + * attributes in inode body */
319 + /* get list of attributes stored in dedicated block */
321 + buffer_size -= error;
322 + if (buffer_size <= 0) {
329 + error = ext3_xattr_block_list(inode, buffer, buffer_size);
331 + /* listing was successful, so we return len */
335 + return error + size;
339 * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
341 @@ -553,6 +764,279 @@ static void ext3_xattr_update_super_bloc
345 + * ext3_xattr_ibody_find()
347 + * search attribute and calculate free space in inode body
348 + * NOTE: free space includes space our attribute hold
351 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
352 + const char *name, struct ext3_xattr_entry *rentry, int *free)
354 + struct ext3_xattr_entry *last;
355 + struct ext3_inode *raw_inode;
356 + int name_len = strlen(name);
357 + int err, storage_size;
358 + struct ext3_iloc iloc;
362 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
365 + err = ext3_get_inode_loc(inode, &iloc);
368 + raw_inode = iloc.raw_inode;
370 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
371 + EXT3_GOOD_OLD_INODE_SIZE -
372 + EXT3_I(inode)->i_extra_isize -
374 + *free = storage_size - sizeof(__u32);
375 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
376 + EXT3_I(inode)->i_extra_isize;
377 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
381 + start += sizeof(__u32);
382 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
384 + last = (struct ext3_xattr_entry *) start;
385 + while (!IS_LAST_ENTRY(last)) {
386 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
387 + if (le32_to_cpu(last->e_value_size) > storage_size ||
388 + (char *) next >= end) {
389 + ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
390 + "inode %ld", inode->i_ino);
395 + if (name_index == last->e_name_index &&
396 + name_len == last->e_name_len &&
397 + !memcmp(name, last->e_name, name_len)) {
398 + memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
401 + *free -= EXT3_XATTR_LEN(last->e_name_len);
402 + *free -= le32_to_cpu(last->e_value_size);
412 + * ext3_xattr_block_find()
414 + * search attribute and calculate free space in EA block (if it allocated)
415 + * NOTE: free space includes space our attribute hold
418 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
419 + struct ext3_xattr_entry *rentry, int *free)
421 + struct buffer_head *bh = NULL;
422 + struct ext3_xattr_entry *entry;
424 + int name_len, error = -ENOENT;
426 + if (!EXT3_I(inode)->i_file_acl) {
427 + *free = inode->i_sb->s_blocksize -
428 + sizeof(struct ext3_xattr_header) -
432 + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
433 + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
436 + ea_bdebug(bh, "b_count=%d, refcount=%d",
437 + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
438 + end = bh->b_data + bh->b_size;
439 + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
440 + HDR(bh)->h_blocks != cpu_to_le32(1)) {
441 +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
442 + "inode %ld: bad block %d", inode->i_ino,
443 + EXT3_I(inode)->i_file_acl);
447 + /* find named attribute */
448 + name_len = strlen(name);
449 + *free = bh->b_size - sizeof(__u32);
451 + entry = FIRST_ENTRY(bh);
452 + while (!IS_LAST_ENTRY(entry)) {
453 + struct ext3_xattr_entry *next =
454 + EXT3_XATTR_NEXT(entry);
455 + if ((char *)next >= end)
457 + if (name_index == entry->e_name_index &&
458 + name_len == entry->e_name_len &&
459 + memcmp(name, entry->e_name, name_len) == 0) {
460 + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
463 + *free -= EXT3_XATTR_LEN(entry->e_name_len);
464 + *free -= le32_to_cpu(entry->e_value_size);
474 + * ext3_xattr_inode_set()
476 + * this routine add/remove/replace attribute in inode body
479 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
480 + const char *name, const void *value, size_t value_len,
483 + struct ext3_xattr_entry *last, *next, *here = NULL;
484 + struct ext3_inode *raw_inode;
485 + int name_len = strlen(name);
486 + int esize = EXT3_XATTR_LEN(name_len);
487 + struct buffer_head *bh;
488 + int err, storage_size;
489 + struct ext3_iloc iloc;
490 + int free, min_offs;
493 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
496 + err = ext3_get_inode_loc(inode, &iloc);
499 + raw_inode = iloc.raw_inode;
502 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
503 + EXT3_GOOD_OLD_INODE_SIZE -
504 + EXT3_I(inode)->i_extra_isize -
506 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
507 + EXT3_I(inode)->i_extra_isize;
508 + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
509 + /* inode had no attributes before */
510 + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
512 + start += sizeof(__u32);
513 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
514 + min_offs = storage_size;
515 + free = storage_size - sizeof(__u32);
517 + last = (struct ext3_xattr_entry *) start;
518 + while (!IS_LAST_ENTRY(last)) {
519 + next = EXT3_XATTR_NEXT(last);
520 + if (le32_to_cpu(last->e_value_size) > storage_size ||
521 + (char *) next >= end) {
522 + ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
523 + "inode %ld", inode->i_ino);
528 + if (last->e_value_size) {
529 + int offs = le16_to_cpu(last->e_value_offs);
530 + if (offs < min_offs)
533 + if (name_index == last->e_name_index &&
534 + name_len == last->e_name_len &&
535 + !memcmp(name, last->e_name, name_len))
538 + /* we calculate all but our attribute
539 + * because it will be removed before changing */
540 + free -= EXT3_XATTR_LEN(last->e_name_len);
541 + free -= le32_to_cpu(last->e_value_size);
546 + if (value && (esize + value_len > free)) {
551 + err = ext3_reserve_inode_write(handle, inode, &iloc);
558 + /* time to remove old value */
559 + struct ext3_xattr_entry *e;
560 + int size = le32_to_cpu(here->e_value_size);
561 + int border = le16_to_cpu(here->e_value_offs);
565 + memmove(start + min_offs + size, start + min_offs,
566 + border - min_offs);
568 + /* recalculate offsets */
569 + e = (struct ext3_xattr_entry *) start;
570 + while (!IS_LAST_ENTRY(e)) {
571 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
572 + int offs = le16_to_cpu(e->e_value_offs);
575 + cpu_to_le16(offs + size);
581 + border = EXT3_XATTR_LEN(here->e_name_len);
582 + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
583 + size = (char *) last - src;
584 + if ((char *) here + size > end)
585 + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
586 + __FILE__, __LINE__, here, size, end);
587 + memmove(here, src, size);
588 + last = (struct ext3_xattr_entry *) ((char *) last - border);
589 + *((__u32 *) last) = 0;
593 + int offs = min_offs - value_len;
594 + /* use last to create new entry */
595 + last->e_name_len = strlen(name);
596 + last->e_name_index = name_index;
597 + last->e_value_offs = cpu_to_le16(offs);
598 + last->e_value_size = cpu_to_le32(value_len);
599 + last->e_hash = last->e_value_block = 0;
600 + memset(last->e_name, 0, esize);
601 + memcpy(last->e_name, name, last->e_name_len);
602 + if (start + offs + value_len > end)
603 + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
604 + __FILE__, __LINE__, start, offs,
606 + memcpy(start + offs, value, value_len);
607 + last = EXT3_XATTR_NEXT(last);
608 + *((__u32 *) last) = 0;
611 + ext3_mark_iloc_dirty(handle, inode, &iloc);
620 * Create, replace or remove an extended attribute for this inode. Buffer
621 @@ -566,6 +1050,101 @@ static void ext3_xattr_update_super_bloc
624 ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
625 + const char *name, const void *value, size_t value_len, int flags)
627 + struct ext3_xattr_entry entry;
628 + int err, where = 0, found = 0, total;
629 + int free1 = -1, free2 = -1;
632 + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
633 + name_index, name, value, (long)value_len);
635 + if (IS_RDONLY(inode))
637 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
643 + name_len = strlen(name);
644 + if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
647 + /* try to find attribute in inode body */
648 + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
650 + /* found EA in inode */
653 + } else if (err == -ENOENT) {
654 + /* there is no such attribute in inode body */
655 + /* try to find attribute in dedicated block */
656 + err = ext3_xattr_block_find(inode, name_index, name,
658 + if (err != 0 && err != -ENOENT) {
659 + /* not found EA in block */
661 + } else if (err == 0) {
662 + /* found EA in block */
669 + /* check flags: may replace? may create ? */
670 + if (found && (flags & XATTR_CREATE)) {
673 + } else if (!found && (flags & XATTR_REPLACE)) {
678 + /* check if we have enough space to store attribute */
679 + total = EXT3_XATTR_LEN(strlen(name)) + value_len;
680 + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
681 + /* have no enough space */
686 + /* time to remove attribute */
689 + /* EA is stored in inode body */
690 + ext3_xattr_ibody_set(handle, inode, name_index, name,
693 + /* EA is stored in separated block */
694 + ext3_xattr_block_set(handle, inode, name_index, name,
699 + /* try to store EA in inode body */
700 + err = ext3_xattr_ibody_set(handle, inode, name_index, name,
701 + value, value_len, flags);
703 + /* can't store EA in inode body */
704 + /* try to store in block */
705 + err = ext3_xattr_block_set(handle, inode, name_index,
706 + name, value, value_len, flags);
714 + * ext3_xattr_block_set()
716 + * this routine add/remove/replace attribute in EA block
719 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
720 const char *name, const void *value, size_t value_len, int flags)
722 struct super_block *sb = inode->i_sb;
723 @@ -603,6 +1181,7 @@ ext3_xattr_set(handle_t *handle, struct
724 name_len = strlen(name);
725 if (name_len > 255 || value_len > sb->s_blocksize)
728 down(&ext3_xattr_sem);
731 --- linux-2.4.22-ac1/include/linux/ext3_fs.h~ext3-ea-in-inode-2.4.22-rh 2003-10-08 13:57:57.000000000 +0400
732 +++ linux-2.4.22-ac1-alexey/include/linux/ext3_fs.h 2003-10-08 15:13:31.000000000 +0400
733 @@ -265,6 +265,8 @@ struct ext3_inode {
734 __u32 m_i_reserved2[2];
736 } osd2; /* OS dependent 2 */
737 + __u16 i_extra_isize;
741 #define i_size_high i_dir_acl
742 --- linux-2.4.22-ac1/include/linux/ext3_fs_i.h~ext3-ea-in-inode-2.4.22-rh 2003-09-26 00:54:44.000000000 +0400
743 +++ linux-2.4.22-ac1-alexey/include/linux/ext3_fs_i.h 2003-10-08 15:13:31.000000000 +0400
744 @@ -62,6 +62,9 @@ struct ext3_inode_info {
748 + /* on-disk additional length */
749 + __u16 i_extra_isize;
752 * truncate_sem is for serialising ext3_truncate() against
753 * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's