+++ /dev/null
-Index: linux-2.6.7/fs/ext3/ialloc.c
-===================================================================
---- linux-2.6.7.orig/fs/ext3/ialloc.c 2004-10-05 21:15:58.000000000 +0400
-+++ linux-2.6.7/fs/ext3/ialloc.c 2004-10-06 17:14:39.776562240 +0400
-@@ -144,11 +144,16 @@
- if (!bitmap_bh)
- goto error_return;
-
-- BUFFER_TRACE(bitmap_bh, "get_write_access");
-- fatal = ext3_journal_get_write_access(handle, bitmap_bh);
-+ BUFFER_TRACE(bitmap_bh, "get_undo_access");
-+ fatal = ext3_journal_get_undo_access(handle, bitmap_bh, NULL);
- if (fatal)
- goto error_return;
-
-+ /* to prevent inode reusing within single transaction -bzzz */
-+ BUFFER_TRACE(bitmap_bh, "clear in b_committed_data");
-+ J_ASSERT_BH(bitmap_bh, bh2jh(bitmap_bh)->b_committed_data != NULL);
-+ ext3_set_bit(bit, bh2jh(bitmap_bh)->b_committed_data);
-+
- /* Ok, now we can actually update the inode bitmaps.. */
- if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
- bit, bitmap_bh->b_data))
-@@ -411,6 +416,16 @@
- }
-
- /*
-+ * this is just to check was block freed in current transaction -bzzz
-+ */
-+static int ext3_test_allocatable(int nr, struct buffer_head *bh)
-+{
-+ if (!buffer_jbd(bh) || !bh2jh(bh)->b_committed_data)
-+ return 1;
-+ return !ext3_test_bit(nr, bh2jh(bh)->b_committed_data);
-+}
-+
-+/*
- * 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
- * free space and a low directory-to-inode ratio; if that fails, then of
-@@ -426,7 +441,7 @@
- struct super_block *sb;
- struct buffer_head *bitmap_bh = NULL;
- struct buffer_head *bh2;
-- int group;
-+ int group, credits;
- unsigned long ino = 0;
- struct inode * inode;
- struct ext3_group_desc * gdp = NULL;
-@@ -459,16 +474,25 @@
- if (!bitmap_bh)
- goto fail;
-
-- BUFFER_TRACE(bh, "get_write_access");
-- err = ext3_journal_get_write_access(handle, bitmap_bh);
-+ BUFFER_TRACE(bh, "get_undo_access");
-+ err = ext3_journal_get_undo_access(handle, bitmap_bh, &credits);
- if (err) goto fail;
-
-- if (ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
-- ino, bitmap_bh->b_data)) {
-+ if (!ext3_test_allocatable(ino, bitmap_bh) ||
-+ ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
-+ ino, bitmap_bh->b_data)) {
- printk(KERN_ERR "goal inode %lu unavailable\n", goal);
- /* Oh well, we tried. */
- goto continue_allocation;
- }
-+ if (!ext3_test_allocatable(ino, bitmap_bh)) {
-+ /* in theory it's possible another that thread has
-+ * allocated and freed block between test_allocatable()
-+ * and set_bit_atomic(). so, we we have to check
-+ * this -bzzz */
-+ journal_release_buffer(handle, bitmap_bh, credits);
-+ goto continue_allocation;
-+ }
-
- BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
- err = ext3_journal_dirty_metadata(handle, bitmap_bh);
-@@ -511,21 +535,29 @@
- int credits = 0;
-
- BUFFER_TRACE(bitmap_bh, "get_write_access");
-- err = ext3_journal_get_write_access_credits(handle,
-+ err = ext3_journal_get_undo_access(handle,
- bitmap_bh, &credits);
- if (err)
- goto fail;
-
-- if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
-- ino, bitmap_bh->b_data)) {
-- /* we won it */
-- BUFFER_TRACE(bitmap_bh,
-- "call ext3_journal_dirty_metadata");
-- err = ext3_journal_dirty_metadata(handle,
-- bitmap_bh);
-- if (err)
-- goto fail;
-- goto got;
-+ if (ext3_test_allocatable(ino, bitmap_bh) &&
-+ !ext3_set_bit_atomic(sb_bgl_lock(sbi, group),
-+ ino, bitmap_bh->b_data)) {
-+ /* in theory it's possible another that
-+ * thread has allocated and freed block
-+ * between ext3_test_allocatable() and
-+ * set_bit_atomic(). so, we we have to
-+ * check this -bzzz */
-+ if (ext3_test_allocatable(ino, bitmap_bh)) {
-+ /* we won it */
-+ BUFFER_TRACE(bitmap_bh,
-+ "call ext3_journal_dirty_metadata");
-+ err = ext3_journal_dirty_metadata(handle,
-+ bitmap_bh);
-+ if (err)
-+ goto fail;
-+ goto got;
-+ }
- }
- /* we lost it */
- journal_release_buffer(handle, bitmap_bh, credits);