+++ /dev/null
---- extN/extN.orig/balloc.c Wed Sep 25 11:51:33 2002
-+++ extN/balloc.c Wed Sep 25 14:22:53 2002
-@@ -46,18 +46,18 @@
- unsigned long desc;
- struct extN_group_desc * gdp;
-
-- if (block_group >= sb->u.extN_sb.s_groups_count) {
-+ if (block_group >= EXTN_SB(sb)->s_groups_count) {
- extN_error (sb, "extN_get_group_desc",
- "block_group >= groups_count - "
- "block_group = %d, groups_count = %lu",
-- block_group, sb->u.extN_sb.s_groups_count);
-+ block_group, EXTN_SB(sb)->s_groups_count);
-
- return NULL;
- }
-
- group_desc = block_group / EXTN_DESC_PER_BLOCK(sb);
- desc = block_group % EXTN_DESC_PER_BLOCK(sb);
-- if (!sb->u.extN_sb.s_group_desc[group_desc]) {
-+ if (!EXTN_SB(sb)->s_group_desc[group_desc]) {
- extN_error (sb, "extN_get_group_desc",
- "Group descriptor not loaded - "
- "block_group = %d, group_desc = %lu, desc = %lu",
-@@ -66,9 +66,9 @@
- }
-
- gdp = (struct extN_group_desc *)
-- sb->u.extN_sb.s_group_desc[group_desc]->b_data;
-+ EXTN_SB(sb)->s_group_desc[group_desc]->b_data;
- if (bh)
-- *bh = sb->u.extN_sb.s_group_desc[group_desc];
-+ *bh = EXTN_SB(sb)->s_group_desc[group_desc];
- return gdp + desc;
- }
-
-@@ -104,8 +104,8 @@
- * this group. The IO will be retried next time.
- */
- error_out:
-- sb->u.extN_sb.s_block_bitmap_number[bitmap_nr] = block_group;
-- sb->u.extN_sb.s_block_bitmap[bitmap_nr] = bh;
-+ EXTN_SB(sb)->s_block_bitmap_number[bitmap_nr] = block_group;
-+ EXTN_SB(sb)->s_block_bitmap[bitmap_nr] = bh;
- return retval;
- }
-
-@@ -128,16 +128,17 @@
- int i, j, retval = 0;
- unsigned long block_bitmap_number;
- struct buffer_head * block_bitmap;
-+ struct extN_sb_info *sbi = EXTN_SB(sb);
-
-- if (block_group >= sb->u.extN_sb.s_groups_count)
-+ if (block_group >= sbi->s_groups_count)
- extN_panic (sb, "load_block_bitmap",
- "block_group >= groups_count - "
- "block_group = %d, groups_count = %lu",
-- block_group, sb->u.extN_sb.s_groups_count);
-+ block_group, EXTN_SB(sb)->s_groups_count);
-
-- if (sb->u.extN_sb.s_groups_count <= EXTN_MAX_GROUP_LOADED) {
-- if (sb->u.extN_sb.s_block_bitmap[block_group]) {
-- if (sb->u.extN_sb.s_block_bitmap_number[block_group] ==
-+ if (sbi->s_groups_count <= EXTN_MAX_GROUP_LOADED) {
-+ if (sbi->s_block_bitmap[block_group]) {
-+ if (sbi->s_block_bitmap_number[block_group] ==
- block_group)
- return block_group;
- extN_error (sb, "__load_block_bitmap",
-@@ -149,21 +150,20 @@
- return block_group;
- }
-
-- for (i = 0; i < sb->u.extN_sb.s_loaded_block_bitmaps &&
-- sb->u.extN_sb.s_block_bitmap_number[i] != block_group; i++)
-+ for (i = 0; i < sbi->s_loaded_block_bitmaps &&
-+ sbi->s_block_bitmap_number[i] != block_group; i++)
- ;
-- if (i < sb->u.extN_sb.s_loaded_block_bitmaps &&
-- sb->u.extN_sb.s_block_bitmap_number[i] == block_group) {
-- block_bitmap_number = sb->u.extN_sb.s_block_bitmap_number[i];
-- block_bitmap = sb->u.extN_sb.s_block_bitmap[i];
-+ if (i < sbi->s_loaded_block_bitmaps &&
-+ sbi->s_block_bitmap_number[i] == block_group) {
-+ block_bitmap_number = sbi->s_block_bitmap_number[i];
-+ block_bitmap = sbi->s_block_bitmap[i];
- for (j = i; j > 0; j--) {
-- sb->u.extN_sb.s_block_bitmap_number[j] =
-- sb->u.extN_sb.s_block_bitmap_number[j - 1];
-- sb->u.extN_sb.s_block_bitmap[j] =
-- sb->u.extN_sb.s_block_bitmap[j - 1];
-+ sbi->s_block_bitmap_number[j] =
-+ sbi->s_block_bitmap_number[j - 1];
-+ sbi->s_block_bitmap[j] = sbi->s_block_bitmap[j - 1];
- }
-- sb->u.extN_sb.s_block_bitmap_number[0] = block_bitmap_number;
-- sb->u.extN_sb.s_block_bitmap[0] = block_bitmap;
-+ sbi->s_block_bitmap_number[0] = block_bitmap_number;
-+ sbi->s_block_bitmap[0] = block_bitmap;
-
- /*
- * There's still one special case here --- if block_bitmap == 0
-@@ -173,17 +173,14 @@
- if (!block_bitmap)
- retval = read_block_bitmap (sb, block_group, 0);
- } else {
-- if (sb->u.extN_sb.s_loaded_block_bitmaps<EXTN_MAX_GROUP_LOADED)
-- sb->u.extN_sb.s_loaded_block_bitmaps++;
-+ if (sbi->s_loaded_block_bitmaps<EXTN_MAX_GROUP_LOADED)
-+ sbi->s_loaded_block_bitmaps++;
- else
-- brelse (sb->u.extN_sb.s_block_bitmap
-- [EXTN_MAX_GROUP_LOADED - 1]);
-- for (j = sb->u.extN_sb.s_loaded_block_bitmaps - 1;
-- j > 0; j--) {
-- sb->u.extN_sb.s_block_bitmap_number[j] =
-- sb->u.extN_sb.s_block_bitmap_number[j - 1];
-- sb->u.extN_sb.s_block_bitmap[j] =
-- sb->u.extN_sb.s_block_bitmap[j - 1];
-+ brelse(sbi->s_block_bitmap[EXTN_MAX_GROUP_LOADED - 1]);
-+ for (j = sbi->s_loaded_block_bitmaps - 1; j > 0; j--) {
-+ sbi->s_block_bitmap_number[j] =
-+ sbi->s_block_bitmap_number[j - 1];
-+ sbi->s_block_bitmap[j] = sbi->s_block_bitmap[j - 1];
- }
- retval = read_block_bitmap (sb, block_group, 0);
- }
-@@ -206,24 +203,25 @@
- static inline int load_block_bitmap (struct super_block * sb,
- unsigned int block_group)
- {
-+ struct extN_sb_info *sbi = EXTN_SB(sb);
- int slot;
--
-+
- /*
- * Do the lookup for the slot. First of all, check if we're asking
- * for the same slot as last time, and did we succeed that last time?
- */
-- if (sb->u.extN_sb.s_loaded_block_bitmaps > 0 &&
-- sb->u.extN_sb.s_block_bitmap_number[0] == block_group &&
-- sb->u.extN_sb.s_block_bitmap[0]) {
-+ if (sbi->s_loaded_block_bitmaps > 0 &&
-+ sbi->s_block_bitmap_number[0] == block_group &&
-+ sbi->s_block_bitmap[0]) {
- return 0;
- }
- /*
- * Or can we do a fast lookup based on a loaded group on a filesystem
- * small enough to be mapped directly into the superblock?
- */
-- else if (sb->u.extN_sb.s_groups_count <= EXTN_MAX_GROUP_LOADED &&
-- sb->u.extN_sb.s_block_bitmap_number[block_group]==block_group
-- && sb->u.extN_sb.s_block_bitmap[block_group]) {
-+ else if (sbi->s_groups_count <= EXTN_MAX_GROUP_LOADED &&
-+ sbi->s_block_bitmap_number[block_group] == block_group
-+ && sbi->s_block_bitmap[block_group]) {
- slot = block_group;
- }
- /*
-@@ -243,7 +241,7 @@
- * If it's a valid slot, we may still have cached a previous IO error,
- * in which case the bh in the superblock cache will be zero.
- */
-- if (!sb->u.extN_sb.s_block_bitmap[slot])
-+ if (!sbi->s_block_bitmap[slot])
- return -EIO;
-
- /*
-@@ -275,7 +273,7 @@
- return;
- }
- lock_super (sb);
-- es = sb->u.extN_sb.s_es;
-+ es = EXTN_SB(sb)->s_es;
- if (block < le32_to_cpu(es->s_first_data_block) ||
- (block + count) > le32_to_cpu(es->s_blocks_count)) {
- extN_error (sb, "extN_free_blocks",
-@@ -304,7 +302,7 @@
- if (bitmap_nr < 0)
- goto error_return;
-
-- bitmap_bh = sb->u.extN_sb.s_block_bitmap[bitmap_nr];
-+ bitmap_bh = EXTN_SB(sb)->s_block_bitmap[bitmap_nr];
- gdp = extN_get_group_desc (sb, block_group, &gd_bh);
- if (!gdp)
- goto error_return;
-@@ -312,9 +310,9 @@
- if (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
- in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
- in_range (block, le32_to_cpu(gdp->bg_inode_table),
-- sb->u.extN_sb.s_itb_per_group) ||
-+ EXTN_SB(sb)->s_itb_per_group) ||
- in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
-- sb->u.extN_sb.s_itb_per_group))
-+ EXTN_SB(sb)->s_itb_per_group))
- extN_error (sb, "extN_free_blocks",
- "Freeing blocks in system zones - "
- "Block = %lu, count = %lu",
-@@ -340,8 +338,8 @@
- if (err)
- goto error_return;
-
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "get_write_access");
-- err = extN_journal_get_write_access(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(EXTN_SB(sb)->s_sbh, "get_write_access");
-+ err = extN_journal_get_write_access(handle, EXTN_SB(sb)->s_sbh);
- if (err)
- goto error_return;
-
-@@ -410,8 +408,8 @@
- if (!err) err = ret;
-
- /* And the superblock */
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "dirtied superblock");
-- ret = extN_journal_dirty_metadata(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(EXTN_SB(sb)->s_sbh, "dirtied superblock");
-+ ret = extN_journal_dirty_metadata(handle, EXTN_SB(sb)->s_sbh);
- if (!err) err = ret;
-
- if (overflow && !err) {
-@@ -564,12 +562,12 @@
- }
-
- lock_super (sb);
-- es = sb->u.extN_sb.s_es;
-+ es = EXTN_SB(sb)->s_es;
- if (le32_to_cpu(es->s_free_blocks_count) <=
- le32_to_cpu(es->s_r_blocks_count) &&
-- ((sb->u.extN_sb.s_resuid != current->fsuid) &&
-- (sb->u.extN_sb.s_resgid == 0 ||
-- !in_group_p (sb->u.extN_sb.s_resgid)) &&
-+ ((EXTN_SB(sb)->s_resuid != current->fsuid) &&
-+ (EXTN_SB(sb)->s_resgid == 0 ||
-+ !in_group_p (EXTN_SB(sb)->s_resgid)) &&
- !capable(CAP_SYS_RESOURCE)))
- goto out;
-
-@@ -598,7 +596,7 @@
- if (bitmap_nr < 0)
- goto io_error;
-
-- bh = sb->u.extN_sb.s_block_bitmap[bitmap_nr];
-+ bh = EXTN_SB(sb)->s_block_bitmap[bitmap_nr];
-
- extN_debug ("goal is at %d:%d.\n", i, j);
-
-@@ -621,9 +619,9 @@
- * Now search the rest of the groups. We assume that
- * i and gdp correctly point to the last group visited.
- */
-- for (k = 0; k < sb->u.extN_sb.s_groups_count; k++) {
-+ for (k = 0; k < EXTN_SB(sb)->s_groups_count; k++) {
- i++;
-- if (i >= sb->u.extN_sb.s_groups_count)
-+ if (i >= EXTN_SB(sb)->s_groups_count)
- i = 0;
- gdp = extN_get_group_desc (sb, i, &bh2);
- if (!gdp) {
-@@ -635,7 +633,7 @@
- if (bitmap_nr < 0)
- goto io_error;
-
-- bh = sb->u.extN_sb.s_block_bitmap[bitmap_nr];
-+ bh = EXTN_SB(sb)->s_block_bitmap[bitmap_nr];
- j = find_next_usable_block(-1, bh,
- EXTN_BLOCKS_PER_GROUP(sb));
- if (j >= 0)
-@@ -674,8 +672,8 @@
- fatal = extN_journal_get_write_access(handle, bh2);
- if (fatal) goto out;
-
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "get_write_access");
-- fatal = extN_journal_get_write_access(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(EXTN_SB(sb)->s_sbh, "get_write_access");
-+ fatal = extN_journal_get_write_access(handle, EXTN_SB(sb)->s_sbh);
- if (fatal) goto out;
-
- tmp = j + i * EXTN_BLOCKS_PER_GROUP(sb)
-@@ -684,7 +682,7 @@
- if (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
- tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
- in_range (tmp, le32_to_cpu(gdp->bg_inode_table),
-- sb->u.extN_sb.s_itb_per_group))
-+ EXTN_SB(sb)->s_itb_per_group))
- extN_error (sb, "extN_new_block",
- "Allocating block in system zone - "
- "block = %u", tmp);
-@@ -796,7 +794,7 @@
- if (!fatal) fatal = err;
-
- BUFFER_TRACE(bh, "journal_dirty_metadata for superblock");
-- err = extN_journal_dirty_metadata(handle, sb->u.extN_sb.s_sbh);
-+ err = extN_journal_dirty_metadata(handle, EXTN_SB(sb)->s_sbh);
- if (!fatal) fatal = err;
-
- sb->s_dirt = 1;
-@@ -829,11 +827,11 @@
- int i;
-
- lock_super (sb);
-- es = sb->u.extN_sb.s_es;
-+ es = EXTN_SB(sb)->s_es;
- desc_count = 0;
- bitmap_count = 0;
- gdp = NULL;
-- for (i = 0; i < sb->u.extN_sb.s_groups_count; i++) {
-+ for (i = 0; i < EXTN_SB(sb)->s_groups_count; i++) {
- gdp = extN_get_group_desc (sb, i, NULL);
- if (!gdp)
- continue;
-@@ -842,7 +840,7 @@
- if (bitmap_nr < 0)
- continue;
-
-- x = extN_count_free (sb->u.extN_sb.s_block_bitmap[bitmap_nr],
-+ x = extN_count_free (EXTN_SB(sb)->s_block_bitmap[bitmap_nr],
- sb->s_blocksize);
- printk ("group %d: stored = %d, counted = %lu\n",
- i, le16_to_cpu(gdp->bg_free_blocks_count), x);
-@@ -853,7 +851,7 @@
- unlock_super (sb);
- return bitmap_count;
- #else
-- return le32_to_cpu(sb->u.extN_sb.s_es->s_free_blocks_count);
-+ return le32_to_cpu(EXTN_SB(sb)->s_es->s_free_blocks_count);
- #endif
- }
-
-@@ -862,7 +860,7 @@
- unsigned char * map)
- {
- return extN_test_bit ((block -
-- le32_to_cpu(sb->u.extN_sb.s_es->s_first_data_block)) %
-+ le32_to_cpu(EXTN_SB(sb)->s_es->s_first_data_block)) %
- EXTN_BLOCKS_PER_GROUP(sb), map);
- }
-
-@@ -930,11 +928,11 @@
- struct extN_group_desc * gdp;
- int i;
-
-- es = sb->u.extN_sb.s_es;
-+ es = EXTN_SB(sb)->s_es;
- desc_count = 0;
- bitmap_count = 0;
- gdp = NULL;
-- for (i = 0; i < sb->u.extN_sb.s_groups_count; i++) {
-+ for (i = 0; i < EXTN_SB(sb)->s_groups_count; i++) {
- gdp = extN_get_group_desc (sb, i, NULL);
- if (!gdp)
- continue;
-@@ -968,7 +966,7 @@
- "Inode bitmap for group %d is marked free",
- i);
-
-- for (j = 0; j < sb->u.extN_sb.s_itb_per_group; j++)
-+ for (j = 0; j < EXTN_SB(sb)->s_itb_per_group; j++)
- if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j,
- sb, bh->b_data))
- extN_error (sb, "extN_check_blocks_bitmap",
---- extN/extN.orig/dir.c Wed Sep 25 11:51:33 2002
-+++ extN/dir.c Wed Sep 25 11:53:07 2002
-@@ -52,7 +52,7 @@
- else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
- error_msg = "directory entry across blocks";
- else if (le32_to_cpu(de->inode) >
-- le32_to_cpu(dir->i_sb->u.extN_sb.s_es->s_inodes_count))
-+ le32_to_cpu(EXTN_SB(dir->i_sb)->s_es->s_inodes_count))
- error_msg = "inode out of bounds";
-
- if (error_msg != NULL)
---- extN/extN.orig/ialloc.c Wed Sep 25 11:51:33 2002
-+++ extN/ialloc.c Wed Sep 25 11:53:07 2002
-@@ -17,6 +17,7 @@
- #include <linux/jbd.h>
- #include <linux/extN_fs.h>
- #include <linux/extN_jbd.h>
-+#include <linux/extN_xattr.h>
- #include <linux/stat.h>
- #include <linux/string.h>
- #include <linux/locks.h>
-@@ -73,8 +74,8 @@
- * this group. The IO will be retried next time.
- */
- error_out:
-- sb->u.extN_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
-- sb->u.extN_sb.s_inode_bitmap[bitmap_nr] = bh;
-+ EXTN_SB(sb)->s_inode_bitmap_number[bitmap_nr] = block_group;
-+ EXTN_SB(sb)->s_inode_bitmap[bitmap_nr] = bh;
- return retval;
- }
-
-@@ -216,6 +217,7 @@
- * as writing the quota to disk may need the lock as well.
- */
- DQUOT_INIT(inode);
-+ extN_xattr_drop_inode(handle, inode);
- DQUOT_FREE_INODE(inode);
- DQUOT_DROP(inode);
-
-@@ -225,7 +227,7 @@
- clear_inode (inode);
-
- lock_super (sb);
-- es = sb->u.extN_sb.s_es;
-+ es = EXTN_SB(sb)->s_es;
- if (ino < EXTN_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
- extN_error (sb, "extN_free_inode",
- "reserved or nonexistent inode %lu", ino);
-@@ -237,7 +239,7 @@
- if (bitmap_nr < 0)
- goto error_return;
-
-- bh = sb->u.extN_sb.s_inode_bitmap[bitmap_nr];
-+ bh = EXTN_SB(sb)->s_inode_bitmap[bitmap_nr];
-
- BUFFER_TRACE(bh, "get_write_access");
- fatal = extN_journal_get_write_access(handle, bh);
-@@ -255,8 +257,8 @@
- fatal = extN_journal_get_write_access(handle, bh2);
- if (fatal) goto error_return;
-
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "get write access");
-- fatal = extN_journal_get_write_access(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(EXTN_SB(sb)->s_sbh, "get write access");
-+ fatal = extN_journal_get_write_access(handle, EXTN_SB(sb)->s_sbh);
- if (fatal) goto error_return;
-
- if (gdp) {
-@@ -271,9 +273,9 @@
- if (!fatal) fatal = err;
- es->s_free_inodes_count =
- cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh,
-+ BUFFER_TRACE(EXTN_SB(sb)->s_sbh,
- "call extN_journal_dirty_metadata");
-- err = extN_journal_dirty_metadata(handle, sb->u.extN_sb.s_sbh);
-+ err = extN_journal_dirty_metadata(handle, EXTN_SB(sb)->s_sbh);
- if (!fatal) fatal = err;
- }
- BUFFER_TRACE(bh, "call extN_journal_dirty_metadata");
-@@ -305,6 +307,8 @@
- int i, j, avefreei;
- struct inode * inode;
- int bitmap_nr;
-+ struct extN_inode_info *ei;
-+ struct extN_sb_info *sbi;
- struct extN_group_desc * gdp;
- struct extN_group_desc * tmp;
- struct extN_super_block * es;
-@@ -318,19 +322,21 @@
- inode = new_inode(sb);
- if (!inode)
- return ERR_PTR(-ENOMEM);
-- init_rwsem(&inode->u.extN_i.truncate_sem);
-+ sbi = EXTN_SB(sb);
-+ ei = EXTN_I(inode);
-+ init_rwsem(&ei->truncate_sem);
-
- lock_super (sb);
-- es = sb->u.extN_sb.s_es;
-+ es = sbi->s_es;
- repeat:
- gdp = NULL;
- i = 0;
-
- if (S_ISDIR(mode)) {
- avefreei = le32_to_cpu(es->s_free_inodes_count) /
-- sb->u.extN_sb.s_groups_count;
-+ sbi->s_groups_count;
- if (!gdp) {
-- for (j = 0; j < sb->u.extN_sb.s_groups_count; j++) {
-+ for (j = 0; j < sbi->s_groups_count; j++) {
- struct buffer_head *temp_buffer;
- tmp = extN_get_group_desc (sb, j, &temp_buffer);
- if (tmp &&
-@@ -350,7 +356,7 @@
- /*
- * Try to place the inode in its parent directory
- */
-- i = dir->u.extN_i.i_block_group;
-+ i = EXTN_I(dir)->i_block_group;
- tmp = extN_get_group_desc (sb, i, &bh2);
- if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
- gdp = tmp;
-@@ -360,10 +366,10 @@
- * Use a quadratic hash to find a group with a
- * free inode
- */
-- for (j = 1; j < sb->u.extN_sb.s_groups_count; j <<= 1) {
-+ for (j = 1; j < sbi->s_groups_count; j <<= 1) {
- i += j;
-- if (i >= sb->u.extN_sb.s_groups_count)
-- i -= sb->u.extN_sb.s_groups_count;
-+ if (i >= sbi->s_groups_count)
-+ i -= sbi->s_groups_count;
- tmp = extN_get_group_desc (sb, i, &bh2);
- if (tmp &&
- le16_to_cpu(tmp->bg_free_inodes_count)) {
-@@ -376,9 +382,9 @@
- /*
- * That failed: try linear search for a free inode
- */
-- i = dir->u.extN_i.i_block_group + 1;
-- for (j = 2; j < sb->u.extN_sb.s_groups_count; j++) {
-- if (++i >= sb->u.extN_sb.s_groups_count)
-+ i = EXTN_I(dir)->i_block_group + 1;
-+ for (j = 2; j < sbi->s_groups_count; j++) {
-+ if (++i >= sbi->s_groups_count)
- i = 0;
- tmp = extN_get_group_desc (sb, i, &bh2);
- if (tmp &&
-@@ -399,11 +405,11 @@
- if (bitmap_nr < 0)
- goto fail;
-
-- bh = sb->u.extN_sb.s_inode_bitmap[bitmap_nr];
-+ bh = sbi->s_inode_bitmap[bitmap_nr];
-
- if ((j = extN_find_first_zero_bit ((unsigned long *) bh->b_data,
-- EXTN_INODES_PER_GROUP(sb))) <
-- EXTN_INODES_PER_GROUP(sb)) {
-+ sbi->s_inodes_per_group)) <
-+ sbi->s_inodes_per_group) {
- BUFFER_TRACE(bh, "get_write_access");
- err = extN_journal_get_write_access(handle, bh);
- if (err) goto fail;
-@@ -436,8 +442,8 @@
- }
- goto repeat;
- }
-- j += i * EXTN_INODES_PER_GROUP(sb) + 1;
-- if (j < EXTN_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) {
-+ j += i * sbi->s_inodes_per_group + 1;
-+ if (j < sbi->s_first_ino || j > le32_to_cpu(es->s_inodes_count)) {
- extN_error (sb, "extN_new_inode",
- "reserved inode or inode > inodes count - "
- "block_group = %d,inode=%d", i, j);
-@@ -457,13 +463,13 @@
- err = extN_journal_dirty_metadata(handle, bh2);
- if (err) goto fail;
-
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "get_write_access");
-- err = extN_journal_get_write_access(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(sbi->s_sbh, "get_write_access");
-+ err = extN_journal_get_write_access(handle, sbi->s_sbh);
- if (err) goto fail;
- es->s_free_inodes_count =
- cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "call extN_journal_dirty_metadata");
-- err = extN_journal_dirty_metadata(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(sbi->s_sbh, "call extN_journal_dirty_metadata");
-+ err = extN_journal_dirty_metadata(handle, sbi->s_sbh);
- sb->s_dirt = 1;
- if (err) goto fail;
-
-@@ -483,31 +489,31 @@
- inode->i_blksize = PAGE_SIZE;
- inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
-- inode->u.extN_i.i_flags = dir->u.extN_i.i_flags & ~EXTN_INDEX_FL;
-+ ei->i_flags = EXTN_I(dir)->i_flags & ~EXTN_INDEX_FL;
- if (S_ISLNK(mode))
-- inode->u.extN_i.i_flags &= ~(EXTN_IMMUTABLE_FL|EXTN_APPEND_FL);
-+ ei->i_flags &= ~(EXTN_IMMUTABLE_FL|EXTN_APPEND_FL);
- #ifdef EXTN_FRAGMENTS
-- inode->u.extN_i.i_faddr = 0;
-- inode->u.extN_i.i_frag_no = 0;
-- inode->u.extN_i.i_frag_size = 0;
-+ ei->i_faddr = 0;
-+ ei->i_frag_no = 0;
-+ ei->i_frag_size = 0;
- #endif
-- inode->u.extN_i.i_file_acl = 0;
-- inode->u.extN_i.i_dir_acl = 0;
-- inode->u.extN_i.i_dtime = 0;
-- INIT_LIST_HEAD(&inode->u.extN_i.i_orphan);
-+ ei->i_file_acl = 0;
-+ ei->i_dir_acl = 0;
-+ ei->i_dtime = 0;
-+ INIT_LIST_HEAD(&ei->i_orphan);
- #ifdef EXTN_PREALLOCATE
-- inode->u.extN_i.i_prealloc_count = 0;
-+ ei->i_prealloc_count = 0;
- #endif
-- inode->u.extN_i.i_block_group = i;
-+ ei->i_block_group = i;
-
-- if (inode->u.extN_i.i_flags & EXTN_SYNC_FL)
-+ if (ei->i_flags & EXTN_SYNC_FL)
- inode->i_flags |= S_SYNC;
- if (IS_SYNC(inode))
- handle->h_sync = 1;
- insert_inode_hash(inode);
-- inode->i_generation = sb->u.extN_sb.s_next_generation++;
-+ inode->i_generation = sbi->s_next_generation++;
-
-- inode->u.extN_i.i_state = EXTN_STATE_NEW;
-+ ei->i_state = EXTN_STATE_NEW;
- err = extN_mark_inode_dirty(handle, inode);
- if (err) goto fail;
-
-@@ -585,19 +591,19 @@
-
- unsigned long extN_count_free_inodes (struct super_block * sb)
- {
-+ struct extN_sb_info *sbi = EXTN_SB(sb);
-+ struct extN_super_block *es = sbi->s_es;
- #ifdef EXTNFS_DEBUG
-- struct extN_super_block * es;
- unsigned long desc_count, bitmap_count, x;
- int bitmap_nr;
- struct extN_group_desc * gdp;
- int i;
-
- lock_super (sb);
-- es = sb->u.extN_sb.s_es;
- desc_count = 0;
- bitmap_count = 0;
- gdp = NULL;
-- for (i = 0; i < sb->u.extN_sb.s_groups_count; i++) {
-+ for (i = 0; i < sbi->s_groups_count; i++) {
- gdp = extN_get_group_desc (sb, i, NULL);
- if (!gdp)
- continue;
-@@ -606,8 +612,8 @@
- if (bitmap_nr < 0)
- continue;
-
-- x = extN_count_free (sb->u.extN_sb.s_inode_bitmap[bitmap_nr],
-- EXTN_INODES_PER_GROUP(sb) / 8);
-+ x = extN_count_free(sbi->s_inode_bitmap[bitmap_nr],
-+ sbi->s_inodes_per_group / 8);
- printk ("group %d: stored = %d, counted = %lu\n",
- i, le16_to_cpu(gdp->bg_free_inodes_count), x);
- bitmap_count += x;
-@@ -617,7 +623,7 @@
- unlock_super (sb);
- return desc_count;
- #else
-- return le32_to_cpu(sb->u.extN_sb.s_es->s_free_inodes_count);
-+ return le32_to_cpu(es->s_free_inodes_count);
- #endif
- }
-
-@@ -626,16 +632,18 @@
- void extN_check_inodes_bitmap (struct super_block * sb)
- {
- struct extN_super_block * es;
-+ struct extN_sb_info *sbi;
- unsigned long desc_count, bitmap_count, x;
- int bitmap_nr;
- struct extN_group_desc * gdp;
- int i;
-
-- es = sb->u.extN_sb.s_es;
-+ sbi = EXTN_SB(sb);
-+ es = sbi->s_es;
- desc_count = 0;
- bitmap_count = 0;
- gdp = NULL;
-- for (i = 0; i < sb->u.extN_sb.s_groups_count; i++) {
-+ for (i = 0; i < sbi->s_groups_count; i++) {
- gdp = extN_get_group_desc (sb, i, NULL);
- if (!gdp)
- continue;
-@@ -644,7 +652,7 @@
- if (bitmap_nr < 0)
- continue;
-
-- x = extN_count_free (sb->u.extN_sb.s_inode_bitmap[bitmap_nr],
-+ x = extN_count_free (sbi->s_inode_bitmap[bitmap_nr],
- EXTN_INODES_PER_GROUP(sb) / 8);
- if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
- extN_error (sb, "extN_check_inodes_bitmap",
---- extN/extN.orig/inode.c Wed Sep 25 11:51:33 2002
-+++ extN/inode.c Wed Sep 25 11:53:07 2002
-@@ -39,6 +39,18 @@
- */
- #undef SEARCH_FROM_ZERO
-
-+/*
-+ * Test whether an inode is a fast symlink.
-+ */
-+static inline int extN_inode_is_fast_symlink(struct inode *inode)
-+{
-+ int ea_blocks = EXTN_I(inode)->i_file_acl ?
-+ (inode->i_sb->s_blocksize >> 9) : 0;
-+
-+ return (S_ISLNK(inode->i_mode) &&
-+ inode->i_blocks - ea_blocks == 0);
-+}
-+
- /* The extN forget function must perform a revoke if we are freeing data
- * which has been journaled. Metadata (eg. indirect blocks) must be
- * revoked in all cases.
-@@ -48,7 +60,7 @@
- * still needs to be revoked.
- */
-
--static int extN_forget(handle_t *handle, int is_metadata,
-+int extN_forget(handle_t *handle, int is_metadata,
- struct inode *inode, struct buffer_head *bh,
- int blocknr)
- {
-@@ -164,9 +176,7 @@
- {
- handle_t *handle;
-
-- if (is_bad_inode(inode) ||
-- inode->i_ino == EXTN_ACL_IDX_INO ||
-- inode->i_ino == EXTN_ACL_DATA_INO)
-+ if (is_bad_inode(inode))
- goto no_delete;
-
- lock_kernel();
-@@ -196,7 +206,7 @@
- * (Well, we could do this if we need to, but heck - it works)
- */
- extN_orphan_del(handle, inode);
-- inode->u.extN_i.i_dtime = CURRENT_TIME;
-+ EXTN_I(inode)->i_dtime = CURRENT_TIME;
-
- /*
- * One subtle ordering requirement: if anything has gone wrong
-@@ -220,13 +230,14 @@
- void extN_discard_prealloc (struct inode * inode)
- {
- #ifdef EXTN_PREALLOCATE
-+ struct extN_inode_info *ei = EXTN_I(inode);
- lock_kernel();
- /* Writer: ->i_prealloc* */
-- if (inode->u.extN_i.i_prealloc_count) {
-- unsigned short total = inode->u.extN_i.i_prealloc_count;
-- unsigned long block = inode->u.extN_i.i_prealloc_block;
-- inode->u.extN_i.i_prealloc_count = 0;
-- inode->u.extN_i.i_prealloc_block = 0;
-+ if (ei->i_prealloc_count) {
-+ unsigned short total = ei->i_prealloc_count;
-+ unsigned long block = ei->i_prealloc_block;
-+ ei->i_prealloc_count = 0;
-+ ei->i_prealloc_block = 0;
- /* Writer: end */
- extN_free_blocks (inode, block, total);
- }
-@@ -243,13 +254,15 @@
- unsigned long result;
-
- #ifdef EXTN_PREALLOCATE
-+ struct extN_inode_info *ei = EXTN_I(inode);
-+
- /* Writer: ->i_prealloc* */
-- if (inode->u.extN_i.i_prealloc_count &&
-- (goal == inode->u.extN_i.i_prealloc_block ||
-- goal + 1 == inode->u.extN_i.i_prealloc_block))
-+ if (ei->i_prealloc_count &&
-+ (goal == ei->i_prealloc_block ||
-+ goal + 1 == ei->i_prealloc_block))
- {
-- result = inode->u.extN_i.i_prealloc_block++;
-- inode->u.extN_i.i_prealloc_count--;
-+ result = ei->i_prealloc_block++;
-+ ei->i_prealloc_count--;
- /* Writer: end */
- extN_debug ("preallocation hit (%lu/%lu).\n",
- ++alloc_hits, ++alloc_attempts);
-@@ -259,8 +272,8 @@
- alloc_hits, ++alloc_attempts);
- if (S_ISREG(inode->i_mode))
- result = extN_new_block (inode, goal,
-- &inode->u.extN_i.i_prealloc_count,
-- &inode->u.extN_i.i_prealloc_block, err);
-+ &ei->i_prealloc_count,
-+ &ei->i_prealloc_block, err);
- else
- result = extN_new_block (inode, goal, 0, 0, err);
- /*
-@@ -394,7 +407,7 @@
-
- *err = 0;
- /* i_data is not going away, no lock needed */
-- add_chain (chain, NULL, inode->u.extN_i.i_data + *offsets);
-+ add_chain (chain, NULL, EXTN_I(inode)->i_data + *offsets);
- if (!p->key)
- goto no_block;
- while (--depth) {
-@@ -437,7 +450,8 @@
-
- static inline unsigned long extN_find_near(struct inode *inode, Indirect *ind)
- {
-- u32 *start = ind->bh ? (u32*) ind->bh->b_data : inode->u.extN_i.i_data;
-+ struct extN_inode_info *ei = EXTN_I(inode);
-+ u32 *start = ind->bh ? (u32*) ind->bh->b_data : ei->i_data;
- u32 *p;
-
- /* Try to find previous block */
-@@ -453,9 +467,8 @@
- * It is going to be refered from inode itself? OK, just put it into
- * the same cylinder group then.
- */
-- return (inode->u.extN_i.i_block_group *
-- EXTN_BLOCKS_PER_GROUP(inode->i_sb)) +
-- le32_to_cpu(inode->i_sb->u.extN_sb.s_es->s_first_data_block);
-+ return (ei->i_block_group * EXTN_BLOCKS_PER_GROUP(inode->i_sb)) +
-+ le32_to_cpu(EXTN_SB(inode->i_sb)->s_es->s_first_data_block);
- }
-
- /**
-@@ -474,14 +487,15 @@
- static int extN_find_goal(struct inode *inode, long block, Indirect chain[4],
- Indirect *partial, unsigned long *goal)
- {
-+ struct extN_inode_info *ei = EXTN_I(inode);
- /* Writer: ->i_next_alloc* */
-- if (block == inode->u.extN_i.i_next_alloc_block + 1) {
-- inode->u.extN_i.i_next_alloc_block++;
-- inode->u.extN_i.i_next_alloc_goal++;
-+ if (block == ei->i_next_alloc_block + 1) {
-+ ei->i_next_alloc_block++;
-+ ei->i_next_alloc_goal++;
- }
- #ifdef SEARCH_FROM_ZERO
-- inode->u.extN_i.i_next_alloc_block = 0;
-- inode->u.extN_i.i_next_alloc_goal = 0;
-+ ei->i_next_alloc_block = 0;
-+ ei->i_next_alloc_goal = 0;
- #endif
- /* Writer: end */
- /* Reader: pointers, ->i_next_alloc* */
-@@ -490,8 +504,8 @@
- * try the heuristic for sequential allocation,
- * failing that at least try to get decent locality.
- */
-- if (block == inode->u.extN_i.i_next_alloc_block)
-- *goal = inode->u.extN_i.i_next_alloc_goal;
-+ if (block == ei->i_next_alloc_block)
-+ *goal = ei->i_next_alloc_goal;
- if (!*goal)
- *goal = extN_find_near(inode, partial);
- #ifdef SEARCH_FROM_ZERO
-@@ -619,6 +633,7 @@
- {
- int i;
- int err = 0;
-+ struct extN_inode_info *ei = EXTN_I(inode);
-
- /*
- * If we're splicing into a [td]indirect block (as opposed to the
-@@ -641,11 +656,11 @@
- /* That's it */
-
- *where->p = where->key;
-- inode->u.extN_i.i_next_alloc_block = block;
-- inode->u.extN_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key);
-+ ei->i_next_alloc_block = block;
-+ ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);
- #ifdef SEARCH_FROM_ZERO
-- inode->u.extN_i.i_next_alloc_block = 0;
-- inode->u.extN_i.i_next_alloc_goal = 0;
-+ ei->i_next_alloc_block = 0;
-+ ei->i_next_alloc_goal = 0;
- #endif
- /* Writer: end */
-
-@@ -729,6 +744,7 @@
- unsigned long goal;
- int left;
- int depth = extN_block_to_path(inode, iblock, offsets);
-+ struct extN_inode_info *ei = EXTN_I(inode);
- loff_t new_size;
-
- J_ASSERT(handle != NULL || create == 0);
-@@ -782,7 +798,7 @@
- /*
- * Block out extN_truncate while we alter the tree
- */
-- down_read(&inode->u.extN_i.truncate_sem);
-+ down_read(&ei->truncate_sem);
- err = extN_alloc_branch(handle, inode, left, goal,
- offsets+(partial-chain), partial);
-
-@@ -794,7 +810,7 @@
- if (!err)
- err = extN_splice_branch(handle, inode, iblock, chain,
- partial, left);
-- up_read(&inode->u.extN_i.truncate_sem);
-+ up_read(&ei->truncate_sem);
- if (err == -EAGAIN)
- goto changed;
- if (err)
-@@ -807,8 +823,8 @@
- * truncate is in progress. It is racy between multiple parallel
- * instances of get_block, but we have the BKL.
- */
-- if (new_size > inode->u.extN_i.i_disksize)
-- inode->u.extN_i.i_disksize = new_size;
-+ if (new_size > ei->i_disksize)
-+ ei->i_disksize = new_size;
-
- bh_result->b_state |= (1UL << BH_New);
- goto got_it;
-@@ -921,7 +937,7 @@
- struct buffer_head *tmp_bh;
-
- for (i = 1;
-- inode->u.extN_i.i_prealloc_count &&
-+ EXTN_I(inode)->i_prealloc_count &&
- i < EXTN_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
- i++) {
- /*
-@@ -1131,8 +1147,8 @@
- kunmap(page);
- }
- }
-- if (inode->i_size > inode->u.extN_i.i_disksize) {
-- inode->u.extN_i.i_disksize = inode->i_size;
-+ if (inode->i_size > EXTN_I(inode)->i_disksize) {
-+ EXTN_I(inode)->i_disksize = inode->i_size;
- ret2 = extN_mark_inode_dirty(handle, inode);
- if (!ret)
- ret = ret2;
-@@ -1832,7 +1848,8 @@
- void extN_truncate(struct inode * inode)
- {
- handle_t *handle;
-- u32 *i_data = inode->u.extN_i.i_data;
-+ struct extN_inode_info *ei = EXTN_I(inode);
-+ u32 *i_data = EXTN_I(inode)->i_data;
- int addr_per_block = EXTN_ADDR_PER_BLOCK(inode->i_sb);
- int offsets[4];
- Indirect chain[4];
-@@ -1845,6 +1862,8 @@
- if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)))
- return;
-+ if (extN_inode_is_fast_symlink(inode))
-+ return;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- return;
-
-@@ -1884,13 +1903,13 @@
- * on-disk inode. We do this via i_disksize, which is the value which
- * extN *really* writes onto the disk inode.
- */
-- inode->u.extN_i.i_disksize = inode->i_size;
-+ ei->i_disksize = inode->i_size;
-
- /*
- * From here we block out all extN_get_block() callers who want to
- * modify the block allocation tree.
- */
-- down_write(&inode->u.extN_i.truncate_sem);
-+ down_write(&ei->truncate_sem);
-
- if (n == 1) { /* direct blocks */
- extN_free_data(handle, inode, NULL, i_data+offsets[0],
-@@ -1954,7 +1973,7 @@
- case EXTN_TIND_BLOCK:
- ;
- }
-- up_write(&inode->u.extN_i.truncate_sem);
-+ up_write(&ei->truncate_sem);
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- extN_mark_inode_dirty(handle, inode);
-
-@@ -1983,6 +2002,8 @@
-
- int extN_get_inode_loc (struct inode *inode, struct extN_iloc *iloc)
- {
-+ struct super_block *sb = inode->i_sb;
-+ struct extN_sb_info *sbi = EXTN_SB(sb);
- struct buffer_head *bh = 0;
- unsigned long block;
- unsigned long block_group;
-@@ -1992,28 +2013,22 @@
- struct extN_group_desc * gdp;
-
- if ((inode->i_ino != EXTN_ROOT_INO &&
-- inode->i_ino != EXTN_ACL_IDX_INO &&
-- inode->i_ino != EXTN_ACL_DATA_INO &&
- inode->i_ino != EXTN_JOURNAL_INO &&
-- inode->i_ino < EXTN_FIRST_INO(inode->i_sb)) ||
-- inode->i_ino > le32_to_cpu(
-- inode->i_sb->u.extN_sb.s_es->s_inodes_count)) {
-- extN_error (inode->i_sb, "extN_get_inode_loc",
-- "bad inode number: %lu", inode->i_ino);
-+ inode->i_ino < EXTN_FIRST_INO(sb)) ||
-+ inode->i_ino > le32_to_cpu(sbi->s_es->s_inodes_count)) {
-+ extN_error (sb, __FUNCTION__, "bad inode #%lu", inode->i_ino);
- goto bad_inode;
- }
-- block_group = (inode->i_ino - 1) / EXTN_INODES_PER_GROUP(inode->i_sb);
-- if (block_group >= inode->i_sb->u.extN_sb.s_groups_count) {
-- extN_error (inode->i_sb, "extN_get_inode_loc",
-- "group >= groups count");
-+ block_group = (inode->i_ino - 1) / sbi->s_inodes_per_group;
-+ if (block_group >= sbi->s_groups_count) {
-+ extN_error(sb, __FUNCTION__, "group >= groups count");
- goto bad_inode;
- }
-- group_desc = block_group >> EXTN_DESC_PER_BLOCK_BITS(inode->i_sb);
-- desc = block_group & (EXTN_DESC_PER_BLOCK(inode->i_sb) - 1);
-- bh = inode->i_sb->u.extN_sb.s_group_desc[group_desc];
-+ group_desc = block_group >> sbi->s_desc_per_block_bits;
-+ desc = block_group & (sbi->s_desc_per_block - 1);
-+ bh = sbi->s_group_desc[group_desc];
- if (!bh) {
-- extN_error (inode->i_sb, "extN_get_inode_loc",
-- "Descriptor not loaded");
-+ extN_error(sb, __FUNCTION__, "Descriptor not loaded");
- goto bad_inode;
- }
-
-@@ -2021,17 +2036,17 @@
- /*
- * Figure out the offset within the block group inode table
- */
-- offset = ((inode->i_ino - 1) % EXTN_INODES_PER_GROUP(inode->i_sb)) *
-- EXTN_INODE_SIZE(inode->i_sb);
-+ offset = ((inode->i_ino - 1) % sbi->s_inodes_per_group) *
-+ sbi->s_inode_size;
- block = le32_to_cpu(gdp[desc].bg_inode_table) +
-- (offset >> EXTN_BLOCK_SIZE_BITS(inode->i_sb));
-- if (!(bh = sb_bread(inode->i_sb, block))) {
-- extN_error (inode->i_sb, "extN_get_inode_loc",
-+ (offset >> EXTN_BLOCK_SIZE_BITS(sb));
-+ if (!(bh = sb_bread(sb, block))) {
-+ extN_error (sb, __FUNCTION__,
- "unable to read inode block - "
- "inode=%lu, block=%lu", inode->i_ino, block);
- goto bad_inode;
- }
-- offset &= (EXTN_BLOCK_SIZE(inode->i_sb) - 1);
-+ offset &= (EXTN_BLOCK_SIZE(sb) - 1);
-
- iloc->bh = bh;
- iloc->raw_inode = (struct extN_inode *) (bh->b_data + offset);
-@@ -2047,6 +2062,7 @@
- {
- struct extN_iloc iloc;
- struct extN_inode *raw_inode;
-+ struct extN_inode_info *ei = EXTN_I(inode);
- struct buffer_head *bh;
- int block;
-
-@@ -2054,7 +2070,7 @@
- goto bad_inode;
- bh = iloc.bh;
- raw_inode = iloc.raw_inode;
-- init_rwsem(&inode->u.extN_i.truncate_sem);
-+ init_rwsem(&ei->truncate_sem);
- inode->i_mode = le16_to_cpu(raw_inode->i_mode);
- inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
- inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
-@@ -2067,7 +2083,7 @@
- inode->i_atime = le32_to_cpu(raw_inode->i_atime);
- inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
- inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
-- inode->u.extN_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
-+ ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
- /* We now have enough fields to check if the inode was active or not.
- * This is needed because nfsd might try to access dead inodes
- * the test is that same one that e2fsck uses
-@@ -2075,7 +2091,7 @@
- */
- if (inode->i_nlink == 0) {
- if (inode->i_mode == 0 ||
-- !(inode->i_sb->u.extN_sb.s_mount_state & EXTN_ORPHAN_FS)) {
-+ !(EXTN_SB(inode->i_sb)->s_mount_state & EXTN_ORPHAN_FS)) {
- /* this inode is deleted */
- brelse (bh);
- goto bad_inode;
-@@ -2090,40 +2106,37 @@
- * size */
- inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
- inode->i_version = ++event;
-- inode->u.extN_i.i_flags = le32_to_cpu(raw_inode->i_flags);
-+ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
- #ifdef EXTN_FRAGMENTS
-- inode->u.extN_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
-- inode->u.extN_i.i_frag_no = raw_inode->i_frag;
-- inode->u.extN_i.i_frag_size = raw_inode->i_fsize;
-+ ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
-+ ei->i_frag_no = raw_inode->i_frag;
-+ ei->i_frag_size = raw_inode->i_fsize;
- #endif
-- inode->u.extN_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
-+ ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
- if (!S_ISREG(inode->i_mode)) {
-- inode->u.extN_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
-+ ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
- } else {
- inode->i_size |=
- ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
- }
-- inode->u.extN_i.i_disksize = inode->i_size;
-+ ei->i_disksize = inode->i_size;
- inode->i_generation = le32_to_cpu(raw_inode->i_generation);
- #ifdef EXTN_PREALLOCATE
-- inode->u.extN_i.i_prealloc_count = 0;
-+ ei->i_prealloc_count = 0;
- #endif
-- inode->u.extN_i.i_block_group = iloc.block_group;
-+ ei->i_block_group = iloc.block_group;
-
- /*
- * NOTE! The in-memory inode i_data array is in little-endian order
- * even on big-endian machines: we do NOT byteswap the block numbers!
- */
- for (block = 0; block < EXTN_N_BLOCKS; block++)
-- inode->u.extN_i.i_data[block] = iloc.raw_inode->i_block[block];
-- INIT_LIST_HEAD(&inode->u.extN_i.i_orphan);
-+ ei->i_data[block] = iloc.raw_inode->i_block[block];
-+ INIT_LIST_HEAD(&ei->i_orphan);
-
- brelse (iloc.bh);
-
-- if (inode->i_ino == EXTN_ACL_IDX_INO ||
-- inode->i_ino == EXTN_ACL_DATA_INO)
-- /* Nothing to do */ ;
-- else if (S_ISREG(inode->i_mode)) {
-+ if (S_ISREG(inode->i_mode)) {
- inode->i_op = &extN_file_inode_operations;
- inode->i_fop = &extN_file_operations;
- inode->i_mapping->a_ops = &extN_aops;
-@@ -2131,7 +2144,7 @@
- inode->i_op = &extN_dir_inode_operations;
- inode->i_fop = &extN_dir_operations;
- } else if (S_ISLNK(inode->i_mode)) {
-- if (!inode->i_blocks)
-+ if (extN_inode_is_fast_symlink(inode))
- inode->i_op = &extN_fast_symlink_inode_operations;
- else {
- inode->i_op = &page_symlink_inode_operations;
-@@ -2141,19 +2154,19 @@
- init_special_inode(inode, inode->i_mode,
- le32_to_cpu(iloc.raw_inode->i_block[0]));
- /* inode->i_attr_flags = 0; unused */
-- if (inode->u.extN_i.i_flags & EXTN_SYNC_FL) {
-+ if (ei->i_flags & EXTN_SYNC_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */
- inode->i_flags |= S_SYNC;
- }
-- if (inode->u.extN_i.i_flags & EXTN_APPEND_FL) {
-+ if (ei->i_flags & EXTN_APPEND_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_APPEND; unused */
- inode->i_flags |= S_APPEND;
- }
-- if (inode->u.extN_i.i_flags & EXTN_IMMUTABLE_FL) {
-+ if (ei->i_flags & EXTN_IMMUTABLE_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE; unused */
- inode->i_flags |= S_IMMUTABLE;
- }
-- if (inode->u.extN_i.i_flags & EXTN_NOATIME_FL) {
-+ if (ei->i_flags & EXTN_NOATIME_FL) {
- /* inode->i_attr_flags |= ATTR_FLAG_NOATIME; unused */
- inode->i_flags |= S_NOATIME;
- }
-@@ -2175,6 +2188,7 @@
- struct extN_iloc *iloc)
- {
- struct extN_inode *raw_inode = iloc->raw_inode;
-+ struct extN_inode_info *ei = EXTN_I(inode);
- struct buffer_head *bh = iloc->bh;
- int err = 0, rc, block;
-
-@@ -2192,7 +2206,7 @@
- * Fix up interoperability with old kernels. Otherwise, old inodes get
- * re-used with the upper 16 bits of the uid/gid intact
- */
-- if(!inode->u.extN_i.i_dtime) {
-+ if(!ei->i_dtime) {
- raw_inode->i_uid_high =
- cpu_to_le16(high_16_bits(inode->i_uid));
- raw_inode->i_gid_high =
-@@ -2210,34 +2224,33 @@
- raw_inode->i_gid_high = 0;
- }
- raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
-- raw_inode->i_size = cpu_to_le32(inode->u.extN_i.i_disksize);
-+ raw_inode->i_size = cpu_to_le32(ei->i_disksize);
- raw_inode->i_atime = cpu_to_le32(inode->i_atime);
- raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
- raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
- raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
-- raw_inode->i_dtime = cpu_to_le32(inode->u.extN_i.i_dtime);
-- raw_inode->i_flags = cpu_to_le32(inode->u.extN_i.i_flags);
-+ raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
-+ raw_inode->i_flags = cpu_to_le32(ei->i_flags);
- #ifdef EXTN_FRAGMENTS
-- raw_inode->i_faddr = cpu_to_le32(inode->u.extN_i.i_faddr);
-- raw_inode->i_frag = inode->u.extN_i.i_frag_no;
-- raw_inode->i_fsize = inode->u.extN_i.i_frag_size;
-+ raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
-+ raw_inode->i_frag = ei->i_frag_no;
-+ raw_inode->i_fsize = ei->i_frag_size;
- #else
- /* If we are not tracking these fields in the in-memory inode,
- * then preserve them on disk, but still initialise them to zero
- * for new inodes. */
-- if (EXTN_I(inode)->i_state & EXTN_STATE_NEW) {
-+ if (ei->i_state & EXTN_STATE_NEW) {
- raw_inode->i_faddr = 0;
- raw_inode->i_frag = 0;
- raw_inode->i_fsize = 0;
- }
- #endif
-- raw_inode->i_file_acl = cpu_to_le32(inode->u.extN_i.i_file_acl);
-+ raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
- if (!S_ISREG(inode->i_mode)) {
-- raw_inode->i_dir_acl = cpu_to_le32(inode->u.extN_i.i_dir_acl);
-+ raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
- } else {
-- raw_inode->i_size_high =
-- cpu_to_le32(inode->u.extN_i.i_disksize >> 32);
-- if (inode->u.extN_i.i_disksize > 0x7fffffffULL) {
-+ raw_inode->i_size_high = cpu_to_le32(ei->i_disksize >> 32);
-+ if (ei->i_disksize > MAX_NON_LFS) {
- struct super_block *sb = inode->i_sb;
- if (!EXTN_HAS_RO_COMPAT_FEATURE(sb,
- EXTN_FEATURE_RO_COMPAT_LARGE_FILE) ||
-@@ -2247,7 +2260,7 @@
- * created, add a flag to the superblock.
- */
- err = extN_journal_get_write_access(handle,
-- sb->u.extN_sb.s_sbh);
-+ EXTN_SB(sb)->s_sbh);
- if (err)
- goto out_brelse;
- extN_update_dynamic_rev(sb);
-@@ -2256,7 +2269,7 @@
- sb->s_dirt = 1;
- handle->h_sync = 1;
- err = extN_journal_dirty_metadata(handle,
-- sb->u.extN_sb.s_sbh);
-+ EXTN_SB(sb)->s_sbh);
- }
- }
- }
-@@ -2265,13 +2278,13 @@
- raw_inode->i_block[0] =
- cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
- else for (block = 0; block < EXTN_N_BLOCKS; block++)
-- raw_inode->i_block[block] = inode->u.extN_i.i_data[block];
-+ raw_inode->i_block[block] = ei->i_data[block];
-
- BUFFER_TRACE(bh, "call extN_journal_dirty_metadata");
- rc = extN_journal_dirty_metadata(handle, bh);
- if (!err)
- err = rc;
-- EXTN_I(inode)->i_state &= ~EXTN_STATE_NEW;
-+ ei->i_state &= ~EXTN_STATE_NEW;
-
- out_brelse:
- brelse (bh);
-@@ -2379,7 +2392,7 @@
- }
-
- error = extN_orphan_add(handle, inode);
-- inode->u.extN_i.i_disksize = attr->ia_size;
-+ EXTN_I(inode)->i_disksize = attr->ia_size;
- rc = extN_mark_inode_dirty(handle, inode);
- if (!error)
- error = rc;
-@@ -2622,9 +2635,9 @@
- */
-
- if (val)
-- inode->u.extN_i.i_flags |= EXTN_JOURNAL_DATA_FL;
-+ EXTN_I(inode)->i_flags |= EXTN_JOURNAL_DATA_FL;
- else
-- inode->u.extN_i.i_flags &= ~EXTN_JOURNAL_DATA_FL;
-+ EXTN_I(inode)->i_flags &= ~EXTN_JOURNAL_DATA_FL;
-
- journal_unlock_updates(journal);
-
---- extN/extN.orig/ioctl.c Wed Sep 25 11:51:33 2002
-+++ extN/ioctl.c Wed Sep 25 11:53:07 2002
-@@ -18,13 +18,14 @@
- int extN_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
- unsigned long arg)
- {
-+ struct extN_inode_info *ei = EXTN_I(inode);
- unsigned int flags;
-
- extN_debug ("cmd = %u, arg = %lu\n", cmd, arg);
-
- switch (cmd) {
- case EXTN_IOC_GETFLAGS:
-- flags = inode->u.extN_i.i_flags & EXTN_FL_USER_VISIBLE;
-+ flags = ei->i_flags & EXTN_FL_USER_VISIBLE;
- return put_user(flags, (int *) arg);
- case EXTN_IOC_SETFLAGS: {
- handle_t *handle = NULL;
-@@ -42,7 +43,7 @@
- if (get_user(flags, (int *) arg))
- return -EFAULT;
-
-- oldflags = inode->u.extN_i.i_flags;
-+ oldflags = ei->i_flags;
-
- /* The JOURNAL_DATA flag is modifiable only by root */
- jflag = flags & EXTN_JOURNAL_DATA_FL;
-@@ -79,7 +80,7 @@
-
- flags = flags & EXTN_FL_USER_MODIFIABLE;
- flags |= oldflags & ~EXTN_FL_USER_MODIFIABLE;
-- inode->u.extN_i.i_flags = flags;
-+ ei->i_flags = flags;
-
- if (flags & EXTN_SYNC_FL)
- inode->i_flags |= S_SYNC;
-@@ -155,12 +156,12 @@
- int ret = 0;
-
- set_current_state(TASK_INTERRUPTIBLE);
-- add_wait_queue(&sb->u.extN_sb.ro_wait_queue, &wait);
-- if (timer_pending(&sb->u.extN_sb.turn_ro_timer)) {
-+ add_wait_queue(&EXTN_SB(sb)->ro_wait_queue, &wait);
-+ if (timer_pending(&EXTN_SB(sb)->turn_ro_timer)) {
- schedule();
- ret = 1;
- }
-- remove_wait_queue(&sb->u.extN_sb.ro_wait_queue, &wait);
-+ remove_wait_queue(&EXTN_SB(sb)->ro_wait_queue, &wait);
- return ret;
- }
- #endif
---- extN/extN.orig/namei.c Wed Sep 25 11:51:34 2002
-+++ extN/namei.c Wed Sep 25 14:24:17 2002
-@@ -16,6 +16,10 @@
- * David S. Miller (davem@caip.rutgers.edu), 1995
- * Directory entry file type support and forward compatibility hooks
- * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
-+ * Hash Tree Directory indexing (c)
-+ * Daniel Phillips, 2001
-+ * Hash Tree Directory indexing porting
-+ * Christopher Li, 2002
- */
-
- #include <linux/fs.h>
-@@ -23,12 +27,13 @@
- #include <linux/sched.h>
- #include <linux/extN_fs.h>
- #include <linux/extN_jbd.h>
-+#include <linux/extN_xattr.h>
- #include <linux/fcntl.h>
- #include <linux/stat.h>
- #include <linux/string.h>
- #include <linux/locks.h>
- #include <linux/quotaops.h>
--
-+#include <linux/slab.h>
-
- /*
- * define how far ahead to read directories while searching them.
-@@ -38,6 +43,432 @@
- #define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
- #define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
-
-+static struct buffer_head *extN_append(handle_t *handle,
-+ struct inode *inode,
-+ u32 *block, int *err)
-+{
-+ struct buffer_head *bh;
-+
-+ *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
-+
-+ if ((bh = extN_bread(handle, inode, *block, 1, err))) {
-+ inode->i_size += inode->i_sb->s_blocksize;
-+ EXTN_I(inode)->i_disksize = inode->i_size;
-+ extN_journal_get_write_access(handle,bh);
-+ }
-+ return bh;
-+}
-+
-+#ifndef assert
-+#define assert(test) J_ASSERT(test)
-+#endif
-+
-+#ifndef swap
-+#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)
-+#endif
-+
-+typedef struct { u32 v; } le_u32;
-+typedef struct { u16 v; } le_u16;
-+
-+#define dxtrace_on(command) command
-+#define dxtrace_off(command)
-+#define dxtrace dxtrace_off
-+
-+struct fake_dirent
-+{
-+ /*le*/u32 inode;
-+ /*le*/u16 rec_len;
-+ u8 name_len;
-+ u8 file_type;
-+};
-+
-+struct dx_countlimit
-+{
-+ le_u16 limit;
-+ le_u16 count;
-+};
-+
-+struct dx_entry
-+{
-+ le_u32 hash;
-+ le_u32 block;
-+};
-+
-+/*
-+ * dx_root_info is laid out so that if it should somehow get overlaid by a
-+ * dirent the two low bits of the hash version will be zero. Therefore, the
-+ * hash version mod 4 should never be 0. Sincerely, the paranoia department.
-+ */
-+
-+struct dx_root
-+{
-+ struct fake_dirent dot;
-+ char dot_name[4];
-+ struct fake_dirent dotdot;
-+ char dotdot_name[4];
-+ struct dx_root_info
-+ {
-+ le_u32 reserved_zero;
-+ u8 hash_version; /* 0 now, 1 at release */
-+ u8 info_length; /* 8 */
-+ u8 indirect_levels;
-+ u8 unused_flags;
-+ }
-+ info;
-+ struct dx_entry entries[0];
-+};
-+
-+struct dx_node
-+{
-+ struct fake_dirent fake;
-+ struct dx_entry entries[0];
-+};
-+
-+
-+struct dx_frame
-+{
-+ struct buffer_head *bh;
-+ struct dx_entry *entries;
-+ struct dx_entry *at;
-+};
-+
-+struct dx_map_entry
-+{
-+ u32 hash;
-+ u32 offs;
-+};
-+
-+typedef struct extN_dir_entry_2 extN_dirent;
-+static inline unsigned dx_get_block (struct dx_entry *entry);
-+static void dx_set_block (struct dx_entry *entry, unsigned value);
-+static inline unsigned dx_get_hash (struct dx_entry *entry);
-+static void dx_set_hash (struct dx_entry *entry, unsigned value);
-+static unsigned dx_get_count (struct dx_entry *entries);
-+static unsigned dx_get_limit (struct dx_entry *entries);
-+static void dx_set_count (struct dx_entry *entries, unsigned value);
-+static void dx_set_limit (struct dx_entry *entries, unsigned value);
-+static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
-+static unsigned dx_node_limit (struct inode *dir);
-+static unsigned dx_hack_hash (const u8 *name, int len);
-+static struct dx_frame *dx_probe (struct inode *dir, u32 hash, struct dx_frame *frame);
-+static void dx_release (struct dx_frame *frames);
-+static int dx_make_map (extN_dirent *de, int size, struct dx_map_entry map[]);
-+static void dx_sort_map(struct dx_map_entry *map, unsigned count);
-+static extN_dirent *dx_copy_dirents (char *from, char *to,
-+ struct dx_map_entry *map, int count);
-+static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
-+
-+
-+#ifdef CONFIG_EXTN_INDEX
-+/*
-+ * Future: use high four bits of block for coalesce-on-delete flags
-+ * Mask them off for now.
-+ */
-+
-+static inline unsigned dx_get_block (struct dx_entry *entry)
-+{
-+ return le32_to_cpu(entry->block.v) & 0x00ffffff;
-+}
-+
-+static inline void dx_set_block (struct dx_entry *entry, unsigned value)
-+{
-+ entry->block.v = cpu_to_le32(value);
-+}
-+
-+static inline unsigned dx_get_hash (struct dx_entry *entry)
-+{
-+ return le32_to_cpu(entry->hash.v);
-+}
-+
-+static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
-+{
-+ entry->hash.v = cpu_to_le32(value);
-+}
-+
-+static inline unsigned dx_get_count (struct dx_entry *entries)
-+{
-+ return le16_to_cpu(((struct dx_countlimit *) entries)->count.v);
-+}
-+
-+static inline unsigned dx_get_limit (struct dx_entry *entries)
-+{
-+ return le16_to_cpu(((struct dx_countlimit *) entries)->limit.v);
-+}
-+
-+static inline void dx_set_count (struct dx_entry *entries, unsigned value)
-+{
-+ ((struct dx_countlimit *) entries)->count.v = cpu_to_le16(value);
-+}
-+
-+static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
-+{
-+ ((struct dx_countlimit *) entries)->limit.v = cpu_to_le16(value);
-+}
-+
-+static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
-+{
-+ unsigned entry_space = dir->i_sb->s_blocksize - EXTN_DIR_REC_LEN(1) -
-+ EXTN_DIR_REC_LEN(2) - infosize;
-+ return 0? 20: entry_space / sizeof(struct dx_entry);
-+}
-+
-+static inline unsigned dx_node_limit (struct inode *dir)
-+{
-+ unsigned entry_space = dir->i_sb->s_blocksize - EXTN_DIR_REC_LEN(0);
-+ return 0? 22: entry_space / sizeof(struct dx_entry);
-+}
-+
-+/* Hash function - not bad, but still looking for an ideal default */
-+
-+static unsigned dx_hack_hash (const u8 *name, int len)
-+{
-+ u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
-+ while (len--)
-+ {
-+ u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
-+ if (hash & 0x80000000) hash -= 0x7fffffff;
-+ hash1 = hash0;
-+ hash0 = hash;
-+ }
-+ return hash0;
-+}
-+
-+#define dx_hash(s,n) (dx_hack_hash(s,n) << 1)
-+
-+/*
-+ * Debug
-+ */
-+static void dx_show_index (char * label, struct dx_entry *entries)
-+{
-+ int i, n = dx_get_count (entries);
-+ printk("%s index ", label);
-+ for (i = 0; i < n; i++)
-+ {
-+ printk("%x->%u ", i? dx_get_hash(entries + i): 0, dx_get_block(entries + i));
-+ }
-+ printk("\n");
-+}
-+
-+struct stats
-+{
-+ unsigned names;
-+ unsigned space;
-+ unsigned bcount;
-+};
-+
-+static struct stats dx_show_leaf (extN_dirent *de, int size, int show_names)
-+{
-+ unsigned names = 0, space = 0;
-+ char *base = (char *) de;
-+ printk("names: ");
-+ while ((char *) de < base + size)
-+ {
-+ if (de->inode)
-+ {
-+ if (show_names)
-+ {
-+ int len = de->name_len;
-+ char *name = de->name;
-+ while (len--) printk("%c", *name++);
-+ printk(":%x.%u ", dx_hash (de->name, de->name_len), ((char *) de - base));
-+ }
-+ space += EXTN_DIR_REC_LEN(de->name_len);
-+ names++;
-+ }
-+ de = (extN_dirent *) ((char *) de + le16_to_cpu(de->rec_len));
-+ }
-+ printk("(%i)\n", names);
-+ return (struct stats) { names, space, 1 };
-+}
-+
-+struct stats dx_show_entries (struct inode *dir, struct dx_entry *entries, int levels)
-+{
-+ unsigned blocksize = dir->i_sb->s_blocksize;
-+ unsigned count = dx_get_count (entries), names = 0, space = 0, i;
-+ unsigned bcount = 0;
-+ struct buffer_head *bh;
-+ int err;
-+ printk("%i indexed blocks...\n", count);
-+ for (i = 0; i < count; i++, entries++)
-+ {
-+ u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0;
-+ u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;
-+ struct stats stats;
-+ printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range);
-+ if (!(bh = extN_bread (NULL,dir, block, 0,&err))) continue;
-+ stats = levels?
-+ dx_show_entries (dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):
-+ dx_show_leaf ((extN_dirent *) bh->b_data, blocksize, 0);
-+ names += stats.names;
-+ space += stats.space;
-+ bcount += stats.bcount;
-+ brelse (bh);
-+ }
-+ if (bcount)
-+ printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ",
-+ names, space/bcount,(space/bcount)*100/blocksize);
-+ return (struct stats) { names, space, bcount};
-+}
-+
-+/*
-+ * Probe for a directory leaf block to search
-+ */
-+
-+static struct dx_frame *
-+dx_probe(struct inode *dir, u32 hash, struct dx_frame *frame_in)
-+{
-+ unsigned count, indirect;
-+ struct dx_entry *at, *entries, *p, *q, *m;
-+ struct dx_root *root;
-+ struct buffer_head *bh;
-+ struct dx_frame *frame = frame_in;
-+ int err;
-+
-+ frame->bh = NULL;
-+ if (!(bh = extN_bread(NULL, dir, 0, 0, &err)))
-+ goto fail;
-+ root = (struct dx_root *) bh->b_data;
-+ if (root->info.hash_version > 0 || root->info.unused_flags & 1) {
-+ brelse(bh);
-+ goto fail;
-+ }
-+ if ((indirect = root->info.indirect_levels) > 1) {
-+ brelse(bh);
-+ goto fail;
-+ }
-+ entries = (struct dx_entry *) (((char *) &root->info) + root->info.info_length);
-+ assert (dx_get_limit(entries) == dx_root_limit(dir, root->info.info_length));
-+ dxtrace (printk("Look up %x", hash));
-+ while (1)
-+ {
-+ count = dx_get_count(entries);
-+ assert (count && count <= dx_get_limit(entries));
-+ p = entries + 1;
-+ q = entries + count - 1;
-+ while (p <= q)
-+ {
-+ m = p + (q - p)/2;
-+ dxtrace(printk("."));
-+ if (dx_get_hash(m) > hash)
-+ q = m - 1;
-+ else
-+ p = m + 1;
-+ }
-+
-+ if (0) // linear search cross check
-+ {
-+ unsigned n = count - 1;
-+ at = entries;
-+ while (n--)
-+ {
-+ dxtrace(printk(","));
-+ if (dx_get_hash(++at) > hash)
-+ {
-+ at--;
-+ break;
-+ }
-+ }
-+ assert (at == p - 1);
-+ }
-+
-+ at = p - 1;
-+ dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
-+ frame->bh = bh;
-+ frame->entries = entries;
-+ frame->at = at;
-+ if (!indirect--) return frame;
-+ if (!(bh = extN_bread (NULL,dir, dx_get_block(at), 0,&err)))
-+ goto fail2;
-+ at = entries = ((struct dx_node *) bh->b_data)->entries;
-+ assert (dx_get_limit(entries) == dx_node_limit (dir));
-+ frame++;
-+ }
-+fail2:
-+ while (frame >= frame_in) {
-+ brelse(frame->bh);
-+ frame--;
-+ }
-+fail:
-+ return NULL;
-+}
-+
-+static void dx_release (struct dx_frame *frames)
-+{
-+ if (frames[0].bh == NULL)
-+ return;
-+
-+ if (((struct dx_root *)frames[0].bh->b_data)->info.indirect_levels)
-+ brelse (frames[1].bh);
-+ brelse (frames[0].bh);
-+}
-+
-+/*
-+ * Directory block splitting, compacting
-+ */
-+
-+static int dx_make_map (extN_dirent *de, int size, struct dx_map_entry map[])
-+{
-+ int count = 0;
-+ char *base = (char *) de;
-+ while ((char *) de < base + size)
-+ {
-+ map[count].hash = dx_hash (de->name, de->name_len);
-+ map[count].offs = (u32) ((char *) de - base);
-+ de = (extN_dirent *) ((char *) de + le16_to_cpu(de->rec_len));
-+ count++;
-+ }
-+ return count;
-+}
-+
-+static void dx_sort_map (struct dx_map_entry *map, unsigned count)
-+{
-+ struct dx_map_entry *p, *q, *top = map + count - 1;
-+ int more;
-+ /* Combsort until bubble sort doesn't suck */
-+ while (count > 2)
-+ {
-+ count = count*10/13;
-+ if (count - 9 < 2) /* 9, 10 -> 11 */
-+ count = 11;
-+ for (p = top, q = p - count; q >= map; p--, q--)
-+ if (p->hash < q->hash)
-+ swap(*p, *q);
-+ }
-+ /* Garden variety bubble sort */
-+ do {
-+ more = 0;
-+ q = top;
-+ while (q-- > map)
-+ {
-+ if (q[1].hash >= q[0].hash)
-+ continue;
-+ swap(*(q+1), *q);
-+ more = 1;
-+ }
-+ } while(more);
-+}
-+
-+static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
-+{
-+ struct dx_entry *entries = frame->entries;
-+ struct dx_entry *old = frame->at, *new = old + 1;
-+ int count = dx_get_count(entries);
-+
-+ assert(count < dx_get_limit(entries));
-+ assert(old < entries + count);
-+ memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
-+ dx_set_hash(new, hash);
-+ dx_set_block(new, block);
-+ dx_set_count(entries, count + 1);
-+}
-+#endif
-+
-+static void extN_update_dx_flag(struct inode *inode)
-+{
-+ if (!test_opt(inode->i_sb, INDEX))
-+ EXTN_I(inode)->i_flags &= ~EXTN_INDEX_FL;
-+}
-+
- /*
- * NOTE! unlike strncmp, extN_match returns 1 for success, 0 for failure.
- *
-@@ -95,6 +526,15 @@
- }
-
- /*
-+ * p is at least 6 bytes before the end of page
-+ */
-+static inline extN_dirent *extN_next_entry(extN_dirent *p)
-+{
-+ return (extN_dirent *)((char*)p + le16_to_cpu(p->rec_len));
-+}
-+
-+
-+/*
- * extN_find_entry()
- *
- * finds an entry in the specified directory with the wanted name. It
-@@ -105,6 +545,8 @@
- * The returned buffer_head has ->b_count elevated. The caller is expected
- * to brelse() it when appropriate.
- */
-+
-+
- static struct buffer_head * extN_find_entry (struct dentry *dentry,
- struct extN_dir_entry_2 ** res_dir)
- {
-@@ -119,12 +561,78 @@
- int num = 0;
- int nblocks, i, err;
- struct inode *dir = dentry->d_parent->d_inode;
-+ int namelen;
-+ const u8 *name;
-+ unsigned blocksize;
-+ extN_dirent *de, *top;
-
- *res_dir = NULL;
- sb = dir->i_sb;
-+ blocksize = sb->s_blocksize;
-+ namelen = dentry->d_name.len;
-+ name = dentry->d_name.name;
-+ if (namelen > EXTN_NAME_LEN)
-+ return NULL;
-+ if (extN_dx && is_dx(dir)) {
-+ u32 hash = dx_hash (name, namelen);
-+ struct dx_frame frames[2], *frame;
-+ if (!(frame = dx_probe (dir, hash, frames)))
-+ return NULL;
-+dxnext:
-+ block = dx_get_block(frame->at);
-+ if (!(bh = extN_bread (NULL,dir, block, 0, &err)))
-+ goto dxfail;
-+ de = (extN_dirent *) bh->b_data;
-+ top = (extN_dirent *) ((char *) de + blocksize -
-+ EXTN_DIR_REC_LEN(0));
-+ for (; de < top; de = extN_next_entry(de))
-+ if (extN_match (namelen, name, de)) {
-+ if (!extN_check_dir_entry("extN_find_entry",
-+ dir, de, bh,
-+ (block<<EXTN_BLOCK_SIZE_BITS(sb))
-+ +((char *)de - bh->b_data))) {
-+ brelse (bh);
-+ goto dxfail;
-+ }
-+ *res_dir = de;
-+ goto dxfound;
-+ }
-+ brelse (bh);
-+ /* Same hash continues in next block? Search on. */
-+ if (++(frame->at) == frame->entries + dx_get_count(frame->entries))
-+ {
-+ struct buffer_head *bh2;
-+ if (frame == frames)
-+ goto dxfail;
-+ if (++(frames->at) == frames->entries + dx_get_count(frames->entries))
-+ goto dxfail;
-+ /* should omit read if not continued */
-+ if (!(bh2 = extN_bread (NULL, dir,
-+ dx_get_block(frames->at),
-+ 0, &err)))
-+ goto dxfail;
-+ brelse (frame->bh);
-+ frame->bh = bh2;
-+ frame->at = frame->entries = ((struct dx_node *) bh2->b_data)->entries;
-+ /* Subtle: the 0th entry has the count, find the hash in frame above */
-+ if ((dx_get_hash(frames->at) & -2) == hash)
-+ goto dxnext;
-+ goto dxfail;
-+ }
-+ if ((dx_get_hash(frame->at) & -2) == hash)
-+ goto dxnext;
-+dxfail:
-+ dxtrace(printk("%s not found\n", name));
-+ dx_release (frames);
-+ return NULL;
-+dxfound:
-+ dx_release (frames);
-+ return bh;
-
-+ }
-+
- nblocks = dir->i_size >> EXTN_BLOCK_SIZE_BITS(sb);
-- start = dir->u.extN_i.i_dir_start_lookup;
-+ start = EXTN_I(dir)->i_dir_start_lookup;
- if (start >= nblocks)
- start = 0;
- block = start;
-@@ -165,7 +673,7 @@
- i = search_dirblock(bh, dir, dentry,
- block << EXTN_BLOCK_SIZE_BITS(sb), res_dir);
- if (i == 1) {
-- dir->u.extN_i.i_dir_start_lookup = block;
-+ EXTN_I(dir)->i_dir_start_lookup = block;
- ret = bh;
- goto cleanup_and_exit;
- } else {
-@@ -237,6 +745,92 @@
- de->file_type = extN_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
- }
-
-+static extN_dirent *
-+dx_copy_dirents (char *from, char *to, struct dx_map_entry *map, int count)
-+{
-+ unsigned rec_len = 0;
-+
-+ while (count--) {
-+ extN_dirent *de = (extN_dirent *) (from + map->offs);
-+ rec_len = EXTN_DIR_REC_LEN(de->name_len);
-+ memcpy (to, de, rec_len);
-+ ((extN_dirent *) to)->rec_len = rec_len;
-+ to += rec_len;
-+ map++;
-+ }
-+ return (extN_dirent *) (to - rec_len);
-+}
-+
-+#ifdef CONFIG_EXTN_INDEX
-+static extN_dirent *do_split(handle_t *handle, struct inode *dir,
-+ struct buffer_head **bh,struct dx_frame *frame,
-+ u32 hash, int *error)
-+{
-+ unsigned blocksize = dir->i_sb->s_blocksize;
-+ unsigned count, continued;
-+ struct buffer_head *bh2;
-+ u32 newblock;
-+ unsigned MAX_DX_MAP = PAGE_CACHE_SIZE/EXTN_DIR_REC_LEN(1) + 1;
-+ u32 hash2;
-+ struct dx_map_entry *map;
-+ char *data1 = (*bh)->b_data, *data2, *data3;
-+ unsigned split;
-+ extN_dirent *de, *de2;
-+
-+ bh2 = extN_append (handle, dir, &newblock, error);
-+ if (!(bh2))
-+ {
-+ brelse(*bh);
-+ *bh = NULL;
-+ return (extN_dirent *)bh2;
-+ }
-+
-+ BUFFER_TRACE(*bh, "get_write_access");
-+ extN_journal_get_write_access(handle, *bh);
-+ BUFFER_TRACE(frame->bh, "get_write_access");
-+ extN_journal_get_write_access(handle, frame->bh);
-+
-+ data2 = bh2->b_data;
-+
-+ map = kmalloc(sizeof(*map) * MAX_DX_MAP, GFP_KERNEL);
-+ if (!map)
-+ panic("no memory for do_split\n");
-+ count = dx_make_map ((extN_dirent *) data1, blocksize, map);
-+ split = count/2; // need to adjust to actual middle
-+ dx_sort_map (map, count);
-+ hash2 = map[split].hash;
-+ continued = hash2 == map[split - 1].hash;
-+ dxtrace(printk("Split block %i at %x, %i/%i\n",
-+ dx_get_block(frame->at), hash2, split, count-split));
-+
-+ /* Fancy dance to stay within two buffers */
-+ de2 = dx_copy_dirents (data1, data2, map + split, count - split);
-+ data3 = (char *) de2 + de2->rec_len;
-+ de = dx_copy_dirents (data1, data3, map, split);
-+ memcpy(data1, data3, (char *) de + de->rec_len - data3);
-+ de = (extN_dirent *) ((char *) de - data3 + data1); // relocate de
-+ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
-+ de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
-+ dxtrace(dx_show_leaf ((extN_dirent *) data1, blocksize, 1));
-+ dxtrace(dx_show_leaf ((extN_dirent *) data2, blocksize, 1));
-+
-+ /* Which block gets the new entry? */
-+ if (hash >= hash2)
-+ {
-+ swap(*bh, bh2);
-+ de = de2;
-+ }
-+ dx_insert_block (frame, hash2 + continued, newblock);
-+ extN_journal_dirty_metadata (handle, bh2);
-+ brelse (bh2);
-+ extN_journal_dirty_metadata (handle, frame->bh);
-+ dxtrace(dx_show_index ("frame", frame->entries));
-+ kfree(map);
-+ return de;
-+}
-+#endif
-+
-+
- /*
- * extN_add_entry()
- *
-@@ -251,6 +845,7 @@
- /*
- * AKPM: the journalling code here looks wrong on the error paths
- */
-+
- static int extN_add_entry (handle_t *handle, struct dentry *dentry,
- struct inode *inode)
- {
-@@ -258,117 +853,281 @@
- const char *name = dentry->d_name.name;
- int namelen = dentry->d_name.len;
- unsigned long offset;
-- unsigned short rec_len;
- struct buffer_head * bh;
-- struct extN_dir_entry_2 * de, * de1;
-- struct super_block * sb;
-+ extN_dirent *de;
-+ struct super_block * sb = dir->i_sb;
- int retval;
-+ unsigned short reclen = EXTN_DIR_REC_LEN(namelen);
-
-- sb = dir->i_sb;
-+ unsigned blocksize = sb->s_blocksize;
-+ unsigned nlen, rlen;
-+ u32 block, blocks;
-+ char *top;
-
- if (!namelen)
- return -EINVAL;
-- bh = extN_bread (handle, dir, 0, 0, &retval);
-- if (!bh)
-- return retval;
-- rec_len = EXTN_DIR_REC_LEN(namelen);
-- offset = 0;
-- de = (struct extN_dir_entry_2 *) bh->b_data;
-- while (1) {
-- if ((char *)de >= sb->s_blocksize + bh->b_data) {
-- brelse (bh);
-- bh = NULL;
-- bh = extN_bread (handle, dir,
-- offset >> EXTN_BLOCK_SIZE_BITS(sb), 1, &retval);
-- if (!bh)
-- return retval;
-- if (dir->i_size <= offset) {
-- if (dir->i_size == 0) {
-- brelse(bh);
-- return -ENOENT;
-+ if (extN_dx && is_dx(dir)) {
-+ struct dx_frame frames[2], *frame;
-+ struct dx_entry *entries, *at;
-+ u32 hash;
-+ char *data1;
-+
-+ hash = dx_hash(name, namelen);
-+ /* FIXME: do something if dx_probe() fails here */
-+ frame = dx_probe(dir, hash, frames);
-+ entries = frame->entries;
-+ at = frame->at;
-+
-+ if (!(bh = extN_bread(handle,dir, dx_get_block(at), 0,&retval)))
-+ goto dxfail1;
-+
-+ BUFFER_TRACE(bh, "get_write_access");
-+ extN_journal_get_write_access(handle, bh);
-+
-+ data1 = bh->b_data;
-+ de = (extN_dirent *) data1;
-+ top = data1 + (0? 200: blocksize);
-+ while ((char *) de < top)
-+ {
-+ /* FIXME: check EEXIST and dir */
-+ nlen = EXTN_DIR_REC_LEN(de->name_len);
-+ rlen = le16_to_cpu(de->rec_len);
-+ if ((de->inode? rlen - nlen: rlen) >= reclen)
-+ goto dx_add;
-+ de = (extN_dirent *) ((char *) de + rlen);
-+ }
-+ /* Block full, should compress but for now just split */
-+ dxtrace(printk("using %u of %u node entries\n",
-+ dx_get_count(entries), dx_get_limit(entries)));
-+ /* Need to split index? */
-+ if (dx_get_count(entries) == dx_get_limit(entries))
-+ {
-+ u32 newblock;
-+ unsigned icount = dx_get_count(entries);
-+ int levels = frame - frames;
-+ struct dx_entry *entries2;
-+ struct dx_node *node2;
-+ struct buffer_head *bh2;
-+ if (levels && dx_get_count(frames->entries) == dx_get_limit(frames->entries))
-+ goto dxfull;
-+ bh2 = extN_append (handle, dir, &newblock, &retval);
-+ if (!(bh2))
-+ goto dxfail2;
-+ node2 = (struct dx_node *)(bh2->b_data);
-+ entries2 = node2->entries;
-+ node2->fake.rec_len = cpu_to_le16(blocksize);
-+ node2->fake.inode = 0;
-+ BUFFER_TRACE(frame->bh, "get_write_access");
-+ extN_journal_get_write_access(handle, frame->bh);
-+ if (levels)
-+ {
-+ unsigned icount1 = icount/2, icount2 = icount - icount1;
-+ unsigned hash2 = dx_get_hash(entries + icount1);
-+ dxtrace(printk("Split index %i/%i\n", icount1, icount2));
-+
-+ BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
-+ extN_journal_get_write_access(handle, frames[0].bh);
-+
-+ memcpy ((char *) entries2, (char *) (entries + icount1),
-+ icount2 * sizeof(struct dx_entry));
-+ dx_set_count (entries, icount1);
-+ dx_set_count (entries2, icount2);
-+ dx_set_limit (entries2, dx_node_limit(dir));
-+
-+ /* Which index block gets the new entry? */
-+ if (at - entries >= icount1) {
-+ frame->at = at = at - entries - icount1 + entries2;
-+ frame->entries = entries = entries2;
-+ swap(frame->bh, bh2);
- }
--
-- extN_debug ("creating next block\n");
--
-- BUFFER_TRACE(bh, "get_write_access");
-- extN_journal_get_write_access(handle, bh);
-- de = (struct extN_dir_entry_2 *) bh->b_data;
-- de->inode = 0;
-- de->rec_len = le16_to_cpu(sb->s_blocksize);
-- dir->u.extN_i.i_disksize =
-- dir->i_size = offset + sb->s_blocksize;
-- dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-- extN_mark_inode_dirty(handle, dir);
-+ dx_insert_block (frames + 0, hash2, newblock);
-+ dxtrace(dx_show_index ("node", frames[1].entries));
-+ dxtrace(dx_show_index ("node",
-+ ((struct dx_node *) bh2->b_data)->entries));
-+ extN_journal_dirty_metadata(handle, bh2);
-+ brelse (bh2);
- } else {
--
-- extN_debug ("skipping to next block\n");
--
-- de = (struct extN_dir_entry_2 *) bh->b_data;
-+ dxtrace(printk("Creating second level index...\n"));
-+ memcpy((char *) entries2, (char *) entries,
-+ icount * sizeof(struct dx_entry));
-+ dx_set_limit(entries2, dx_node_limit(dir));
-+
-+ /* Set up root */
-+ dx_set_count(entries, 1);
-+ dx_set_block(entries + 0, newblock);
-+ ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
-+
-+ /* Add new access path frame */
-+ frame = frames + 1;
-+ frame->at = at = at - entries + entries2;
-+ frame->entries = entries = entries2;
-+ frame->bh = bh2;
-+ extN_journal_get_write_access(handle, frame->bh);
- }
-+ extN_journal_dirty_metadata(handle, frames[0].bh);
- }
-- if (!extN_check_dir_entry ("extN_add_entry", dir, de, bh,
-- offset)) {
-- brelse (bh);
-- return -ENOENT;
-- }
-- if (extN_match (namelen, name, de)) {
-+ de = do_split(handle, dir, &bh, frame, hash, &retval);
-+ dx_release (frames);
-+ if (!(de))
-+ goto fail;
-+ nlen = EXTN_DIR_REC_LEN(de->name_len);
-+ rlen = le16_to_cpu(de->rec_len);
-+ goto add;
-+
-+dx_add:
-+ dx_release (frames);
-+ goto add;
-+
-+dxfull:
-+ extN_warning(sb, __FUNCTION__, "Directory index full!\n");
-+ retval = -ENOSPC;
-+dxfail2:
-+ brelse(bh);
-+dxfail1:
-+ dx_release (frames);
-+ goto fail1;
-+ }
-+
-+ blocks = dir->i_size >> sb->s_blocksize_bits;
-+ for (block = 0, offset = 0; block < blocks; block++) {
-+ bh = extN_bread(handle, dir, block, 0, &retval);
-+ if(!bh)
-+ return retval;
-+ de = (extN_dirent *)bh->b_data;
-+ top = bh->b_data + blocksize - reclen;
-+ while ((char *) de <= top) {
-+ if (!extN_check_dir_entry("extN_add_entry", dir, de,
-+ bh, offset)) {
-+ brelse (bh);
-+ return -EIO;
-+ }
-+ if (extN_match (namelen, name, de)) {
- brelse (bh);
- return -EEXIST;
-- }
-- if ((le32_to_cpu(de->inode) == 0 &&
-- le16_to_cpu(de->rec_len) >= rec_len) ||
-- (le16_to_cpu(de->rec_len) >=
-- EXTN_DIR_REC_LEN(de->name_len) + rec_len)) {
-- BUFFER_TRACE(bh, "get_write_access");
-- extN_journal_get_write_access(handle, bh);
-- /* By now the buffer is marked for journaling */
-- offset += le16_to_cpu(de->rec_len);
-- if (le32_to_cpu(de->inode)) {
-- de1 = (struct extN_dir_entry_2 *) ((char *) de +
-- EXTN_DIR_REC_LEN(de->name_len));
-- de1->rec_len =
-- cpu_to_le16(le16_to_cpu(de->rec_len) -
-- EXTN_DIR_REC_LEN(de->name_len));
-- de->rec_len = cpu_to_le16(
-- EXTN_DIR_REC_LEN(de->name_len));
-- de = de1;
- }
-- de->file_type = EXTN_FT_UNKNOWN;
-- if (inode) {
-- de->inode = cpu_to_le32(inode->i_ino);
-- extN_set_de_type(dir->i_sb, de, inode->i_mode);
-- } else
-- de->inode = 0;
-- de->name_len = namelen;
-- memcpy (de->name, name, namelen);
-- /*
-- * XXX shouldn't update any times until successful
-- * completion of syscall, but too many callers depend
-- * on this.
-- *
-- * XXX similarly, too many callers depend on
-- * extN_new_inode() setting the times, but error
-- * recovery deletes the inode, so the worst that can
-- * happen is that the times are slightly out of date
-- * and/or different from the directory change time.
-- */
-- dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-- dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-- extN_mark_inode_dirty(handle, dir);
-- dir->i_version = ++event;
-- BUFFER_TRACE(bh, "call extN_journal_dirty_metadata");
-- extN_journal_dirty_metadata(handle, bh);
-+ nlen = EXTN_DIR_REC_LEN(de->name_len);
-+ rlen = le16_to_cpu(de->rec_len);
-+ if ((de->inode? rlen - nlen: rlen) >= reclen)
-+ goto add;
-+ de = (extN_dirent *)((char *)de + rlen);
-+ offset += rlen;
-+ }
-+ if (extN_dx && blocks == 1 && test_opt(sb, INDEX))
-+ goto dx_make_index;
-+ brelse(bh);
-+ }
-+ bh = extN_append(handle, dir, &block, &retval);
-+ if (!bh)
-+ return retval;
-+ de = (extN_dirent *) bh->b_data;
-+ de->inode = 0;
-+ de->rec_len = cpu_to_le16(rlen = blocksize);
-+ nlen = 0;
-+ goto add;
-+
-+add:
-+ BUFFER_TRACE(bh, "get_write_access");
-+ extN_journal_get_write_access(handle, bh);
-+ /* By now the buffer is marked for journaling */
-+ if (de->inode) {
-+ extN_dirent *de1 = (extN_dirent *)((char *)de + nlen);
-+ de1->rec_len = cpu_to_le16(rlen - nlen);
-+ de->rec_len = cpu_to_le16(nlen);
-+ de = de1;
-+ }
-+ de->file_type = EXTN_FT_UNKNOWN;
-+ if (inode) {
-+ de->inode = cpu_to_le32(inode->i_ino);
-+ extN_set_de_type(dir->i_sb, de, inode->i_mode);
-+ } else
-+ de->inode = 0;
-+ de->name_len = namelen;
-+ memcpy (de->name, name, namelen);
-+ /*
-+ * XXX shouldn't update any times until successful
-+ * completion of syscall, but too many callers depend
-+ * on this.
-+ *
-+ * XXX similarly, too many callers depend on
-+ * extN_new_inode() setting the times, but error
-+ * recovery deletes the inode, so the worst that can
-+ * happen is that the times are slightly out of date
-+ * and/or different from the directory change time.
-+ */
-+ dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-+ extN_update_dx_flag(dir);
-+ dir->i_version = ++event;
-+ extN_mark_inode_dirty(handle, dir);
-+ BUFFER_TRACE(bh, "call extN_journal_dirty_metadata");
-+ extN_journal_dirty_metadata(handle, bh);
-+ brelse(bh);
-+ return 0;
-+
-+dx_make_index:
-+ {
-+ struct buffer_head *bh2;
-+ struct dx_root *root;
-+ struct dx_frame frames[2], *frame;
-+ struct dx_entry *entries;
-+ extN_dirent *de2;
-+ char *data1;
-+ unsigned len;
-+ u32 hash;
-+
-+ dxtrace(printk("Creating index\n"));
-+ extN_journal_get_write_access(handle, bh);
-+ root = (struct dx_root *) bh->b_data;
-+
-+ EXTN_I(dir)->i_flags |= EXTN_INDEX_FL;
-+ bh2 = extN_append (handle, dir, &block, &retval);
-+ if (!(bh2))
-+ {
- brelse(bh);
-- return 0;
-+ return retval;
- }
-- offset += le16_to_cpu(de->rec_len);
-- de = (struct extN_dir_entry_2 *)
-- ((char *) de + le16_to_cpu(de->rec_len));
-+ data1 = bh2->b_data;
-+
-+ /* The 0th block becomes the root, move the dirents out */
-+ de = (extN_dirent *) &root->info;
-+ len = ((char *) root) + blocksize - (char *) de;
-+ memcpy (data1, de, len);
-+ de = (extN_dirent *) data1;
-+ top = data1 + len;
-+ while (((char *) de2=(char*)de+le16_to_cpu(de->rec_len)) < top)
-+ de = de2;
-+ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
-+ /* Initialize the root; the dot dirents already exist */
-+ de = (extN_dirent *) (&root->dotdot);
-+ de->rec_len = cpu_to_le16(blocksize - EXTN_DIR_REC_LEN(2));
-+ memset (&root->info, 0, sizeof(root->info));
-+ root->info.info_length = sizeof(root->info);
-+ entries = root->entries;
-+ dx_set_block (entries, 1);
-+ dx_set_count (entries, 1);
-+ dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
-+
-+ /* Initialize as for dx_probe */
-+ hash = dx_hash (name, namelen);
-+ frame = frames;
-+ frame->entries = entries;
-+ frame->at = entries;
-+ frame->bh = bh;
-+ bh = bh2;
-+ de = do_split(handle,dir, &bh, frame, hash, &retval);
-+ dx_release (frames);
-+ if (!(de))
-+ return retval;
-+ nlen = EXTN_DIR_REC_LEN(de->name_len);
-+ rlen = le16_to_cpu(de->rec_len);
-+ goto add;
- }
-- brelse (bh);
-- return -ENOSPC;
-+fail1:
-+ return retval;
-+fail:
-+ return -ENOENT;
- }
-
-+
- /*
- * extN_delete_entry deletes a directory entry by merging it with the
- * previous entry
-@@ -451,7 +1210,8 @@
- struct inode * inode;
- int err;
-
-- handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS + 3);
-+ handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS +
-+ EXTN_INDEX_EXTRA_TRANS_BLOCKS + 3);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
-@@ -464,8 +1224,10 @@
- inode->i_op = &extN_file_inode_operations;
- inode->i_fop = &extN_file_operations;
- inode->i_mapping->a_ops = &extN_aops;
-- extN_mark_inode_dirty(handle, inode);
- err = extN_add_nondir(handle, dentry, inode);
-+ if (err)
-+ extN_xattr_drop_inode(handle, inode);
-+ extN_mark_inode_dirty(handle, inode);
- }
- extN_journal_stop(handle, dir);
- return err;
-@@ -478,7 +1240,8 @@
- struct inode *inode;
- int err;
-
-- handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS + 3);
-+ handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS +
-+ EXTN_INDEX_EXTRA_TRANS_BLOCKS + 3);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
-@@ -489,8 +1252,10 @@
- err = PTR_ERR(inode);
- if (!IS_ERR(inode)) {
- init_special_inode(inode, mode, rdev);
-- extN_mark_inode_dirty(handle, inode);
- err = extN_add_nondir(handle, dentry, inode);
-+ if (err)
-+ extN_xattr_drop_inode(handle, inode);
-+ extN_mark_inode_dirty(handle, inode);
- }
- extN_journal_stop(handle, dir);
- return err;
-@@ -507,22 +1272,22 @@
- if (dir->i_nlink >= EXTN_LINK_MAX)
- return -EMLINK;
-
-- handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS + 3);
-+ handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS +
-+ EXTN_INDEX_EXTRA_TRANS_BLOCKS + 3);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
- if (IS_SYNC(dir))
- handle->h_sync = 1;
-
-- inode = extN_new_inode (handle, dir, S_IFDIR);
-+ inode = extN_new_inode (handle, dir, S_IFDIR | mode);
- err = PTR_ERR(inode);
- if (IS_ERR(inode))
- goto out_stop;
-
- inode->i_op = &extN_dir_inode_operations;
- inode->i_fop = &extN_dir_operations;
-- inode->i_size = inode->u.extN_i.i_disksize = inode->i_sb->s_blocksize;
-- inode->i_blocks = 0;
-+ inode->i_size = EXTN_I(inode)->i_disksize = inode->i_sb->s_blocksize;
- dir_block = extN_bread (handle, inode, 0, 1, &err);
- if (!dir_block) {
- inode->i_nlink--; /* is this nlink == 0? */
-@@ -549,15 +1314,12 @@
- BUFFER_TRACE(dir_block, "call extN_journal_dirty_metadata");
- extN_journal_dirty_metadata(handle, dir_block);
- brelse (dir_block);
-- inode->i_mode = S_IFDIR | mode;
-- if (dir->i_mode & S_ISGID)
-- inode->i_mode |= S_ISGID;
- extN_mark_inode_dirty(handle, inode);
- err = extN_add_entry (handle, dentry, inode);
- if (err)
- goto out_no_entry;
- dir->i_nlink++;
-- dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-+ extN_update_dx_flag(dir);
- extN_mark_inode_dirty(handle, dir);
- d_instantiate(dentry, inode);
- out_stop:
-@@ -565,6 +1327,7 @@
- return err;
-
- out_no_entry:
-+ extN_xattr_drop_inode(handle, inode);
- inode->i_nlink = 0;
- extN_mark_inode_dirty(handle, inode);
- iput (inode);
-@@ -655,7 +1418,7 @@
- int err = 0, rc;
-
- lock_super(sb);
-- if (!list_empty(&inode->u.extN_i.i_orphan))
-+ if (!list_empty(&EXTN_I(inode)->i_orphan))
- goto out_unlock;
-
- /* Orphan handling is only valid for files with data blocks
-@@ -670,8 +1433,8 @@
- J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
- S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
-
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "get_write_access");
-- err = extN_journal_get_write_access(handle, sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(EXTN_SB(sb)->s_sbh, "get_write_access");
-+ err = extN_journal_get_write_access(handle, EXTN_SB(sb)->s_sbh);
- if (err)
- goto out_unlock;
-
-@@ -682,7 +1445,7 @@
- /* Insert this inode at the head of the on-disk orphan list... */
- NEXT_ORPHAN(inode) = le32_to_cpu(EXTN_SB(sb)->s_es->s_last_orphan);
- EXTN_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
-- err = extN_journal_dirty_metadata(handle, sb->u.extN_sb.s_sbh);
-+ err = extN_journal_dirty_metadata(handle, EXTN_SB(sb)->s_sbh);
- rc = extN_mark_iloc_dirty(handle, inode, &iloc);
- if (!err)
- err = rc;
-@@ -696,7 +1459,7 @@
- * This is safe: on error we're going to ignore the orphan list
- * anyway on the next recovery. */
- if (!err)
-- list_add(&inode->u.extN_i.i_orphan, &EXTN_SB(sb)->s_orphan);
-+ list_add(&EXTN_I(inode)->i_orphan, &EXTN_SB(sb)->s_orphan);
-
- jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);
- jbd_debug(4, "orphan inode %ld will point to %d\n",
-@@ -714,25 +1477,25 @@
- int extN_orphan_del(handle_t *handle, struct inode *inode)
- {
- struct list_head *prev;
-+ struct extN_inode_info *ei = EXTN_I(inode);
- struct extN_sb_info *sbi;
- ino_t ino_next;
- struct extN_iloc iloc;
- int err = 0;
-
- lock_super(inode->i_sb);
-- if (list_empty(&inode->u.extN_i.i_orphan)) {
-+ if (list_empty(&ei->i_orphan)) {
- unlock_super(inode->i_sb);
- return 0;
- }
-
- ino_next = NEXT_ORPHAN(inode);
-- prev = inode->u.extN_i.i_orphan.prev;
-+ prev = ei->i_orphan.prev;
- sbi = EXTN_SB(inode->i_sb);
-
- jbd_debug(4, "remove inode %ld from orphan list\n", inode->i_ino);
-
-- list_del(&inode->u.extN_i.i_orphan);
-- INIT_LIST_HEAD(&inode->u.extN_i.i_orphan);
-+ list_del_init(&ei->i_orphan);
-
- /* If we're on an error path, we may not have a valid
- * transaction handle with which to update the orphan list on
-@@ -755,9 +1518,8 @@
- err = extN_journal_dirty_metadata(handle, sbi->s_sbh);
- } else {
- struct extN_iloc iloc2;
-- struct inode *i_prev =
-- list_entry(prev, struct inode, u.extN_i.i_orphan);
--
-+ struct inode *i_prev = orphan_list_entry(prev);
-+
- jbd_debug(4, "orphan inode %ld will point to %ld\n",
- i_prev->i_ino, ino_next);
- err = extN_reserve_inode_write(handle, i_prev, &iloc2);
-@@ -832,7 +1594,7 @@
- extN_mark_inode_dirty(handle, inode);
- dir->i_nlink--;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-- dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-+ extN_update_dx_flag(dir);
- extN_mark_inode_dirty(handle, dir);
-
- end_rmdir:
-@@ -878,7 +1640,7 @@
- if (retval)
- goto end_unlink;
- dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-- dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-+ extN_update_dx_flag(dir);
- extN_mark_inode_dirty(handle, dir);
- inode->i_nlink--;
- if (!inode->i_nlink)
-@@ -904,7 +1666,8 @@
- if (l > dir->i_sb->s_blocksize)
- return -ENAMETOOLONG;
-
-- handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS + 5);
-+ handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS +
-+ EXTN_INDEX_EXTRA_TRANS_BLOCKS + 5);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
-@@ -916,7 +1679,7 @@
- if (IS_ERR(inode))
- goto out_stop;
-
-- if (l > sizeof (inode->u.extN_i.i_data)) {
-+ if (l > sizeof(EXTN_I(inode)->i_data)) {
- inode->i_op = &page_symlink_inode_operations;
- inode->i_mapping->a_ops = &extN_aops;
- /*
-@@ -929,10 +1692,10 @@
- goto out_no_entry;
- } else {
- inode->i_op = &extN_fast_symlink_inode_operations;
-- memcpy((char*)&inode->u.extN_i.i_data,symname,l);
-+ memcpy((char*)&EXTN_I(inode)->i_data,symname,l);
- inode->i_size = l-1;
- }
-- inode->u.extN_i.i_disksize = inode->i_size;
-+ EXTN_I(inode)->i_disksize = inode->i_size;
- extN_mark_inode_dirty(handle, inode);
- err = extN_add_nondir(handle, dentry, inode);
- out_stop:
-@@ -959,7 +1722,8 @@
- if (inode->i_nlink >= EXTN_LINK_MAX)
- return -EMLINK;
-
-- handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS);
-+ handle = extN_journal_start(dir, EXTN_DATA_TRANS_BLOCKS +
-+ EXTN_INDEX_EXTRA_TRANS_BLOCKS);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
-@@ -995,7 +1759,8 @@
-
- old_bh = new_bh = dir_bh = NULL;
-
-- handle = extN_journal_start(old_dir, 2 * EXTN_DATA_TRANS_BLOCKS + 2);
-+ handle = extN_journal_start(old_dir, 2 * EXTN_DATA_TRANS_BLOCKS +
-+ EXTN_INDEX_EXTRA_TRANS_BLOCKS + 2);
- if (IS_ERR(handle))
- return PTR_ERR(handle);
-
-@@ -1077,7 +1842,7 @@
- new_inode->i_ctime = CURRENT_TIME;
- }
- old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-- old_dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-+ extN_update_dx_flag(old_dir);
- if (dir_bh) {
- BUFFER_TRACE(dir_bh, "get_write_access");
- extN_journal_get_write_access(handle, dir_bh);
-@@ -1089,7 +1854,7 @@
- new_inode->i_nlink--;
- } else {
- new_dir->i_nlink++;
-- new_dir->u.extN_i.i_flags &= ~EXTN_INDEX_FL;
-+ extN_update_dx_flag(new_dir);
- extN_mark_inode_dirty(handle, new_dir);
- }
- }
---- extN/extN.orig/super.c Wed Sep 25 11:51:34 2002
-+++ extN/super.c Wed Sep 25 11:53:07 2002
-@@ -24,6 +24,7 @@
- #include <linux/jbd.h>
- #include <linux/extN_fs.h>
- #include <linux/extN_jbd.h>
-+#include <linux/extN_xattr.h>
- #include <linux/slab.h>
- #include <linux/init.h>
- #include <linux/locks.h>
-@@ -121,7 +122,7 @@
- /* If no overrides were specified on the mount, then fall back
- * to the default behaviour set in the filesystem's superblock
- * on disk. */
-- switch (le16_to_cpu(sb->u.extN_sb.s_es->s_errors)) {
-+ switch (le16_to_cpu(EXTN_SB(sb)->s_es->s_errors)) {
- case EXTN_ERRORS_PANIC:
- return EXTN_ERRORS_PANIC;
- case EXTN_ERRORS_RO:
-@@ -269,9 +270,9 @@
- return;
-
- printk (KERN_CRIT "Remounting filesystem read-only\n");
-- sb->u.extN_sb.s_mount_state |= EXTN_ERROR_FS;
-+ EXTN_SB(sb)->s_mount_state |= EXTN_ERROR_FS;
- sb->s_flags |= MS_RDONLY;
-- sb->u.extN_sb.s_mount_opt |= EXTN_MOUNT_ABORT;
-+ EXTN_SB(sb)->s_mount_opt |= EXTN_MOUNT_ABORT;
- journal_abort(EXTN_SB(sb)->s_journal, -EIO);
- }
-
-@@ -377,8 +378,6 @@
- return ret;
- }
-
--#define orphan_list_entry(l) list_entry((l), struct inode, u.extN_i.i_orphan)
--
- static void dump_orphan_list(struct super_block *sb, struct extN_sb_info *sbi)
- {
- struct list_head *l;
-@@ -404,6 +403,7 @@
- kdev_t j_dev = sbi->s_journal->j_dev;
- int i;
-
-+ extN_xattr_put_super(sb);
- journal_destroy(sbi->s_journal);
- if (!(sb->s_flags & MS_RDONLY)) {
- EXTN_CLEAR_INCOMPAT_FEATURE(sb, EXTN_FEATURE_INCOMPAT_RECOVER);
-@@ -529,6 +529,12 @@
- "EXTN Check option not supported\n");
- #endif
- }
-+ else if (!strcmp (this_char, "index"))
-+#ifdef CONFIG_EXTN_INDEX
-+ set_opt (*mount_options, INDEX);
-+#else
-+ printk("EXTN index option not supported\n");
-+#endif
- else if (!strcmp (this_char, "debug"))
- set_opt (*mount_options, DEBUG);
- else if (!strcmp (this_char, "errors")) {
-@@ -702,6 +708,12 @@
- es->s_mtime = cpu_to_le32(CURRENT_TIME);
- extN_update_dynamic_rev(sb);
- EXTN_SET_INCOMPAT_FEATURE(sb, EXTN_FEATURE_INCOMPAT_RECOVER);
-+
-+ if (test_opt(sb, INDEX))
-+ EXTN_SET_COMPAT_FEATURE(sb, EXTN_FEATURE_COMPAT_DIR_INDEX);
-+ else if (EXTN_HAS_COMPAT_FEATURE(sb, EXTN_FEATURE_COMPAT_DIR_INDEX))
-+ set_opt (EXTN_SB(sb)->s_mount_opt, INDEX);
-+
- extN_commit_super (sb, es, 1);
- if (test_opt (sb, DEBUG))
- printk (KERN_INFO
-@@ -818,7 +830,7 @@
- sb->s_flags &= ~MS_RDONLY;
- }
-
-- if (sb->u.extN_sb.s_mount_state & EXTN_ERROR_FS) {
-+ if (EXTN_SB(sb)->s_mount_state & EXTN_ERROR_FS) {
- if (es->s_last_orphan)
- jbd_debug(1, "Errors on filesystem, "
- "clearing orphan list.\n");
-@@ -1334,10 +1346,10 @@
- printk(KERN_ERR "EXTN-fs: I/O error on journal device\n");
- goto out_journal;
- }
-- if (ntohl(journal->j_superblock->s_nr_users) != 1) {
-+ if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) {
- printk(KERN_ERR "EXTN-fs: External journal has more than one "
- "user (unsupported) - %d\n",
-- ntohl(journal->j_superblock->s_nr_users));
-+ be32_to_cpu(journal->j_superblock->s_nr_users));
- goto out_journal;
- }
- EXTN_SB(sb)->journal_bdev = bdev;
-@@ -1463,12 +1475,14 @@
- struct extN_super_block * es,
- int sync)
- {
-+ struct buffer_head *sbh = EXTN_SB(sb)->s_sbh;
-+
- es->s_wtime = cpu_to_le32(CURRENT_TIME);
-- BUFFER_TRACE(sb->u.extN_sb.s_sbh, "marking dirty");
-- mark_buffer_dirty(sb->u.extN_sb.s_sbh);
-+ BUFFER_TRACE(sbh, "marking dirty");
-+ mark_buffer_dirty(sbh);
- if (sync) {
-- ll_rw_block(WRITE, 1, &sb->u.extN_sb.s_sbh);
-- wait_on_buffer(sb->u.extN_sb.s_sbh);
-+ ll_rw_block(WRITE, 1, &sbh);
-+ wait_on_buffer(sbh);
- }
- }
-
-@@ -1519,7 +1533,7 @@
- extN_warning(sb, __FUNCTION__, "Marking fs in need of "
- "filesystem check.");
-
-- sb->u.extN_sb.s_mount_state |= EXTN_ERROR_FS;
-+ EXTN_SB(sb)->s_mount_state |= EXTN_ERROR_FS;
- es->s_state |= cpu_to_le16(EXTN_ERROR_FS);
- extN_commit_super (sb, es, 1);
-
-@@ -1734,14 +1748,25 @@
-
- static DECLARE_FSTYPE_DEV(extN_fs_type, "extN", extN_read_super);
-
--static int __init init_extN_fs(void)
-+static void exit_extN_fs(void)
- {
-- return register_filesystem(&extN_fs_type);
-+ unregister_filesystem(&extN_fs_type);
-+ exit_extN_xattr_user();
-+ exit_extN_xattr();
- }
-
--static void __exit exit_extN_fs(void)
-+static int __init init_extN_fs(void)
- {
-- unregister_filesystem(&extN_fs_type);
-+ int error = init_extN_xattr();
-+ if (!error)
-+ error = init_extN_xattr_user();
-+ if (!error)
-+ error = register_filesystem(&extN_fs_type);
-+ if (!error)
-+ return 0;
-+
-+ exit_extN_fs();
-+ return error;
- }
-
- EXPORT_SYMBOL(extN_bread);
---- extN/extN.orig/symlink.c Wed Sep 25 11:51:34 2002
-+++ extN/symlink.c Wed Sep 25 11:53:07 2002
-@@ -23,14 +23,14 @@
-
- static int extN_readlink(struct dentry *dentry, char *buffer, int buflen)
- {
-- char *s = (char *)dentry->d_inode->u.extN_i.i_data;
-- return vfs_readlink(dentry, buffer, buflen, s);
-+ struct extN_inode_info *ei = EXTN_I(dentry->d_inode);
-+ return vfs_readlink(dentry, buffer, buflen, (char *)ei->i_data);
- }
-
- static int extN_follow_link(struct dentry *dentry, struct nameidata *nd)
- {
-- char *s = (char *)dentry->d_inode->u.extN_i.i_data;
-- return vfs_follow_link(nd, s);
-+ struct extN_inode_info *ei = EXTN_I(dentry->d_inode);
-+ return vfs_follow_link(nd, (char*)ei->i_data);
- }
-
- struct inode_operations extN_fast_symlink_inode_operations = {
---- extN/extN-include.orig/extN_fs.h Wed Sep 25 11:51:34 2002
-+++ include/linux/extN_fs.h Wed Sep 25 14:13:38 2002
-@@ -17,6 +17,8 @@
- #define _LINUX_EXTN_FS_H
-
- #include <linux/types.h>
-+#include <linux/extN_fs_sb.h>
-+#include <linux/extN_fs_i.h>
-
- /*
- * The second extended filesystem constants/structures
-@@ -58,8 +60,6 @@
- */
- #define EXTN_BAD_INO 1 /* Bad blocks inode */
- #define EXTN_ROOT_INO 2 /* Root inode */
--#define EXTN_ACL_IDX_INO 3 /* ACL inode */
--#define EXTN_ACL_DATA_INO 4 /* ACL inode */
- #define EXTN_BOOT_LOADER_INO 5 /* Boot loader inode */
- #define EXTN_UNDEL_DIR_INO 6 /* Undelete directory inode */
- #define EXTN_RESIZE_INO 7 /* Reserved group descriptors inode */
-@@ -84,23 +84,25 @@
- #define EXTN_MIN_BLOCK_SIZE 1024
- #define EXTN_MAX_BLOCK_SIZE 4096
- #define EXTN_MIN_BLOCK_LOG_SIZE 10
-+
- #ifdef __KERNEL__
--# define EXTN_BLOCK_SIZE(s) ((s)->s_blocksize)
--#else
--# define EXTN_BLOCK_SIZE(s) (EXTN_MIN_BLOCK_SIZE << (s)->s_log_block_size)
--#endif
--#define EXTN_ACLE_PER_BLOCK(s) (EXTN_BLOCK_SIZE(s) / sizeof (struct extN_acl_entry))
--#define EXTN_ADDR_PER_BLOCK(s) (EXTN_BLOCK_SIZE(s) / sizeof (__u32))
--#ifdef __KERNEL__
--# define EXTN_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
--#else
--# define EXTN_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
--#endif
--#ifdef __KERNEL__
--#define EXTN_ADDR_PER_BLOCK_BITS(s) ((s)->u.extN_sb.s_addr_per_block_bits)
--#define EXTN_INODE_SIZE(s) ((s)->u.extN_sb.s_inode_size)
--#define EXTN_FIRST_INO(s) ((s)->u.extN_sb.s_first_ino)
-+#define EXTN_SB(sb) ((struct extN_sb_info *)&((sb)->u.generic_sbp))
-+#define EXTN_I(inode) ((struct extN_inode_info *)&((inode)->u.generic_ip))
-+
-+#define EXTN_BLOCK_SIZE(s) ((s)->s_blocksize)
-+#define EXTN_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
-+#define EXTN_ADDR_PER_BLOCK_BITS(s) (EXTN_SB(s)->s_addr_per_block_bits)
-+#define EXTN_INODE_SIZE(s) (EXTN_SB(s)->s_inode_size)
-+#define EXTN_FIRST_INO(s) (EXTN_SB(s)->s_first_ino)
- #else
-+
-+/* Assume that user mode programs are passing in an extNfs superblock, not
-+ * a kernel struct super_block. This will allow us to call the feature-test
-+ * macros from user land. */
-+#define EXTN_SB(sb) (sb)
-+
-+#define EXTN_BLOCK_SIZE(s) (EXTN_MIN_BLOCK_SIZE << (s)->s_log_block_size)
-+#define EXTN_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
- #define EXTN_INODE_SIZE(s) (((s)->s_rev_level == EXTN_GOOD_OLD_REV) ? \
- EXTN_GOOD_OLD_INODE_SIZE : \
- (s)->s_inode_size)
-@@ -108,6 +110,7 @@
- EXTN_GOOD_OLD_FIRST_INO : \
- (s)->s_first_ino)
- #endif
-+#define EXTN_ADDR_PER_BLOCK(s) (EXTN_BLOCK_SIZE(s) / sizeof (__u32))
-
- /*
- * Macro-instructions used to manage fragments
-@@ -116,36 +119,14 @@
- #define EXTN_MAX_FRAG_SIZE 4096
- #define EXTN_MIN_FRAG_LOG_SIZE 10
- #ifdef __KERNEL__
--# define EXTN_FRAG_SIZE(s) ((s)->u.extN_sb.s_frag_size)
--# define EXTN_FRAGS_PER_BLOCK(s) ((s)->u.extN_sb.s_frags_per_block)
-+# define EXTN_FRAG_SIZE(s) (EXTN_SB(s)->s_frag_size)
-+# define EXTN_FRAGS_PER_BLOCK(s) (EXTN_SB(s)->s_frags_per_block)
- #else
- # define EXTN_FRAG_SIZE(s) (EXTN_MIN_FRAG_SIZE << (s)->s_log_frag_size)
- # define EXTN_FRAGS_PER_BLOCK(s) (EXTN_BLOCK_SIZE(s) / EXTN_FRAG_SIZE(s))
- #endif
-
- /*
-- * ACL structures
-- */
--struct extN_acl_header /* Header of Access Control Lists */
--{
-- __u32 aclh_size;
-- __u32 aclh_file_count;
-- __u32 aclh_acle_count;
-- __u32 aclh_first_acle;
--};
--
--struct extN_acl_entry /* Access Control List Entry */
--{
-- __u32 acle_size;
-- __u16 acle_perms; /* Access permissions */
-- __u16 acle_type; /* Type of entry */
-- __u16 acle_tag; /* User or group identity */
-- __u16 acle_pad1;
-- __u32 acle_next; /* Pointer on next entry for the */
-- /* same inode or on next free entry */
--};
--
--/*
- * Structure of a blocks group descriptor
- */
- struct extN_group_desc
-@@ -163,15 +144,13 @@
- /*
- * Macro-instructions used to manage group descriptors
- */
-+# define EXTN_BLOCKS_PER_GROUP(s) (EXTN_SB(s)->s_blocks_per_group)
-+# define EXTN_INODES_PER_GROUP(s) (EXTN_SB(s)->s_inodes_per_group)
- #ifdef __KERNEL__
--# define EXTN_BLOCKS_PER_GROUP(s) ((s)->u.extN_sb.s_blocks_per_group)
--# define EXTN_DESC_PER_BLOCK(s) ((s)->u.extN_sb.s_desc_per_block)
--# define EXTN_INODES_PER_GROUP(s) ((s)->u.extN_sb.s_inodes_per_group)
--# define EXTN_DESC_PER_BLOCK_BITS(s) ((s)->u.extN_sb.s_desc_per_block_bits)
-+# define EXTN_DESC_PER_BLOCK(s) (EXTN_SB(s)->s_desc_per_block)
-+# define EXTN_DESC_PER_BLOCK_BITS(s) (EXTN_SB(s)->s_desc_per_block_bits)
- #else
--# define EXTN_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
- # define EXTN_DESC_PER_BLOCK(s) (EXTN_BLOCK_SIZE(s) / sizeof (struct extN_group_desc))
--# define EXTN_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
- #endif
-
- /*
-@@ -339,12 +318,13 @@
- #define EXTN_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */
- #define EXTN_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */
- #define EXTN_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */
-+#define EXTN_MOUNT_INDEX 0x4000 /* Enable directory index */
-
- /* Compatibility, for having both ext2_fs.h and extN_fs.h included at once */
- #ifndef _LINUX_EXT2_FS_H
- #define clear_opt(o, opt) o &= ~EXTN_MOUNT_##opt
- #define set_opt(o, opt) o |= EXTN_MOUNT_##opt
--#define test_opt(sb, opt) ((sb)->u.extN_sb.s_mount_opt & \
-+#define test_opt(sb, opt) (EXTN_SB(sb)->s_mount_opt & \
- EXTN_MOUNT_##opt)
- #else
- #define EXT2_MOUNT_NOLOAD EXTN_MOUNT_NOLOAD
-@@ -441,17 +421,13 @@
- /*EC*/ __u32 s_reserved[197]; /* Padding to the end of the block */
- };
-
--#ifdef __KERNEL__
--#define EXTN_SB(sb) (&((sb)->u.extN_sb))
--#define EXTN_I(inode) (&((inode)->u.extN_i))
--#else
--/* Assume that user mode programs are passing in an extNfs superblock, not
-- * a kernel struct super_block. This will allow us to call the feature-test
-- * macros from user land. */
--#define EXTN_SB(sb) (sb)
--#endif
--
--#define NEXT_ORPHAN(inode) (inode)->u.extN_i.i_dtime
-+#define NEXT_ORPHAN(inode) EXTN_I(inode)->i_dtime
-+static inline struct inode *orphan_list_entry(struct list_head *l)
-+{
-+ return ((struct inode *)((char *)l -
-+ (unsigned long)(offsetof(struct inode, u.generic_ip) +
-+ offsetof(struct extN_inode_info, i_orphan))));
-+}
-
- /*
- * Codes for operating systems
-@@ -512,7 +488,7 @@
- #define EXTN_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
- #define EXTN_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
-
--#define EXTN_FEATURE_COMPAT_SUPP 0
-+#define EXTN_FEATURE_COMPAT_SUPP EXTN_FEATURE_COMPAT_EXT_ATTR
- #define EXTN_FEATURE_INCOMPAT_SUPP (EXTN_FEATURE_INCOMPAT_FILETYPE| \
- EXTN_FEATURE_INCOMPAT_RECOVER)
- #define EXTN_FEATURE_RO_COMPAT_SUPP (EXTN_FEATURE_RO_COMPAT_SPARSE_SUPER| \
-@@ -575,6 +551,24 @@
- #define EXTN_DIR_ROUND (EXTN_DIR_PAD - 1)
- #define EXTN_DIR_REC_LEN(name_len) (((name_len) + 8 + EXTN_DIR_ROUND) & \
- ~EXTN_DIR_ROUND)
-+/*
-+ * Hash Tree Directory indexing
-+ * (c) Daniel Phillips, 2001
-+ */
-+
-+#define CONFIG_EXTN_INDEX
-+
-+#ifdef CONFIG_EXTN_INDEX
-+ enum {extN_dx = 1};
-+ #define is_dx(dir) (EXTN_I(dir)->i_flags & EXTN_INDEX_FL)
-+#define EXTN_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXTN_LINK_MAX)
-+#define EXTN_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
-+#else
-+ enum {extN_dx = 0};
-+ #define is_dx(dir) 0
-+#define EXTN_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXTN_LINK_MAX)
-+#define EXTN_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
-+#endif
-
- #ifdef __KERNEL__
- /*
-@@ -587,6 +581,24 @@
- unsigned long block_group;
- };
-
-+/* Defined for extended attributes */
-+#define CONFIG_EXTN_FS_XATTR y
-+#ifndef ENOATTR
-+#define ENOATTR ENODATA /* No such attribute */
-+#endif
-+#ifndef ENOTSUP
-+#define ENOTSUP EOPNOTSUPP /* Operation not supported */
-+#endif
-+#ifndef XATTR_NAME_MAX
-+#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */
-+#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */
-+#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
-+#endif
-+#ifndef XATTR_CREATE
-+#define XATTR_CREATE 1 /* set value, fail if attr already exists */
-+#define XATTR_REPLACE 2 /* set value, fail if attr does not exist */
-+#endif
-+
- /*
- * Function prototypes
- */
-@@ -628,6 +640,7 @@
- extern unsigned long extN_count_free (struct buffer_head *, unsigned);
-
- /* inode.c */
-+extern int extN_forget(handle_t *, int, struct inode *, struct buffer_head *, int);
- extern struct buffer_head * extN_getblk (handle_t *, struct inode *, long, int, int *);
- extern struct buffer_head * extN_bread (handle_t *, struct inode *, int, int, int *);
-
---- extN/extN-include.orig/extN_jbd.h Wed Sep 25 11:51:34 2002
-+++ include/linux/extN_jbd.h Wed Sep 25 11:53:07 2002
-@@ -30,13 +30,19 @@
-
- #define EXTN_SINGLEDATA_TRANS_BLOCKS 8
-
-+/* Extended attributes may touch two data buffers, two bitmap buffers,
-+ * and two group and summaries. */
-+
-+#define EXTN_XATTR_TRANS_BLOCKS 8
-+
- /* Define the minimum size for a transaction which modifies data. This
- * needs to take into account the fact that we may end up modifying two
- * quota files too (one for the group, one for the user quota). The
- * superblock only gets updated once, of course, so don't bother
- * counting that again for the quota updates. */
-
--#define EXTN_DATA_TRANS_BLOCKS (3 * EXTN_SINGLEDATA_TRANS_BLOCKS - 2)
-+#define EXTN_DATA_TRANS_BLOCKS (3 * EXTN_SINGLEDATA_TRANS_BLOCKS + \
-+ EXTN_XATTR_TRANS_BLOCKS - 2)
-
- extern int extN_writepage_trans_blocks(struct inode *inode);
-
-@@ -63,6 +69,8 @@
-
- #define EXTN_RESERVE_TRANS_BLOCKS 12
-
-+#define EXTN_INDEX_EXTRA_TRANS_BLOCKS 8
-+
- int
- extN_mark_iloc_dirty(handle_t *handle,
- struct inode *inode,
-@@ -289,7 +297,7 @@
- return 1;
- if (test_opt(inode->i_sb, DATA_FLAGS) == EXTN_MOUNT_JOURNAL_DATA)
- return 1;
-- if (inode->u.extN_i.i_flags & EXTN_JOURNAL_DATA_FL)
-+ if (EXTN_I(inode)->i_flags & EXTN_JOURNAL_DATA_FL)
- return 1;
- return 0;
- }
---- /dev/null Tue Aug 6 08:46:29 2002
-+++ include/linux/xattr.h Wed Sep 25 11:51:34 2002
-@@ -0,0 +1,15 @@
-+/*
-+ File: linux/xattr.h
-+
-+ Extended attributes handling.
-+
-+ Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
-+ Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
-+*/
-+#ifndef _LINUX_XATTR_H
-+#define _LINUX_XATTR_H
-+
-+#define XATTR_CREATE 1 /* set value, fail if attr already exists */
-+#define XATTR_REPLACE 2 /* set value, fail if attr does not exist */
-+
-+#endif /* _LINUX_XATTR_H */
---- /dev/null Tue Aug 6 08:46:29 2002
-+++ include/linux/extN_xattr.h Wed Sep 25 11:51:34 2002
-@@ -0,0 +1,155 @@
-+/*
-+ File: linux/extN_xattr.h
-+
-+ On-disk format of extended attributes for the extN filesystem.
-+
-+ (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
-+*/
-+
-+#include <linux/config.h>
-+#include <linux/init.h>
-+#include <linux/xattr.h>
-+
-+/* Magic value in attribute blocks */
-+#define EXTN_XATTR_MAGIC 0xEA020000
-+
-+/* Maximum number of references to one attribute block */
-+#define EXTN_XATTR_REFCOUNT_MAX 1024
-+
-+/* Name indexes */
-+#define EXTN_XATTR_INDEX_MAX 10
-+#define EXTN_XATTR_INDEX_USER 1
-+
-+struct extN_xattr_header {
-+ __u32 h_magic; /* magic number for identification */
-+ __u32 h_refcount; /* reference count */
-+ __u32 h_blocks; /* number of disk blocks used */
-+ __u32 h_hash; /* hash value of all attributes */
-+ __u32 h_reserved[4]; /* zero right now */
-+};
-+
-+struct extN_xattr_entry {
-+ __u8 e_name_len; /* length of name */
-+ __u8 e_name_index; /* attribute name index */
-+ __u16 e_value_offs; /* offset in disk block of value */
-+ __u32 e_value_block; /* disk block attribute is stored on (n/i) */
-+ __u32 e_value_size; /* size of attribute value */
-+ __u32 e_hash; /* hash value of name and value */
-+ char e_name[0]; /* attribute name */
-+};
-+
-+#define EXTN_XATTR_PAD_BITS 2
-+#define EXTN_XATTR_PAD (1<<EXTN_XATTR_PAD_BITS)
-+#define EXTN_XATTR_ROUND (EXTN_XATTR_PAD-1)
-+#define EXTN_XATTR_LEN(name_len) \
-+ (((name_len) + EXTN_XATTR_ROUND + \
-+ sizeof(struct extN_xattr_entry)) & ~EXTN_XATTR_ROUND)
-+#define EXTN_XATTR_NEXT(entry) \
-+ ( (struct extN_xattr_entry *)( \
-+ (char *)(entry) + EXTN_XATTR_LEN((entry)->e_name_len)) )
-+#define EXTN_XATTR_SIZE(size) \
-+ (((size) + EXTN_XATTR_ROUND) & ~EXTN_XATTR_ROUND)
-+
-+#ifdef __KERNEL__
-+
-+# ifdef CONFIG_EXTN_FS_XATTR
-+
-+struct extN_xattr_handler {
-+ char *prefix;
-+ size_t (*list)(char *list, struct inode *inode, const char *name,
-+ int name_len);
-+ int (*get)(struct inode *inode, const char *name, void *buffer,
-+ size_t size);
-+ int (*set)(struct inode *inode, const char *name, void *buffer,
-+ size_t size, int flags);
-+};
-+
-+extern int extN_xattr_register(int, struct extN_xattr_handler *);
-+extern void extN_xattr_unregister(int, struct extN_xattr_handler *);
-+
-+extern int extN_setxattr(struct dentry *, const char *, void *, size_t, int);
-+extern ssize_t extN_getxattr(struct dentry *, const char *, void *, size_t);
-+extern ssize_t extN_listxattr(struct dentry *, char *, size_t);
-+extern int extN_removexattr(struct dentry *, const char *);
-+
-+extern int extN_xattr_get(struct inode *, int, const char *, void *, size_t);
-+extern int extN_xattr_list(struct inode *, char *, size_t);
-+extern int extN_xattr_set(handle_t *handle, struct inode *, int, const char *, void *, size_t, int);
-+
-+extern void extN_xattr_drop_inode(handle_t *, struct inode *);
-+extern void extN_xattr_put_super(struct super_block *);
-+
-+extern int init_extN_xattr(void) __init;
-+extern void exit_extN_xattr(void);
-+
-+# else /* CONFIG_EXTN_FS_XATTR */
-+# define extN_setxattr NULL
-+# define extN_getxattr NULL
-+# define extN_listxattr NULL
-+# define extN_removexattr NULL
-+
-+static inline int
-+extN_xattr_get(struct inode *inode, int name_index, const char *name,
-+ void *buffer, size_t size, int flags)
-+{
-+ return -ENOTSUP;
-+}
-+
-+static inline int
-+extN_xattr_list(struct inode *inode, void *buffer, size_t size, int flags)
-+{
-+ return -ENOTSUP;
-+}
-+
-+static inline int
-+extN_xattr_set(handle_t *handle, struct inode *inode, int name_index,
-+ const char *name, void *value, size_t size, int flags)
-+{
-+ return -ENOTSUP;
-+}
-+
-+static inline void
-+extN_xattr_drop_inode(handle_t *handle, struct inode *inode)
-+{
-+}
-+
-+static inline void
-+extN_xattr_put_super(struct super_block *sb)
-+{
-+}
-+
-+static inline int
-+init_extN_xattr(void)
-+{
-+ return 0;
-+}
-+
-+static inline void
-+exit_extN_xattr(void)
-+{
-+}
-+
-+# endif /* CONFIG_EXTN_FS_XATTR */
-+
-+# ifdef CONFIG_EXTN_FS_XATTR_USER
-+
-+extern int init_extN_xattr_user(void) __init;
-+extern void exit_extN_xattr_user(void);
-+
-+# else /* CONFIG_EXTN_FS_XATTR_USER */
-+
-+static inline int
-+init_extN_xattr_user(void)
-+{
-+ return 0;
-+}
-+
-+static inline void
-+exit_extN_xattr_user(void)
-+{
-+}
-+
-+#endif /* CONFIG_EXTN_FS_XATTR_USER */
-+
-+#endif /* __KERNEL__ */
-+
---- /dev/null Tue Aug 6 08:46:29 2002
-+++ extN/xattr.c Wed Sep 25 11:51:34 2002
-@@ -0,0 +1,1247 @@
-+/*
-+ * linux/fs/extN/xattr.c
-+ *
-+ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
-+ *
-+ * Fix by Harrison Xing <harrison@mountainviewdata.com>.
-+ * Ext3 code with a lot of help from Eric Jarman <ejarman@acm.org>.
-+ * Extended attributes for symlinks and special files added per
-+ * suggestion of Luka Renko <luka.renko@hermes.si>.
-+ */
-+
-+/*
-+ * Extended attributes are stored on disk blocks allocated outside of
-+ * any inode. The i_file_acl field is then made to point to this allocated
-+ * block. If all extended attributes of an inode are identical, these
-+ * inodes may share the same extended attribute block. Such situations
-+ * are automatically detected by keeping a cache of recent attribute block
-+ * numbers and hashes over the block's contents in memory.
-+ *
-+ *
-+ * Extended attribute block layout:
-+ *
-+ * +------------------+
-+ * | header |
-+ * ¦ entry 1 | |
-+ * | entry 2 | | growing downwards
-+ * | entry 3 | v
-+ * | four null bytes |
-+ * | . . . |
-+ * | value 1 | ^
-+ * | value 3 | | growing upwards
-+ * | value 2 | |
-+ * +------------------+
-+ *
-+ * The block header is followed by multiple entry descriptors. These entry
-+ * descriptors are variable in size, and alligned to EXTN_XATTR_PAD
-+ * byte boundaries. The entry descriptors are sorted by attribute name,
-+ * so that two extended attribute blocks can be compared efficiently.
-+ *
-+ * Attribute values are aligned to the end of the block, stored in
-+ * no specific order. They are also padded to EXTN_XATTR_PAD byte
-+ * boundaries. No additional gaps are left between them.
-+ *
-+ * Locking strategy
-+ * ----------------
-+ * The VFS already holds the BKL and the inode->i_sem semaphore when any of
-+ * the xattr inode operations are called, so we are guaranteed that only one
-+ * processes accesses extended attributes of an inode at any time.
-+ *
-+ * For writing we also grab the extN_xattr_sem semaphore. This ensures that
-+ * only a single process is modifying an extended attribute block, even
-+ * if the block is shared among inodes.
-+ *
-+ * Note for porting to 2.5
-+ * -----------------------
-+ * The BKL will no longer be held in the xattr inode operations.
-+ */
-+
-+#include <linux/fs.h>
-+#include <linux/locks.h>
-+#include <linux/slab.h>
-+#include <linux/extN_jbd.h>
-+#include <linux/extN_fs.h>
-+#include <linux/extN_xattr.h>
-+#ifdef CONFIG_EXTN_FS_XATTR_SHARING
-+#include <linux/mbcache.h>
-+#endif
-+#include <linux/quotaops.h>
-+#include <asm/semaphore.h>
-+#include <linux/compatmac.h>
-+#include <linux/module.h>
-+
-+/* These symbols may be needed by a module. */
-+EXPORT_SYMBOL(extN_xattr_register);
-+EXPORT_SYMBOL(extN_xattr_unregister);
-+EXPORT_SYMBOL(extN_xattr_get);
-+EXPORT_SYMBOL(extN_xattr_list);
-+EXPORT_SYMBOL(extN_xattr_set);
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-+# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1)
-+#endif
-+
-+#define HDR(bh) ((struct extN_xattr_header *)((bh)->b_data))
-+#define ENTRY(ptr) ((struct extN_xattr_entry *)(ptr))
-+#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1)
-+#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
-+
-+#ifdef EXTN_XATTR_DEBUG
-+# define ea_idebug(inode, f...) do { \
-+ printk(KERN_DEBUG "inode %s:%ld: ", \
-+ kdevname(inode->i_dev), inode->i_ino); \
-+ printk(f); \
-+ printk("\n"); \
-+ } while (0)
-+# define ea_bdebug(bh, f...) do { \
-+ printk(KERN_DEBUG "block %s:%ld: ", \
-+ kdevname(bh->b_dev), bh->b_blocknr); \
-+ printk(f); \
-+ printk("\n"); \
-+ } while (0)
-+#else
-+# define ea_idebug(f...)
-+# define ea_bdebug(f...)
-+#endif
-+
-+static int extN_xattr_set2(handle_t *, struct inode *, struct buffer_head *,
-+ struct extN_xattr_header *);
-+
-+#ifdef CONFIG_EXTN_FS_XATTR_SHARING
-+
-+static int extN_xattr_cache_insert(struct buffer_head *);
-+static struct buffer_head *extN_xattr_cache_find(struct inode *,
-+ struct extN_xattr_header *);
-+static void extN_xattr_cache_remove(struct buffer_head *);
-+static void extN_xattr_rehash(struct extN_xattr_header *,
-+ struct extN_xattr_entry *);
-+
-+static struct mb_cache *extN_xattr_cache;
-+
-+#else
-+# define extN_xattr_cache_insert(bh) 0
-+# define extN_xattr_cache_find(inode, header) NULL
-+# define extN_xattr_cache_remove(bh) do {} while(0)
-+# define extN_xattr_rehash(header, entry) do {} while(0)
-+#endif
-+
-+/*
-+ * If a file system does not share extended attributes among inodes,
-+ * we should not need the extN_xattr_sem semaphore. However, the
-+ * filesystem may still contain shared blocks, so we always take
-+ * the lock.
-+ */
-+
-+DECLARE_MUTEX(extN_xattr_sem);
-+
-+static inline void
-+extN_xattr_lock(void)
-+{
-+ down(&extN_xattr_sem);
-+}
-+
-+static inline void
-+extN_xattr_unlock(void)
-+{
-+ up(&extN_xattr_sem);
-+}
-+
-+static inline int
-+extN_xattr_new_block(handle_t *handle, struct inode *inode,
-+ int * errp, int force)
-+{
-+ struct super_block *sb = inode->i_sb;
-+ int goal = le32_to_cpu(EXTN_SB(sb)->s_es->s_first_data_block) +
-+ EXTN_I(inode)->i_block_group * EXTN_BLOCKS_PER_GROUP(sb);
-+
-+ /* How can we enforce the allocation? */
-+ int block = extN_new_block(handle, inode, goal, 0, 0, errp);
-+#ifdef OLD_QUOTAS
-+ if (!*errp)
-+ inode->i_blocks += inode->i_sb->s_blocksize >> 9;
-+#endif
-+ return block;
-+}
-+
-+static inline int
-+extN_xattr_quota_alloc(struct inode *inode, int force)
-+{
-+ /* How can we enforce the allocation? */
-+#ifdef OLD_QUOTAS
-+ int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1);
-+ if (!error)
-+ inode->i_blocks += inode->i_sb->s_blocksize >> 9;
-+#else
-+ int error = DQUOT_ALLOC_BLOCK(inode, 1);
-+#endif
-+ return error;
-+}
-+
-+#ifdef OLD_QUOTAS
-+
-+static inline void
-+extN_xattr_quota_free(struct inode *inode)
-+{
-+ DQUOT_FREE_BLOCK(inode->i_sb, inode, 1);
-+ inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
-+}
-+
-+static inline void
-+extN_xattr_free_block(handle_t *handle, struct inode * inode,
-+ unsigned long block)
-+{
-+ extN_free_blocks(handle, inode, block, 1);
-+ inode->i_blocks -= inode->i_sb->s_blocksize >> 9;
-+}
-+
-+#else
-+# define extN_xattr_quota_free(inode) \
-+ DQUOT_FREE_BLOCK(inode, 1)
-+# define extN_xattr_free_block(handle, inode, block) \
-+ extN_free_blocks(handle, inode, block, 1)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
-+
-+static inline struct buffer_head *
-+sb_bread(struct super_block *sb, int block)
-+{
-+ return bread(sb->s_dev, block, sb->s_blocksize);
-+}
-+
-+static inline struct buffer_head *
-+sb_getblk(struct super_block *sb, int block)
-+{
-+ return getblk(sb->s_dev, block, sb->s_blocksize);
-+}
-+
-+#endif
-+
-+struct extN_xattr_handler *extN_xattr_handlers[EXTN_XATTR_INDEX_MAX];
-+rwlock_t extN_handler_lock = RW_LOCK_UNLOCKED;
-+
-+int
-+extN_xattr_register(int name_index, struct extN_xattr_handler *handler)
-+{
-+ int error = -EINVAL;
-+
-+ if (name_index > 0 && name_index <= EXTN_XATTR_INDEX_MAX) {
-+ write_lock(&extN_handler_lock);
-+ if (!extN_xattr_handlers[name_index-1]) {
-+ extN_xattr_handlers[name_index-1] = handler;
-+ error = 0;
-+ }
-+ write_unlock(&extN_handler_lock);
-+ }
-+ return error;
-+}
-+
-+void
-+extN_xattr_unregister(int name_index, struct extN_xattr_handler *handler)
-+{
-+ if (name_index > 0 || name_index <= EXTN_XATTR_INDEX_MAX) {
-+ write_lock(&extN_handler_lock);
-+ extN_xattr_handlers[name_index-1] = NULL;
-+ write_unlock(&extN_handler_lock);
-+ }
-+}
-+
-+static inline const char *
-+strcmp_prefix(const char *a, const char *a_prefix)
-+{
-+ while (*a_prefix && *a == *a_prefix) {
-+ a++;
-+ a_prefix++;
-+ }
-+ return *a_prefix ? NULL : a;
-+}
-+
-+/*
-+ * Decode the extended attribute name, and translate it into
-+ * the name_index and name suffix.
-+ */
-+static inline struct extN_xattr_handler *
-+extN_xattr_resolve_name(const char **name)
-+{
-+ struct extN_xattr_handler *handler = NULL;
-+ int i;
-+
-+ if (!*name)
-+ return NULL;
-+ read_lock(&extN_handler_lock);
-+ for (i=0; i<EXTN_XATTR_INDEX_MAX; i++) {
-+ if (extN_xattr_handlers[i]) {
-+ const char *n = strcmp_prefix(*name,
-+ extN_xattr_handlers[i]->prefix);
-+ if (n) {
-+ handler = extN_xattr_handlers[i];
-+ *name = n;
-+ break;
-+ }
-+ }
-+ }
-+ read_unlock(&extN_handler_lock);
-+ return handler;
-+}
-+
-+static inline struct extN_xattr_handler *
-+extN_xattr_handler(int name_index)
-+{
-+ struct extN_xattr_handler *handler = NULL;
-+ if (name_index > 0 && name_index <= EXTN_XATTR_INDEX_MAX) {
-+ read_lock(&extN_handler_lock);
-+ handler = extN_xattr_handlers[name_index-1];
-+ read_unlock(&extN_handler_lock);
-+ }
-+ return handler;
-+}
-+
-+/*
-+ * Inode operation getxattr()
-+ *
-+ * dentry->d_inode->i_sem down
-+ * BKL held [before 2.5.x]
-+ */
-+ssize_t
-+extN_getxattr(struct dentry *dentry, const char *name,
-+ void *buffer, size_t size)
-+{
-+ struct extN_xattr_handler *handler;
-+ struct inode *inode = dentry->d_inode;
-+
-+ handler = extN_xattr_resolve_name(&name);
-+ if (!handler)
-+ return -ENOTSUP;
-+ return handler->get(inode, name, buffer, size);
-+}
-+
-+/*
-+ * Inode operation listxattr()
-+ *
-+ * dentry->d_inode->i_sem down
-+ * BKL held [before 2.5.x]
-+ */
-+ssize_t
-+extN_listxattr(struct dentry *dentry, char *buffer, size_t size)
-+{
-+ return extN_xattr_list(dentry->d_inode, buffer, size);
-+}
-+
-+/*
-+ * Inode operation setxattr()
-+ *
-+ * dentry->d_inode->i_sem down
-+ * BKL held [before 2.5.x]
-+ */
-+int
-+extN_setxattr(struct dentry *dentry, const char *name,
-+ void *value, size_t size, int flags)
-+{
-+ struct extN_xattr_handler *handler;
-+ struct inode *inode = dentry->d_inode;
-+
-+ if (size == 0)
-+ value = ""; /* empty EA, do not remove */
-+ handler = extN_xattr_resolve_name(&name);
-+ if (!handler)
-+ return -ENOTSUP;
-+ return handler->set(inode, name, value, size, flags);
-+}
-+
-+/*
-+ * Inode operation removexattr()
-+ *
-+ * dentry->d_inode->i_sem down
-+ * BKL held [before 2.5.x]
-+ */
-+int
-+extN_removexattr(struct dentry *dentry, const char *name)
-+{
-+ struct extN_xattr_handler *handler;
-+ struct inode *inode = dentry->d_inode;
-+
-+ handler = extN_xattr_resolve_name(&name);
-+ if (!handler)
-+ return -ENOTSUP;
-+ return handler->set(inode, name, NULL, 0, XATTR_REPLACE);
-+}
-+
-+/*
-+ * extN_xattr_get()
-+ *
-+ * Copy an extended attribute into the buffer
-+ * provided, or compute the buffer size required.
-+ * Buffer is NULL to compute the size of the buffer required.
-+ *
-+ * Returns a negative error number on failure, or the number of bytes
-+ * used / required on success.
-+ */
-+int
-+extN_xattr_get(struct inode *inode, int name_index, const char *name,
-+ void *buffer, size_t buffer_size)
-+{
-+ struct buffer_head *bh = NULL;
-+ struct extN_xattr_entry *entry;
-+ unsigned int block, size;
-+ char *end;
-+ int name_len, error;
-+
-+ ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
-+ name_index, name, buffer, (long)buffer_size);
-+
-+ if (name == NULL)
-+ return -EINVAL;
-+ if (!EXTN_I(inode)->i_file_acl)
-+ return -ENOATTR;
-+ block = EXTN_I(inode)->i_file_acl;
-+ ea_idebug(inode, "reading block %d", block);
-+ bh = sb_bread(inode->i_sb, block);
-+ if (!bh)
-+ return -EIO;
-+ ea_bdebug(bh, "b_count=%d, refcount=%d",
-+ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
-+ end = bh->b_data + bh->b_size;
-+ if (HDR(bh)->h_magic != cpu_to_le32(EXTN_XATTR_MAGIC) ||
-+ HDR(bh)->h_blocks != cpu_to_le32(1)) {
-+bad_block: extN_error(inode->i_sb, "extN_xattr_get",
-+ "inode %ld: bad block %d", inode->i_ino, block);
-+ error = -EIO;
-+ goto cleanup;
-+ }
-+ /* find named attribute */
-+ name_len = strlen(name);
-+
-+ error = -ERANGE;
-+ if (name_len > 255)
-+ goto cleanup;
-+ entry = FIRST_ENTRY(bh);
-+ while (!IS_LAST_ENTRY(entry)) {
-+ struct extN_xattr_entry *next =
-+ EXTN_XATTR_NEXT(entry);
-+ if ((char *)next >= end)
-+ goto bad_block;
-+ if (name_index == entry->e_name_index &&
-+ name_len == entry->e_name_len &&
-+ memcmp(name, entry->e_name, name_len) == 0)
-+ goto found;
-+ entry = next;
-+ }
-+ /* Check the remaining name entries */
-+ while (!IS_LAST_ENTRY(entry)) {
-+ struct extN_xattr_entry *next =
-+ EXTN_XATTR_NEXT(entry);
-+ if ((char *)next >= end)
-+ goto bad_block;
-+ entry = next;
-+ }
-+ if (extN_xattr_cache_insert(bh))
-+ ea_idebug(inode, "cache insert failed");
-+ error = -ENOATTR;
-+ goto cleanup;
-+found:
-+ /* check the buffer size */
-+ if (entry->e_value_block != 0)
-+ goto bad_block;
-+ size = le32_to_cpu(entry->e_value_size);
-+ if (size > inode->i_sb->s_blocksize ||
-+ le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize)
-+ goto bad_block;
-+
-+ if (extN_xattr_cache_insert(bh))
-+ ea_idebug(inode, "cache insert failed");
-+ if (buffer) {
-+ error = -ERANGE;
-+ if (size > buffer_size)
-+ goto cleanup;
-+ /* return value of attribute */
-+ memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
-+ size);
-+ }
-+ error = size;
-+
-+cleanup:
-+ brelse(bh);
-+
-+ return error;
-+}
-+
-+/*
-+ * extN_xattr_list()
-+ *
-+ * Copy a list of attribute names into the buffer
-+ * provided, or compute the buffer size required.
-+ * Buffer is NULL to compute the size of the buffer required.
-+ *
-+ * Returns a negative error number on failure, or the number of bytes
-+ * used / required on success.
-+ */
-+int
-+extN_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
-+{
-+ struct buffer_head *bh = NULL;
-+ struct extN_xattr_entry *entry;
-+ unsigned int block, size = 0;
-+ char *buf, *end;
-+ int error;
-+
-+ ea_idebug(inode, "buffer=%p, buffer_size=%ld",
-+ buffer, (long)buffer_size);
-+
-+ if (!EXTN_I(inode)->i_file_acl)
-+ return 0;
-+ block = EXTN_I(inode)->i_file_acl;
-+ ea_idebug(inode, "reading block %d", block);
-+ bh = sb_bread(inode->i_sb, block);
-+ if (!bh)
-+ return -EIO;
-+ ea_bdebug(bh, "b_count=%d, refcount=%d",
-+ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
-+ end = bh->b_data + bh->b_size;
-+ if (HDR(bh)->h_magic != cpu_to_le32(EXTN_XATTR_MAGIC) ||
-+ HDR(bh)->h_blocks != cpu_to_le32(1)) {
-+bad_block: extN_error(inode->i_sb, "extN_xattr_list",
-+ "inode %ld: bad block %d", inode->i_ino, block);
-+ error = -EIO;
-+ goto cleanup;
-+ }
-+ /* compute the size required for the list of attribute names */
-+ for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
-+ entry = EXTN_XATTR_NEXT(entry)) {
-+ struct extN_xattr_handler *handler;
-+ struct extN_xattr_entry *next =
-+ EXTN_XATTR_NEXT(entry);
-+ if ((char *)next >= end)
-+ goto bad_block;
-+
-+ handler = extN_xattr_handler(entry->e_name_index);
-+ if (handler) {
-+ size += handler->list(NULL, inode, entry->e_name,
-+ entry->e_name_len) + 1;
-+ }
-+ }
-+
-+ if (extN_xattr_cache_insert(bh))
-+ ea_idebug(inode, "cache insert failed");
-+ if (!buffer) {
-+ error = size;
-+ goto cleanup;
-+ } else {
-+ error = -ERANGE;
-+ if (size > buffer_size)
-+ goto cleanup;
-+ }
-+
-+ /* list the attribute names */
-+ buf = buffer;
-+ for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
-+ entry = EXTN_XATTR_NEXT(entry)) {
-+ struct extN_xattr_handler *handler;
-+
-+ handler = extN_xattr_handler(entry->e_name_index);
-+ if (handler) {
-+ buf += handler->list(buf, inode, entry->e_name,
-+ entry->e_name_len);
-+ *buf++ = '\0';
-+ }
-+ }
-+ error = size;
-+
-+cleanup:
-+ brelse(bh);
-+
-+ return error;
-+}
-+
-+/*
-+ * If the EXTN_FEATURE_COMPAT_EXT_ATTR feature of this file system is
-+ * not set, set it.
-+ */
-+static void extN_xattr_update_super_block(handle_t *handle,
-+ struct super_block *sb)
-+{
-+ if (EXTN_HAS_COMPAT_FEATURE(sb, EXTN_FEATURE_COMPAT_EXT_ATTR))
-+ return;
-+
-+ lock_super(sb);
-+ extN_journal_get_write_access(handle, EXTN_SB(sb)->s_sbh);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-+ EXTN_SB(sb)->s_feature_compat |= EXTN_FEATURE_COMPAT_EXT_ATTR;
-+#endif
-+ EXTN_SB(sb)->s_es->s_feature_compat |=
-+ cpu_to_le32(EXTN_FEATURE_COMPAT_EXT_ATTR);
-+ sb->s_dirt = 1;
-+ extN_journal_dirty_metadata(handle, EXTN_SB(sb)->s_sbh);
-+ unlock_super(sb);
-+}
-+
-+/*
-+ * extN_xattr_set()
-+ *
-+ * Create, replace or remove an extended attribute for this inode. Buffer
-+ * is NULL to remove an existing extended attribute, and non-NULL to
-+ * either replace an existing extended attribute, or create a new extended
-+ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
-+ * specify that an extended attribute must exist and must not exist
-+ * previous to the call, respectively.
-+ *
-+ * Returns 0, or a negative error number on failure.
-+ */
-+int
-+extN_xattr_set(handle_t *handle, struct inode *inode, int name_index,
-+ const char *name, void *value, size_t value_len, int flags)
-+{
-+ struct super_block *sb = inode->i_sb;
-+ struct buffer_head *bh = NULL;
-+ struct extN_xattr_header *header = NULL;
-+ struct extN_xattr_entry *here, *last;
-+ unsigned int name_len;
-+ int min_offs = sb->s_blocksize, not_found = 1, free, error;
-+ char *end;
-+
-+ /*
-+ * header -- Points either into bh, or to a temporarily
-+ * allocated buffer.
-+ * here -- The named entry found, or the place for inserting, within
-+ * the block pointed to by header.
-+ * last -- Points right after the last named entry within the block
-+ * pointed to by header.
-+ * min_offs -- The offset of the first value (values are aligned
-+ * towards the end of the block).
-+ * end -- Points right after the block pointed to by header.
-+ */
-+
-+ ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
-+ name_index, name, value, (long)value_len);
-+
-+ if (IS_RDONLY(inode))
-+ return -EROFS;
-+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-+ return -EPERM;
-+ if (value == NULL)
-+ value_len = 0;
-+ if (name == NULL)
-+ return -EINVAL;
-+ name_len = strlen(name);
-+ if (name_len > 255 || value_len > sb->s_blocksize)
-+ return -ERANGE;
-+ extN_xattr_lock();
-+
-+ if (EXTN_I(inode)->i_file_acl) {
-+ /* The inode already has an extended attribute block. */
-+ int block = EXTN_I(inode)->i_file_acl;
-+
-+ bh = sb_bread(sb, block);
-+ error = -EIO;
-+ if (!bh)
-+ goto cleanup;
-+ ea_bdebug(bh, "b_count=%d, refcount=%d",
-+ atomic_read(&(bh->b_count)),
-+ le32_to_cpu(HDR(bh)->h_refcount));
-+ header = HDR(bh);
-+ end = bh->b_data + bh->b_size;
-+ if (header->h_magic != cpu_to_le32(EXTN_XATTR_MAGIC) ||
-+ header->h_blocks != cpu_to_le32(1)) {
-+bad_block: extN_error(sb, "extN_xattr_set",
-+ "inode %ld: bad block %d", inode->i_ino, block);
-+ error = -EIO;
-+ goto cleanup;
-+ }
-+ /* Find the named attribute. */
-+ here = FIRST_ENTRY(bh);
-+ while (!IS_LAST_ENTRY(here)) {
-+ struct extN_xattr_entry *next = EXTN_XATTR_NEXT(here);
-+ if ((char *)next >= end)
-+ goto bad_block;
-+ if (!here->e_value_block && here->e_value_size) {
-+ int offs = le16_to_cpu(here->e_value_offs);
-+ if (offs < min_offs)
-+ min_offs = offs;
-+ }
-+ not_found = name_index - here->e_name_index;
-+ if (!not_found)
-+ not_found = name_len - here->e_name_len;
-+ if (!not_found)
-+ not_found = memcmp(name, here->e_name,name_len);
-+ if (not_found <= 0)
-+ break;
-+ here = next;
-+ }
-+ last = here;
-+ /* We still need to compute min_offs and last. */
-+ while (!IS_LAST_ENTRY(last)) {
-+ struct extN_xattr_entry *next = EXTN_XATTR_NEXT(last);
-+ if ((char *)next >= end)
-+ goto bad_block;
-+ if (!last->e_value_block && last->e_value_size) {
-+ int offs = le16_to_cpu(last->e_value_offs);
-+ if (offs < min_offs)
-+ min_offs = offs;
-+ }
-+ last = next;
-+ }
-+
-+ /* Check whether we have enough space left. */
-+ free = min_offs - ((char*)last - (char*)header) - sizeof(__u32);
-+ } else {
-+ /* We will use a new extended attribute block. */
-+ free = sb->s_blocksize -
-+ sizeof(struct extN_xattr_header) - sizeof(__u32);
-+ here = last = NULL; /* avoid gcc uninitialized warning. */
-+ }
-+
-+ if (not_found) {
-+ /* Request to remove a nonexistent attribute? */
-+ error = -ENOATTR;
-+ if (flags & XATTR_REPLACE)
-+ goto cleanup;
-+ error = 0;
-+ if (value == NULL)
-+ goto cleanup;
-+ else
-+ free -= EXTN_XATTR_LEN(name_len);
-+ } else {
-+ /* Request to create an existing attribute? */
-+ error = -EEXIST;
-+ if (flags & XATTR_CREATE)
-+ goto cleanup;
-+ if (!here->e_value_block && here->e_value_size) {
-+ unsigned int size = le32_to_cpu(here->e_value_size);
-+
-+ if (le16_to_cpu(here->e_value_offs) + size >
-+ sb->s_blocksize || size > sb->s_blocksize)
-+ goto bad_block;
-+ free += EXTN_XATTR_SIZE(size);
-+ }
-+ }
-+ free -= EXTN_XATTR_SIZE(value_len);
-+ error = -ENOSPC;
-+ if (free < 0)
-+ goto cleanup;
-+
-+ /* Here we know that we can set the new attribute. */
-+
-+ if (header) {
-+ if (header->h_refcount == cpu_to_le32(1)) {
-+ ea_bdebug(bh, "modifying in-place");
-+ extN_xattr_cache_remove(bh);
-+ error = extN_journal_get_write_access(handle, bh);
-+ if (error)
-+ goto cleanup;
-+ } else {
-+ int offset;
-+
-+ ea_bdebug(bh, "cloning");
-+ header = kmalloc(bh->b_size, GFP_KERNEL);
-+ error = -ENOMEM;
-+ if (header == NULL)
-+ goto cleanup;
-+ memcpy(header, HDR(bh), bh->b_size);
-+ header->h_refcount = cpu_to_le32(1);
-+ offset = (char *)header - bh->b_data;
-+ here = ENTRY((char *)here + offset);
-+ last = ENTRY((char *)last + offset);
-+ }
-+ } else {
-+ /* Allocate a buffer where we construct the new block. */
-+ header = kmalloc(sb->s_blocksize, GFP_KERNEL);
-+ error = -ENOMEM;
-+ if (header == NULL)
-+ goto cleanup;
-+ memset(header, 0, sb->s_blocksize);
-+ end = (char *)header + sb->s_blocksize;
-+ header->h_magic = cpu_to_le32(EXTN_XATTR_MAGIC);
-+ header->h_blocks = header->h_refcount = cpu_to_le32(1);
-+ last = here = ENTRY(header+1);
-+ }
-+
-+ if (not_found) {
-+ /* Insert the new name. */
-+ int size = EXTN_XATTR_LEN(name_len);
-+ int rest = (char *)last - (char *)here;
-+ memmove((char *)here + size, here, rest);
-+ memset(here, 0, size);
-+ here->e_name_index = name_index;
-+ here->e_name_len = name_len;
-+ memcpy(here->e_name, name, name_len);
-+ } else {
-+ /* Remove the old value. */
-+ if (!here->e_value_block && here->e_value_size) {
-+ char *first_val = (char *)header + min_offs;
-+ int offs = le16_to_cpu(here->e_value_offs);
-+ char *val = (char *)header + offs;
-+ size_t size = EXTN_XATTR_SIZE(
-+ le32_to_cpu(here->e_value_size));
-+ memmove(first_val + size, first_val, val - first_val);
-+ memset(first_val, 0, size);
-+ here->e_value_offs = 0;
-+ min_offs += size;
-+
-+ /* Adjust all value offsets. */
-+ last = ENTRY(header+1);
-+ while (!IS_LAST_ENTRY(last)) {
-+ int o = le16_to_cpu(last->e_value_offs);
-+ if (!last->e_value_block && o < offs)
-+ last->e_value_offs =
-+ cpu_to_le16(o + size);
-+ last = EXTN_XATTR_NEXT(last);
-+ }
-+ }
-+ if (value == NULL) {
-+ /* Remove this attribute. */
-+ if (EXTN_XATTR_NEXT(ENTRY(header+1)) == last) {
-+ /* This block is now empty. */
-+ error = extN_xattr_set2(handle, inode, bh,NULL);
-+ goto cleanup;
-+ } else {
-+ /* Remove the old name. */
-+ int size = EXTN_XATTR_LEN(name_len);
-+ last = ENTRY((char *)last - size);
-+ memmove(here, (char*)here + size,
-+ (char*)last - (char*)here);
-+ memset(last, 0, size);
-+ }
-+ }
-+ }
-+
-+ if (value != NULL) {
-+ /* Insert the new value. */
-+ here->e_value_size = cpu_to_le32(value_len);
-+ if (value_len) {
-+ size_t size = EXTN_XATTR_SIZE(value_len);
-+ char *val = (char *)header + min_offs - size;
-+ here->e_value_offs =
-+ cpu_to_le16((char *)val - (char *)header);
-+ memset(val + size - EXTN_XATTR_PAD, 0,
-+ EXTN_XATTR_PAD); /* Clear the pad bytes. */
-+ memcpy(val, value, value_len);
-+ }
-+ }
-+ extN_xattr_rehash(header, here);
-+
-+ error = extN_xattr_set2(handle, inode, bh, header);
-+
-+cleanup:
-+ brelse(bh);
-+ if (!(bh && header == HDR(bh)))
-+ kfree(header);
-+ extN_xattr_unlock();
-+
-+ return error;
-+}
-+
-+/*
-+ * Second half of extN_xattr_set(): Update the file system.
-+ */
-+static int
-+extN_xattr_set2(handle_t *handle, struct inode *inode,
-+ struct buffer_head *old_bh, struct extN_xattr_header *header)
-+{
-+ struct super_block *sb = inode->i_sb;
-+ struct buffer_head *new_bh = NULL;
-+ int error;
-+
-+ if (header) {
-+ new_bh = extN_xattr_cache_find(inode, header);
-+ if (new_bh) {
-+ /*
-+ * We found an identical block in the cache.
-+ * The old block will be released after updating
-+ * the inode.
-+ */
-+ ea_bdebug(old_bh, "reusing block %ld",
-+ new_bh->b_blocknr);
-+
-+ error = -EDQUOT;
-+ if (extN_xattr_quota_alloc(inode, 1))
-+ goto cleanup;
-+
-+ error = extN_journal_get_write_access(handle, new_bh);
-+ if (error)
-+ goto cleanup;
-+ HDR(new_bh)->h_refcount = cpu_to_le32(
-+ le32_to_cpu(HDR(new_bh)->h_refcount) + 1);
-+ ea_bdebug(new_bh, "refcount now=%d",
-+ le32_to_cpu(HDR(new_bh)->h_refcount));
-+ } else if (old_bh && header == HDR(old_bh)) {
-+ /* Keep this block. */
-+ new_bh = old_bh;
-+ (void)extN_xattr_cache_insert(new_bh);
-+ } else {
-+ /* We need to allocate a new block */
-+ int force = EXTN_I(inode)->i_file_acl != 0;
-+ int block = extN_xattr_new_block(handle, inode,
-+ &error, force);
-+ if (error)
-+ goto cleanup;
-+ ea_idebug(inode, "creating block %d", block);
-+
-+ new_bh = sb_getblk(sb, block);
-+ if (!new_bh) {
-+getblk_failed: extN_xattr_free_block(handle, inode, block);
-+ error = -EIO;
-+ goto cleanup;
-+ }
-+ lock_buffer(new_bh);
-+ error = extN_journal_get_create_access(handle, new_bh);
-+ if (error) {
-+ unlock_buffer(new_bh);
-+ goto getblk_failed;
-+ }
-+ memcpy(new_bh->b_data, header, new_bh->b_size);
-+ mark_buffer_uptodate(new_bh, 1);
-+ unlock_buffer(new_bh);
-+ (void)extN_xattr_cache_insert(new_bh);
-+ extN_xattr_update_super_block(handle, sb);
-+ }
-+ error = extN_journal_dirty_metadata(handle, new_bh);
-+ if (error)
-+ goto cleanup;
-+ }
-+
-+ /* Update the inode. */
-+ EXTN_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
-+ inode->i_ctime = CURRENT_TIME;
-+ extN_mark_inode_dirty(handle, inode);
-+ if (IS_SYNC(inode))
-+ handle->h_sync = 1;
-+
-+ error = 0;
-+ if (old_bh && old_bh != new_bh) {
-+ /*
-+ * If there was an old block, and we are not still using it,
-+ * we now release the old block.
-+ */
-+ unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount);
-+
-+ error = extN_journal_get_write_access(handle, old_bh);
-+ if (error)
-+ goto cleanup;
-+ if (refcount == 1) {
-+ /* Free the old block. */
-+ ea_bdebug(old_bh, "freeing");
-+ extN_xattr_free_block(handle, inode, old_bh->b_blocknr);
-+
-+ /* extN_forget() calls bforget() for us, but we
-+ let our caller release old_bh, so we need to
-+ duplicate the handle before. */
-+ get_bh(old_bh);
-+ extN_forget(handle, 1, inode, old_bh,old_bh->b_blocknr);
-+ } else {
-+ /* Decrement the refcount only. */
-+ refcount--;
-+ HDR(old_bh)->h_refcount = cpu_to_le32(refcount);
-+ extN_xattr_quota_free(inode);
-+ extN_journal_dirty_metadata(handle, old_bh);
-+ ea_bdebug(old_bh, "refcount now=%d", refcount);
-+ }
-+ }
-+
-+cleanup:
-+ if (old_bh != new_bh)
-+ brelse(new_bh);
-+
-+ return error;
-+}
-+
-+/*
-+ * extN_xattr_drop_inode()
-+ *
-+ * Free extended attribute resources associated with this inode. This
-+ * is called immediately before an inode is freed.
-+ */
-+void
-+extN_xattr_drop_inode(handle_t *handle, struct inode *inode)
-+{
-+ struct buffer_head *bh;
-+ unsigned int block = EXTN_I(inode)->i_file_acl;
-+
-+ if (!block)
-+ return;
-+ extN_xattr_lock();
-+
-+ bh = sb_bread(inode->i_sb, block);
-+ if (!bh) {
-+ extN_error(inode->i_sb, "extN_xattr_drop_inode",
-+ "inode %ld: block %d read error", inode->i_ino, block);
-+ goto cleanup;
-+ }
-+ ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count)));
-+ if (HDR(bh)->h_magic != cpu_to_le32(EXTN_XATTR_MAGIC) ||
-+ HDR(bh)->h_blocks != cpu_to_le32(1)) {
-+ extN_error(inode->i_sb, "extN_xattr_drop_inode",
-+ "inode %ld: bad block %d", inode->i_ino, block);
-+ goto cleanup;
-+ }
-+ extN_journal_get_write_access(handle, bh);
-+ ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1);
-+ if (HDR(bh)->h_refcount == cpu_to_le32(1)) {
-+ extN_xattr_cache_remove(bh);
-+ extN_xattr_free_block(handle, inode, block);
-+ extN_forget(handle, 1, inode, bh, block);
-+ bh = NULL;
-+ } else {
-+ HDR(bh)->h_refcount = cpu_to_le32(
-+ le32_to_cpu(HDR(bh)->h_refcount) - 1);
-+ extN_journal_dirty_metadata(handle, bh);
-+ if (IS_SYNC(inode))
-+ handle->h_sync = 1;
-+ extN_xattr_quota_free(inode);
-+ }
-+ EXTN_I(inode)->i_file_acl = 0;
-+
-+cleanup:
-+ brelse(bh);
-+ extN_xattr_unlock();
-+}
-+
-+/*
-+ * extN_xattr_put_super()
-+ *
-+ * This is called when a file system is unmounted.
-+ */
-+void
-+extN_xattr_put_super(struct super_block *sb)
-+{
-+#ifdef CONFIG_EXTN_FS_XATTR_SHARING
-+ mb_cache_shrink(extN_xattr_cache, sb->s_dev);
-+#endif
-+}
-+
-+#ifdef CONFIG_EXTN_FS_XATTR_SHARING
-+
-+/*
-+ * extN_xattr_cache_insert()
-+ *
-+ * Create a new entry in the extended attribute cache, and insert
-+ * it unless such an entry is already in the cache.
-+ *
-+ * Returns 0, or a negative error number on failure.
-+ */
-+static int
-+extN_xattr_cache_insert(struct buffer_head *bh)
-+{
-+ __u32 hash = le32_to_cpu(HDR(bh)->h_hash);
-+ struct mb_cache_entry *ce;
-+ int error;
-+
-+ ce = mb_cache_entry_alloc(extN_xattr_cache);
-+ if (!ce)
-+ return -ENOMEM;
-+ error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash);
-+ if (error) {
-+ mb_cache_entry_free(ce);
-+ if (error == -EBUSY) {
-+ ea_bdebug(bh, "already in cache (%d cache entries)",
-+ atomic_read(&extN_xattr_cache->c_entry_count));
-+ error = 0;
-+ }
-+ } else {
-+ ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash,
-+ atomic_read(&extN_xattr_cache->c_entry_count));
-+ mb_cache_entry_release(ce);
-+ }
-+ return error;
-+}
-+
-+/*
-+ * extN_xattr_cmp()
-+ *
-+ * Compare two extended attribute blocks for equality.
-+ *
-+ * Returns 0 if the blocks are equal, 1 if they differ, and
-+ * a negative error number on errors.
-+ */
-+static int
-+extN_xattr_cmp(struct extN_xattr_header *header1,
-+ struct extN_xattr_header *header2)
-+{
-+ struct extN_xattr_entry *entry1, *entry2;
-+
-+ entry1 = ENTRY(header1+1);
-+ entry2 = ENTRY(header2+1);
-+ while (!IS_LAST_ENTRY(entry1)) {
-+ if (IS_LAST_ENTRY(entry2))
-+ return 1;
-+ if (entry1->e_hash != entry2->e_hash ||
-+ entry1->e_name_len != entry2->e_name_len ||
-+ entry1->e_value_size != entry2->e_value_size ||
-+ memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
-+ return 1;
-+ if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
-+ return -EIO;
-+ if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
-+ (char *)header2 + le16_to_cpu(entry2->e_value_offs),
-+ le32_to_cpu(entry1->e_value_size)))
-+ return 1;
-+
-+ entry1 = EXTN_XATTR_NEXT(entry1);
-+ entry2 = EXTN_XATTR_NEXT(entry2);
-+ }
-+ if (!IS_LAST_ENTRY(entry2))
-+ return 1;
-+ return 0;
-+}
-+
-+/*
-+ * extN_xattr_cache_find()
-+ *
-+ * Find an identical extended attribute block.
-+ *
-+ * Returns a pointer to the block found, or NULL if such a block was
-+ * not found or an error occurred.
-+ */
-+static struct buffer_head *
-+extN_xattr_cache_find(struct inode *inode, struct extN_xattr_header *header)
-+{
-+ __u32 hash = le32_to_cpu(header->h_hash);
-+ struct mb_cache_entry *ce;
-+
-+ if (!header->h_hash)
-+ return NULL; /* never share */
-+ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
-+ ce = mb_cache_entry_find_first(extN_xattr_cache, 0, inode->i_dev, hash);
-+ while (ce) {
-+ struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block);
-+
-+ if (!bh) {
-+ extN_error(inode->i_sb, "extN_xattr_cache_find",
-+ "inode %ld: block %ld read error",
-+ inode->i_ino, ce->e_block);
-+ } else if (le32_to_cpu(HDR(bh)->h_refcount) >
-+ EXTN_XATTR_REFCOUNT_MAX) {
-+ ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block,
-+ le32_to_cpu(HDR(bh)->h_refcount),
-+ EXTN_XATTR_REFCOUNT_MAX);
-+ } else if (!extN_xattr_cmp(header, HDR(bh))) {
-+ ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count)));
-+ mb_cache_entry_release(ce);
-+ return bh;
-+ }
-+ brelse(bh);
-+ ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash);
-+ }
-+ return NULL;
-+}
-+
-+/*
-+ * extN_xattr_cache_remove()
-+ *
-+ * Remove the cache entry of a block from the cache. Called when a
-+ * block becomes invalid.
-+ */
-+static void
-+extN_xattr_cache_remove(struct buffer_head *bh)
-+{
-+ struct mb_cache_entry *ce;
-+
-+ ce = mb_cache_entry_get(extN_xattr_cache, bh->b_dev, bh->b_blocknr);
-+ if (ce) {
-+ ea_bdebug(bh, "removing (%d cache entries remaining)",
-+ atomic_read(&extN_xattr_cache->c_entry_count)-1);
-+ mb_cache_entry_free(ce);
-+ } else
-+ ea_bdebug(bh, "no cache entry");
-+}
-+
-+#define NAME_HASH_SHIFT 5
-+#define VALUE_HASH_SHIFT 16
-+
-+/*
-+ * extN_xattr_hash_entry()
-+ *
-+ * Compute the hash of an extended attribute.
-+ */
-+static inline void extN_xattr_hash_entry(struct extN_xattr_header *header,
-+ struct extN_xattr_entry *entry)
-+{
-+ __u32 hash = 0;
-+ char *name = entry->e_name;
-+ int n;
-+
-+ for (n=0; n < entry->e_name_len; n++) {
-+ hash = (hash << NAME_HASH_SHIFT) ^
-+ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
-+ *name++;
-+ }
-+
-+ if (entry->e_value_block == 0 && entry->e_value_size != 0) {
-+ __u32 *value = (__u32 *)((char *)header +
-+ le16_to_cpu(entry->e_value_offs));
-+ for (n = (le32_to_cpu(entry->e_value_size) +
-+ EXTN_XATTR_ROUND) >> EXTN_XATTR_PAD_BITS; n; n--) {
-+ hash = (hash << VALUE_HASH_SHIFT) ^
-+ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
-+ le32_to_cpu(*value++);
-+ }
-+ }
-+ entry->e_hash = cpu_to_le32(hash);
-+}
-+
-+#undef NAME_HASH_SHIFT
-+#undef VALUE_HASH_SHIFT
-+
-+#define BLOCK_HASH_SHIFT 16
-+
-+/*
-+ * extN_xattr_rehash()
-+ *
-+ * Re-compute the extended attribute hash value after an entry has changed.
-+ */
-+static void extN_xattr_rehash(struct extN_xattr_header *header,
-+ struct extN_xattr_entry *entry)
-+{
-+ struct extN_xattr_entry *here;
-+ __u32 hash = 0;
-+
-+ extN_xattr_hash_entry(header, entry);
-+ here = ENTRY(header+1);
-+ while (!IS_LAST_ENTRY(here)) {
-+ if (!here->e_hash) {
-+ /* Block is not shared if an entry's hash value == 0 */
-+ hash = 0;
-+ break;
-+ }
-+ hash = (hash << BLOCK_HASH_SHIFT) ^
-+ (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
-+ le32_to_cpu(here->e_hash);
-+ here = EXTN_XATTR_NEXT(here);
-+ }
-+ header->h_hash = cpu_to_le32(hash);
-+}
-+
-+#undef BLOCK_HASH_SHIFT
-+
-+int __init
-+init_extN_xattr(void)
-+{
-+ extN_xattr_cache = mb_cache_create("extN_xattr", NULL,
-+ sizeof(struct mb_cache_entry) +
-+ sizeof(struct mb_cache_entry_index), 1, 61);
-+ if (!extN_xattr_cache)
-+ return -ENOMEM;
-+
-+ return 0;
-+}
-+
-+void
-+exit_extN_xattr(void)
-+{
-+ if (extN_xattr_cache)
-+ mb_cache_destroy(extN_xattr_cache);
-+ extN_xattr_cache = NULL;
-+}
-+
-+#else /* CONFIG_EXTN_FS_XATTR_SHARING */
-+
-+int __init
-+init_extN_xattr(void)
-+{
-+ return 0;
-+}
-+
-+void
-+exit_extN_xattr(void)
-+{
-+}
-+
-+#endif /* CONFIG_EXTN_FS_XATTR_SHARING */