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,12 @@ have_bit_and_group:
12 insert_inode_hash(inode);
13 inode->i_generation = sb->u.ext3_sb.s_next_generation++;
15 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) {
16 + inode->u.ext3_i.i_extra_isize = sizeof(__u16) /* i_extra_isize */
17 + + sizeof(__u16); /* i_pad1 */
19 + inode->u.ext3_i.i_extra_isize = 0;
21 inode->u.ext3_i.i_state = EXT3_STATE_NEW;
22 err = ext3_get_inode_loc_new(inode, &iloc, 1);
24 --- 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
25 +++ linux-2.4.22-ac1-alexey/fs/ext3/inode.c 2003-10-08 15:14:57.000000000 +0400
26 @@ -2229,6 +2229,12 @@ void ext3_read_inode(struct inode * inod
27 inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
28 INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);
30 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
31 + inode->u.ext3_i.i_extra_isize =
32 + le16_to_cpu(raw_inode->i_extra_isize);
34 + inode->u.ext3_i.i_extra_isize = 0;
36 if (S_ISREG(inode->i_mode)) {
37 inode->i_op = &ext3_file_inode_operations;
38 inode->i_fop = &ext3_file_operations;
39 @@ -2277,6 +2283,8 @@ static int ext3_do_update_inode(handle_t
43 + if (EXT3_I(inode)->i_state & EXT3_STATE_NEW)
44 + memset(raw_inode, 0, EXT3_INODE_SIZE(inode->i_sb));
45 raw_inode->i_mode = cpu_to_le16(inode->i_mode);
46 if(!(test_opt(inode->i_sb, NO_UID32))) {
47 raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
48 @@ -2360,6 +2368,10 @@ static int ext3_do_update_inode(handle_t
49 else for (block = 0; block < EXT3_N_BLOCKS; block++)
50 raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
52 + if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
53 + raw_inode->i_extra_isize =
54 + cpu_to_le16(EXT3_I(inode)->i_extra_isize);
56 BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
57 rc = ext3_journal_dirty_metadata(handle, bh);
59 --- 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
60 +++ linux-2.4.22-ac1-alexey/fs/ext3/super.c 2003-10-08 15:13:31.000000000 +0400
61 @@ -1299,8 +1299,10 @@ struct super_block * ext3_read_super (st
63 sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
64 sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
65 - if (sbi->s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
67 + if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) ||
68 + (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
69 + (sbi->s_inode_size > blocksize)) {
71 "EXT3-fs: unsupported inode size: %d\n",
74 --- 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
75 +++ linux-2.4.22-ac1-alexey/fs/ext3/xattr.c 2003-10-12 16:36:07.000000000 +0400
77 static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
78 struct ext3_xattr_header *);
80 +int ext3_xattr_block_set(handle_t *, struct inode *, int, const char *,
81 + const void *, size_t, int);
83 #ifdef CONFIG_EXT3_FS_XATTR_SHARING
85 static int ext3_xattr_cache_insert(struct buffer_head *);
86 @@ -348,17 +351,12 @@ ext3_removexattr(struct dentry *dentry,
92 - * Copy an extended attribute into the buffer
93 - * provided, or compute the buffer size required.
94 - * Buffer is NULL to compute the size of the buffer required.
95 + * ext3_xattr_block_get()
97 - * Returns a negative error number on failure, or the number of bytes
98 - * used / required on success.
99 + * routine looks for attribute in EA block and returns it's value and size
102 -ext3_xattr_get(struct inode *inode, int name_index, const char *name,
103 +ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
104 void *buffer, size_t buffer_size)
106 struct buffer_head *bh = NULL;
107 @@ -447,6 +445,94 @@ cleanup:
111 + * ext3_xattr_ibode_get()
113 + * routine looks for attribute in inode body and returns it's value and size
116 +ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
117 + void *buffer, size_t buffer_size)
119 + int size, name_len = strlen(name), storage_size;
120 + struct ext3_xattr_entry *last;
121 + struct ext3_inode *raw_inode;
122 + struct ext3_iloc iloc;
126 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
129 + ret = ext3_get_inode_loc(inode, &iloc);
132 + raw_inode = iloc.raw_inode;
134 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
135 + EXT3_GOOD_OLD_INODE_SIZE -
136 + EXT3_I(inode)->i_extra_isize -
138 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
139 + EXT3_I(inode)->i_extra_isize;
140 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
144 + start += sizeof(__u32);
145 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
147 + last = (struct ext3_xattr_entry *) start;
148 + while (!IS_LAST_ENTRY(last)) {
149 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
150 + if (le32_to_cpu(last->e_value_size) > storage_size ||
151 + (char *) next >= end) {
152 + ext3_error(inode->i_sb, "ext3_xattr_ibody_get",
153 + "inode %ld", inode->i_ino);
157 + if (name_index == last->e_name_index &&
158 + name_len == last->e_name_len &&
159 + !memcmp(name, last->e_name, name_len))
164 + /* can't find EA */
169 + size = le32_to_cpu(last->e_value_size);
172 + if (buffer_size >= size) {
173 + memcpy(buffer, start + le16_to_cpu(last->e_value_offs),
183 +int ext3_xattr_get(struct inode *inode, int name_index, const char *name,
184 + void *buffer, size_t buffer_size)
188 + /* try to find attribute in inode body */
189 + err = ext3_xattr_ibody_get(inode, name_index, name,
190 + buffer, buffer_size);
192 + /* search was unsuccessful, try to find EA in dedicated block */
193 + err = ext3_xattr_block_get(inode, name_index, name,
194 + buffer, buffer_size);
201 * Copy a list of attribute names into the buffer
202 @@ -457,7 +543,7 @@ cleanup:
203 * used / required on success.
206 -ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
207 +ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
209 struct buffer_head *bh = NULL;
210 struct ext3_xattr_entry *entry;
211 @@ -530,6 +616,131 @@ cleanup:
215 +/* ext3_xattr_ibody_list()
217 + * generate list of attributes stored in inode body
220 +ext3_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
222 + struct ext3_xattr_entry *last;
223 + struct ext3_inode *raw_inode;
224 + char *start, *end, *buf;
225 + struct ext3_iloc iloc;
230 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
233 + ret = ext3_get_inode_loc(inode, &iloc);
236 + raw_inode = iloc.raw_inode;
238 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
239 + EXT3_GOOD_OLD_INODE_SIZE -
240 + EXT3_I(inode)->i_extra_isize -
242 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
243 + EXT3_I(inode)->i_extra_isize;
244 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
248 + start += sizeof(__u32);
249 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
251 + last = (struct ext3_xattr_entry *) start;
252 + while (!IS_LAST_ENTRY(last)) {
253 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
254 + struct ext3_xattr_handler *handler;
255 + if (le32_to_cpu(last->e_value_size) > storage_size ||
256 + (char *) next >= end) {
257 + ext3_error(inode->i_sb, "ext3_xattr_ibody_list",
258 + "inode %ld", inode->i_ino);
262 + handler = ext3_xattr_handler(last->e_name_index);
264 + size += handler->list(NULL, inode, last->e_name,
274 + if (size > buffer_size)
278 + last = (struct ext3_xattr_entry *) start;
280 + while (!IS_LAST_ENTRY(last)) {
281 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
282 + struct ext3_xattr_handler *handler;
283 + handler = ext3_xattr_handler(last->e_name_index);
285 + buf += handler->list(buf, inode, last->e_name,
296 + * ext3_xattr_list()
298 + * Copy a list of attribute names into the buffer
299 + * provided, or compute the buffer size required.
300 + * Buffer is NULL to compute the size of the buffer required.
302 + * Returns a negative error number on failure, or the number of bytes
303 + * used / required on success.
306 +ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
309 + int size = buffer_size;
311 + /* get list of attributes stored in inode body */
312 + error = ext3_xattr_ibody_list(inode, buffer, buffer_size);
314 + /* some error occured while collecting
315 + * attributes in inode body */
321 + /* get list of attributes stored in dedicated block */
323 + buffer_size -= error;
324 + if (buffer_size <= 0) {
331 + error = ext3_xattr_block_list(inode, buffer, buffer_size);
333 + /* listing was successful, so we return len */
337 + return error + size;
341 * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is
343 @@ -553,6 +764,279 @@ static void ext3_xattr_update_super_bloc
347 + * ext3_xattr_ibody_find()
349 + * search attribute and calculate free space in inode body
350 + * NOTE: free space includes space our attribute hold
353 +ext3_xattr_ibody_find(struct inode *inode, int name_index,
354 + const char *name, struct ext3_xattr_entry *rentry, int *free)
356 + struct ext3_xattr_entry *last;
357 + struct ext3_inode *raw_inode;
358 + int name_len = strlen(name);
359 + int err, storage_size;
360 + struct ext3_iloc iloc;
364 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
367 + err = ext3_get_inode_loc(inode, &iloc);
370 + raw_inode = iloc.raw_inode;
372 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
373 + EXT3_GOOD_OLD_INODE_SIZE -
374 + EXT3_I(inode)->i_extra_isize -
376 + *free = storage_size - sizeof(__u32);
377 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
378 + EXT3_I(inode)->i_extra_isize;
379 + if (le32_to_cpu((*(__u32*) start)) != EXT3_XATTR_MAGIC) {
383 + start += sizeof(__u32);
384 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
386 + last = (struct ext3_xattr_entry *) start;
387 + while (!IS_LAST_ENTRY(last)) {
388 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last);
389 + if (le32_to_cpu(last->e_value_size) > storage_size ||
390 + (char *) next >= end) {
391 + ext3_error(inode->i_sb, "ext3_xattr_ibody_find",
392 + "inode %ld", inode->i_ino);
397 + if (name_index == last->e_name_index &&
398 + name_len == last->e_name_len &&
399 + !memcmp(name, last->e_name, name_len)) {
400 + memcpy(rentry, last, sizeof(struct ext3_xattr_entry));
403 + *free -= EXT3_XATTR_LEN(last->e_name_len);
404 + *free -= le32_to_cpu(last->e_value_size);
414 + * ext3_xattr_block_find()
416 + * search attribute and calculate free space in EA block (if it allocated)
417 + * NOTE: free space includes space our attribute hold
420 +ext3_xattr_block_find(struct inode *inode, int name_index, const char *name,
421 + struct ext3_xattr_entry *rentry, int *free)
423 + struct buffer_head *bh = NULL;
424 + struct ext3_xattr_entry *entry;
426 + int name_len, error = -ENOENT;
428 + if (!EXT3_I(inode)->i_file_acl) {
429 + *free = inode->i_sb->s_blocksize -
430 + sizeof(struct ext3_xattr_header) -
434 + ea_idebug(inode, "reading block %d", EXT3_I(inode)->i_file_acl);
435 + bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
438 + ea_bdebug(bh, "b_count=%d, refcount=%d",
439 + atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
440 + end = bh->b_data + bh->b_size;
441 + if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
442 + HDR(bh)->h_blocks != cpu_to_le32(1)) {
443 +bad_block: ext3_error(inode->i_sb, "ext3_xattr_get",
444 + "inode %ld: bad block %d", inode->i_ino,
445 + EXT3_I(inode)->i_file_acl);
449 + /* find named attribute */
450 + name_len = strlen(name);
451 + *free = bh->b_size - sizeof(__u32);
453 + entry = FIRST_ENTRY(bh);
454 + while (!IS_LAST_ENTRY(entry)) {
455 + struct ext3_xattr_entry *next =
456 + EXT3_XATTR_NEXT(entry);
457 + if ((char *)next >= end)
459 + if (name_index == entry->e_name_index &&
460 + name_len == entry->e_name_len &&
461 + memcmp(name, entry->e_name, name_len) == 0) {
462 + memcpy(rentry, entry, sizeof(struct ext3_xattr_entry));
465 + *free -= EXT3_XATTR_LEN(entry->e_name_len);
466 + *free -= le32_to_cpu(entry->e_value_size);
476 + * ext3_xattr_inode_set()
478 + * this routine add/remove/replace attribute in inode body
481 +ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, int name_index,
482 + const char *name, const void *value, size_t value_len,
485 + struct ext3_xattr_entry *last, *next, *here = NULL;
486 + struct ext3_inode *raw_inode;
487 + int name_len = strlen(name);
488 + int esize = EXT3_XATTR_LEN(name_len);
489 + struct buffer_head *bh;
490 + int err, storage_size;
491 + struct ext3_iloc iloc;
492 + int free, min_offs;
495 + if (EXT3_SB(inode->i_sb)->s_inode_size <= EXT3_GOOD_OLD_INODE_SIZE)
498 + err = ext3_get_inode_loc(inode, &iloc);
501 + raw_inode = iloc.raw_inode;
504 + storage_size = EXT3_SB(inode->i_sb)->s_inode_size -
505 + EXT3_GOOD_OLD_INODE_SIZE -
506 + EXT3_I(inode)->i_extra_isize -
508 + start = (char *) raw_inode + EXT3_GOOD_OLD_INODE_SIZE +
509 + EXT3_I(inode)->i_extra_isize;
510 + if ((*(__u32*) start) != EXT3_XATTR_MAGIC) {
511 + /* inode had no attributes before */
512 + *((__u32*) start) = cpu_to_le32(EXT3_XATTR_MAGIC);
514 + start += sizeof(__u32);
515 + end = (char *) raw_inode + EXT3_SB(inode->i_sb)->s_inode_size;
516 + min_offs = storage_size;
517 + free = storage_size - sizeof(__u32);
519 + last = (struct ext3_xattr_entry *) start;
520 + while (!IS_LAST_ENTRY(last)) {
521 + next = EXT3_XATTR_NEXT(last);
522 + if (le32_to_cpu(last->e_value_size) > storage_size ||
523 + (char *) next >= end) {
524 + ext3_error(inode->i_sb, "ext3_xattr_ibody_set",
525 + "inode %ld", inode->i_ino);
530 + if (last->e_value_size) {
531 + int offs = le16_to_cpu(last->e_value_offs);
532 + if (offs < min_offs)
535 + if (name_index == last->e_name_index &&
536 + name_len == last->e_name_len &&
537 + !memcmp(name, last->e_name, name_len))
540 + /* we calculate all but our attribute
541 + * because it will be removed before changing */
542 + free -= EXT3_XATTR_LEN(last->e_name_len);
543 + free -= le32_to_cpu(last->e_value_size);
548 + if (value && (esize + value_len > free)) {
553 + err = ext3_reserve_inode_write(handle, inode, &iloc);
560 + /* time to remove old value */
561 + struct ext3_xattr_entry *e;
562 + int size = le32_to_cpu(here->e_value_size);
563 + int border = le16_to_cpu(here->e_value_offs);
567 + memmove(start + min_offs + size, start + min_offs,
568 + border - min_offs);
570 + /* recalculate offsets */
571 + e = (struct ext3_xattr_entry *) start;
572 + while (!IS_LAST_ENTRY(e)) {
573 + struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(e);
574 + int offs = le16_to_cpu(e->e_value_offs);
577 + cpu_to_le16(offs + size);
583 + border = EXT3_XATTR_LEN(here->e_name_len);
584 + src = (char *) here + EXT3_XATTR_LEN(here->e_name_len);
585 + size = (char *) last - src;
586 + if ((char *) here + size > end)
587 + printk("ALERT at %s:%d: 0x%p + %d > 0x%p\n",
588 + __FILE__, __LINE__, here, size, end);
589 + memmove(here, src, size);
590 + last = (struct ext3_xattr_entry *) ((char *) last - border);
591 + *((__u32 *) last) = 0;
595 + int offs = min_offs - value_len;
596 + /* use last to create new entry */
597 + last->e_name_len = strlen(name);
598 + last->e_name_index = name_index;
599 + last->e_value_offs = cpu_to_le16(offs);
600 + last->e_value_size = cpu_to_le32(value_len);
601 + last->e_hash = last->e_value_block = 0;
602 + memset(last->e_name, 0, esize);
603 + memcpy(last->e_name, name, last->e_name_len);
604 + if (start + offs + value_len > end)
605 + printk("ALERT at %s:%d: 0x%p + %d + %d > 0x%p\n",
606 + __FILE__, __LINE__, start, offs,
608 + memcpy(start + offs, value, value_len);
609 + last = EXT3_XATTR_NEXT(last);
610 + *((__u32 *) last) = 0;
613 + ext3_mark_iloc_dirty(handle, inode, &iloc);
622 * Create, replace or remove an extended attribute for this inode. Buffer
623 @@ -566,6 +1050,101 @@ static void ext3_xattr_update_super_bloc
626 ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index,
627 + const char *name, const void *value, size_t value_len, int flags)
629 + struct ext3_xattr_entry entry;
630 + int err, where = 0, found = 0, total;
631 + int free1 = -1, free2 = -1;
634 + ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
635 + name_index, name, value, (long)value_len);
637 + if (IS_RDONLY(inode))
639 + if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
645 + name_len = strlen(name);
646 + if (name_len > 255 || value_len > inode->i_sb->s_blocksize)
649 + /* try to find attribute in inode body */
650 + err = ext3_xattr_ibody_find(inode, name_index, name, &entry, &free1);
652 + /* found EA in inode */
655 + } else if (err == -ENOENT) {
656 + /* there is no such attribute in inode body */
657 + /* try to find attribute in dedicated block */
658 + err = ext3_xattr_block_find(inode, name_index, name,
660 + if (err != 0 && err != -ENOENT) {
661 + /* not found EA in block */
663 + } else if (err == 0) {
664 + /* found EA in block */
671 + /* check flags: may replace? may create ? */
672 + if (found && (flags & XATTR_CREATE)) {
675 + } else if (!found && (flags & XATTR_REPLACE)) {
680 + /* check if we have enough space to store attribute */
681 + total = EXT3_XATTR_LEN(strlen(name)) + value_len;
682 + if (free1 >= 0 && total > free1 && free2 >= 0 && total > free2) {
683 + /* have no enough space */
688 + /* time to remove attribute */
691 + /* EA is stored in inode body */
692 + ext3_xattr_ibody_set(handle, inode, name_index, name,
695 + /* EA is stored in separated block */
696 + ext3_xattr_block_set(handle, inode, name_index, name,
701 + /* try to store EA in inode body */
702 + err = ext3_xattr_ibody_set(handle, inode, name_index, name,
703 + value, value_len, flags);
705 + /* can't store EA in inode body */
706 + /* try to store in block */
707 + err = ext3_xattr_block_set(handle, inode, name_index,
708 + name, value, value_len, flags);
716 + * ext3_xattr_block_set()
718 + * this routine add/remove/replace attribute in EA block
721 +ext3_xattr_block_set(handle_t *handle, struct inode *inode, int name_index,
722 const char *name, const void *value, size_t value_len, int flags)
724 struct super_block *sb = inode->i_sb;
725 @@ -603,6 +1181,7 @@ ext3_xattr_set(handle_t *handle, struct
726 name_len = strlen(name);
727 if (name_len > 255 || value_len > sb->s_blocksize)
730 down(&ext3_xattr_sem);
733 --- 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
734 +++ linux-2.4.22-ac1-alexey/include/linux/ext3_fs.h 2003-10-08 15:13:31.000000000 +0400
735 @@ -265,6 +265,8 @@ struct ext3_inode {
736 __u32 m_i_reserved2[2];
738 } osd2; /* OS dependent 2 */
739 + __u16 i_extra_isize;
743 #define i_size_high i_dir_acl
744 --- 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
745 +++ linux-2.4.22-ac1-alexey/include/linux/ext3_fs_i.h 2003-10-08 15:13:31.000000000 +0400
746 @@ -62,6 +62,9 @@ struct ext3_inode_info {
750 + /* on-disk additional length */
751 + __u16 i_extra_isize;
754 * truncate_sem is for serialising ext3_truncate() against
755 * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's