--- /dev/null
+Index: linux-2.4.20/fs/ext3/ialloc.c
+===================================================================
+--- linux-2.4.20.orig/fs/ext3/ialloc.c 2003-10-25 00:37:13.000000000 +0400
++++ linux-2.4.20/fs/ext3/ialloc.c 2003-10-29 20:33:33.000000000 +0300
+@@ -241,11 +241,16 @@
+
+ bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
+
+- BUFFER_TRACE(bh, "get_write_access");
+- fatal = ext3_journal_get_write_access(handle, bh);
++ BUFFER_TRACE(bh, "get_undo_access");
++ fatal = ext3_journal_get_undo_access(handle, bh);
+ if (fatal)
+ goto error_return;
+
++ /* to prevent inode reusing within single transaction -bzzz */
++ BUFFER_TRACE(bh, "clear in b_committed_data");
++ J_ASSERT_BH(bh, bh2jh(bh)->b_committed_data != NULL);
++ ext3_set_bit(bit, bh2jh(bh)->b_committed_data);
++
+ /* Ok, now we can actually update the inode bitmaps.. */
+ if (!ext3_clear_bit (bit, bh->b_data))
+ ext3_error (sb, "ext3_free_inode",
+@@ -319,6 +324,131 @@
+ return 0;
+ }
+
++static int ext3_test_allocatable(int nr, struct buffer_head *bh)
++{
++ if (ext3_test_bit(nr, bh->b_data))
++ return 0;
++ if (!buffer_jbd(bh) || !bh2jh(bh)->b_committed_data)
++ return 1;
++#if 0
++ if (!ext3_test_bit(nr, bh2jh(bh)->b_committed_data))
++ printk("EXT3-fs: inode %d was used\n", nr);
++#endif
++ return !ext3_test_bit(nr, bh2jh(bh)->b_committed_data);
++}
++
++int ext3_find_group_dir(const struct inode *dir,
++ struct ext3_group_desc **gdp,
++ struct buffer_head **bh)
++{
++ struct super_block *sb = dir->i_sb;
++ struct ext3_super_block *es;
++ struct ext3_group_desc *tmp;
++ int i = 0, j, avefreei;
++
++ es = EXT3_SB(sb)->s_es;
++ avefreei = le32_to_cpu(es->s_free_inodes_count) /
++ sb->u.ext3_sb.s_groups_count;
++ for (j = 0; j < sb->u.ext3_sb.s_groups_count; j++) {
++ struct buffer_head *temp_buffer;
++ tmp = ext3_get_group_desc(sb, j, &temp_buffer);
++ if (tmp && le16_to_cpu(tmp->bg_free_inodes_count) &&
++ le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) {
++ if (!*gdp || (le16_to_cpu(tmp->bg_free_blocks_count) >
++ le16_to_cpu((*gdp)->bg_free_blocks_count))) {
++ i = j;
++ *gdp = tmp;
++ *bh = temp_buffer;
++ }
++ }
++ }
++
++ return i;
++}
++
++int ext3_find_group_other(const struct inode *dir,
++ struct ext3_group_desc **gdp,
++ struct buffer_head **bh)
++{
++ struct super_block *sb = dir->i_sb;
++ struct ext3_group_desc *tmp;
++ int i, j;
++
++ /*
++ * Try to place the inode in its parent directory
++ */
++ i = dir->u.ext3_i.i_block_group;
++ tmp = ext3_get_group_desc(sb, i, bh);
++ if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
++ *gdp = tmp;
++ else {
++ /*
++ * Use a quadratic hash to find a group with a
++ * free inode
++ */
++ for (j = 1; j < sb->u.ext3_sb.s_groups_count; j <<= 1) {
++ i += j;
++ if (i >= sb->u.ext3_sb.s_groups_count)
++ i -= sb->u.ext3_sb.s_groups_count;
++ tmp = ext3_get_group_desc (sb, i, bh);
++ if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) {
++ *gdp = tmp;
++ break;
++ }
++ }
++ }
++ if (!*gdp) {
++ /*
++ * That failed: try linear search for a free inode
++ */
++ i = dir->u.ext3_i.i_block_group + 1;
++ for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) {
++ if (++i >= sb->u.ext3_sb.s_groups_count)
++ i = 0;
++ tmp = ext3_get_group_desc (sb, i, bh);
++ if (tmp && le16_to_cpu(tmp->bg_free_inodes_count)) {
++ *gdp = tmp;
++ break;
++ }
++ }
++ }
++
++ return i;
++}
++
++static int ext3_find_group(const struct inode *dir, int mode,
++ struct ext3_group_desc **gdp,
++ struct buffer_head **bh)
++{
++ if (S_ISDIR(mode))
++ return ext3_find_group_dir(dir, gdp, bh);
++ return ext3_find_group_other(dir, gdp, bh);
++}
++
++static int ext3_find_usable_inode(struct super_block *sb,
++ struct buffer_head *bh)
++{
++ int here, maxinodes, next;
++
++ maxinodes = EXT3_INODES_PER_GROUP(sb);
++ here = 0;
++
++ while (here < maxinodes) {
++ next = ext3_find_next_zero_bit((unsigned long *) bh->b_data,
++ maxinodes, here);
++ if (next >= maxinodes)
++ return -1;
++ if (ext3_test_allocatable(next, bh))
++ return next;
++
++ J_ASSERT_BH(bh, bh2jh(bh)->b_committed_data);
++ here = ext3_find_next_zero_bit
++ ((unsigned long *) bh2jh(bh)->b_committed_data,
++ maxinodes, next);
++ }
++ return -1;
++}
++
+ /*
+ * There are two policies for allocating an inode. If the new inode is
+ * a directory, then a forward search is made for a block group with both
+@@ -336,7 +466,7 @@
+ struct super_block * sb;
+ struct buffer_head * bh;
+ struct buffer_head * bh2;
+- int i, j, avefreei;
++ int i, j, k;
+ struct inode * inode;
+ int bitmap_nr;
+ struct ext3_group_desc * gdp;
+@@ -371,11 +501,12 @@
+
+ bh = EXT3_SB(sb)->s_inode_bitmap[bitmap_nr];
+
+- BUFFER_TRACE(bh, "get_write_access");
+- err = ext3_journal_get_write_access(handle, bh);
++ BUFFER_TRACE(bh, "get_undo_access");
++ err = ext3_journal_get_undo_access(handle, bh);
+ if (err) goto fail;
+
+- if (ext3_set_bit(j, bh->b_data)) {
++ if (!ext3_test_allocatable(j, bh) ||
++ ext3_set_bit(j, bh->b_data)) {
+ printk(KERN_ERR "goal inode %lu unavailable\n", goal);
+ /* Oh well, we tried. */
+ goto repeat;
+@@ -393,119 +524,70 @@
+
+ repeat:
+ gdp = NULL;
+- i = 0;
+-
+- if (S_ISDIR(mode)) {
+- avefreei = le32_to_cpu(es->s_free_inodes_count) /
+- sb->u.ext3_sb.s_groups_count;
+- if (!gdp) {
+- for (j = 0; j < sb->u.ext3_sb.s_groups_count; j++) {
+- struct buffer_head *temp_buffer;
+- tmp = ext3_get_group_desc (sb, j, &temp_buffer);
+- if (tmp &&
+- le16_to_cpu(tmp->bg_free_inodes_count) &&
+- le16_to_cpu(tmp->bg_free_inodes_count) >=
+- avefreei) {
+- if (!gdp || (le16_to_cpu(tmp->bg_free_blocks_count) >
+- le16_to_cpu(gdp->bg_free_blocks_count))) {
+- i = j;
+- gdp = tmp;
+- bh2 = temp_buffer;
+- }
+- }
+- }
+- }
+- } else {
+- /*
+- * Try to place the inode in its parent directory
+- */
+- i = dir->u.ext3_i.i_block_group;
+- tmp = ext3_get_group_desc (sb, i, &bh2);
+- if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
+- gdp = tmp;
+- else
+- {
+- /*
+- * Use a quadratic hash to find a group with a
+- * free inode
+- */
+- for (j = 1; j < sb->u.ext3_sb.s_groups_count; j <<= 1) {
+- i += j;
+- if (i >= sb->u.ext3_sb.s_groups_count)
+- i -= sb->u.ext3_sb.s_groups_count;
+- tmp = ext3_get_group_desc (sb, i, &bh2);
+- if (tmp &&
+- le16_to_cpu(tmp->bg_free_inodes_count)) {
+- gdp = tmp;
+- break;
+- }
+- }
+- }
+- if (!gdp) {
+- /*
+- * That failed: try linear search for a free inode
+- */
+- i = dir->u.ext3_i.i_block_group + 1;
+- for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) {
+- if (++i >= sb->u.ext3_sb.s_groups_count)
+- i = 0;
+- tmp = ext3_get_group_desc (sb, i, &bh2);
+- if (tmp &&
+- le16_to_cpu(tmp->bg_free_inodes_count)) {
+- gdp = tmp;
+- break;
+- }
+- }
+- }
+- }
+
++ /* choose group */
++ i = ext3_find_group(dir, mode, &gdp, &bh2);
+ err = -ENOSPC;
+ if (!gdp)
+ goto out;
+-
++
+ err = -EIO;
+- bitmap_nr = load_inode_bitmap (sb, i);
++ bitmap_nr = load_inode_bitmap(sb, i);
+ if (bitmap_nr < 0)
+ goto fail;
+-
+ bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
+
+- if ((j = ext3_find_first_zero_bit ((unsigned long *) bh->b_data,
+- EXT3_INODES_PER_GROUP(sb))) <
+- EXT3_INODES_PER_GROUP(sb)) {
+- BUFFER_TRACE(bh, "get_write_access");
+- err = ext3_journal_get_write_access(handle, bh);
+- if (err) goto fail;
+-
+- if (ext3_set_bit (j, bh->b_data)) {
+- ext3_error (sb, "ext3_new_inode",
+- "bit already set for inode %d", j);
+- goto repeat;
+- }
+- BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
+- err = ext3_journal_dirty_metadata(handle, bh);
+- if (err) goto fail;
+- } else {
+- if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
+- ext3_error (sb, "ext3_new_inode",
+- "Free inodes count corrupted in group %d",
+- i);
+- /* Is it really ENOSPC? */
+- err = -ENOSPC;
+- if (sb->s_flags & MS_RDONLY)
+- goto fail;
+-
+- BUFFER_TRACE(bh2, "get_write_access");
+- err = ext3_journal_get_write_access(handle, bh2);
+- if (err) goto fail;
+- gdp->bg_free_inodes_count = 0;
+- BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
+- err = ext3_journal_dirty_metadata(handle, bh2);
+- if (err) goto fail;
++ /* try to allocate in selected group */
++ j = ext3_find_usable_inode(sb, bh);
++ err = -ENOSPC;
++ if (j >= 0)
++ goto found_free;
++
++ /* can't allocate: try to allocate in ANY another groups */
++ k = i;
++ err = -EIO;
++ for (i = i + 1; i != k; i++) {
++ if (i >= sb->u.ext3_sb.s_groups_count)
++ i = 0;
++ tmp = ext3_get_group_desc(sb, i, &bh2);
++ if (le16_to_cpu(tmp->bg_free_inodes_count) == 0)
++ continue;
++
++ bitmap_nr = load_inode_bitmap(sb, i);
++ if (bitmap_nr < 0)
++ goto fail;
++ bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
++
++ /* try to allocate in selected group */
++ if ((j = ext3_find_usable_inode(sb, bh)) >= 0) {
++ gdp = tmp;
++ break;
+ }
+- goto repeat;
+ }
++ err = -ENOSPC;
++ if (!gdp)
++ goto out;
++
++ found_free:
++ BUFFER_TRACE(bh, "get_undo_access");
++ err = ext3_journal_get_undo_access(handle, bh);
++ if (err)
++ goto fail;
++
++ if (ext3_set_bit(j, bh->b_data)) {
++ ext3_error (sb, "ext3_new_inode",
++ "bit already set for inode %d", j);
++ goto fail;
++ }
++ BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
++ err = ext3_journal_dirty_metadata(handle, bh);
++ if (err)
++ goto fail;
++
+ have_bit_and_group:
++ if (buffer_jbd(bh) && bh2jh(bh)->b_committed_data)
++ J_ASSERT_BH(bh, !ext3_test_bit(j, bh2jh(bh)->b_committed_data));
++
+ j += i * EXT3_INODES_PER_GROUP(sb) + 1;
+ if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) {
+ ext3_error (sb, "ext3_new_inode",