--- linux-2.4.20/fs/ext3/inode.c.=K0000=.orig 2003-02-04 13:46:03.000000000 +0000 +++ linux-2.4.20/fs/ext3/inode.c 2003-02-04 13:46:03.000000000 +0000 @@ -101,6 +101,34 @@ return err; } +/* + * Work out how many blocks we need to progress with the next chunk of a + * truncate transaction. + */ + +static unsigned long blocks_for_truncate(struct inode *inode) +{ + unsigned long needed; + + needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); + + /* Give ourselves just enough room to cope with inodes in which + * i_blocks is corrupt: we've seen disk corruptions in the past + * which resulted in random data in an inode which looked enough + * like a regular file for ext3 to try to delete it. Things + * will go a bit crazy if that happens, but at least we should + * try not to panic the whole kernel. */ + if (needed < 2) + needed = 2; + + /* But we need to bound the transaction so we don't overflow the + * journal. */ + if (needed > EXT3_MAX_TRANS_DATA) + needed = EXT3_MAX_TRANS_DATA; + + return EXT3_DATA_TRANS_BLOCKS + needed; +} + /* * Truncate transactions can be complex and absolutely huge. So we need to * be able to restart the transaction at a conventient checkpoint to make @@ -114,14 +142,9 @@ static handle_t *start_transaction(struct inode *inode) { - long needed; handle_t *result; - needed = inode->i_blocks; - if (needed > EXT3_MAX_TRANS_DATA) - needed = EXT3_MAX_TRANS_DATA; - - result = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS + needed); + result = ext3_journal_start(inode, blocks_for_truncate(inode)); if (!IS_ERR(result)) return result; @@ -137,14 +160,9 @@ */ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) { - long needed; - if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS) return 0; - needed = inode->i_blocks; - if (needed > EXT3_MAX_TRANS_DATA) - needed = EXT3_MAX_TRANS_DATA; - if (!ext3_journal_extend(handle, EXT3_RESERVE_TRANS_BLOCKS + needed)) + if (!ext3_journal_extend(handle, blocks_for_truncate(inode))) return 0; return 1; } @@ -156,11 +174,8 @@ */ static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) { - long needed = inode->i_blocks; - if (needed > EXT3_MAX_TRANS_DATA) - needed = EXT3_MAX_TRANS_DATA; jbd_debug(2, "restarting handle %p\n", handle); - return ext3_journal_restart(handle, EXT3_DATA_TRANS_BLOCKS + needed); + return ext3_journal_restart(handle, blocks_for_truncate(inode)); } /* --- linux-2.4.20/include/linux/ext3_jbd.h.=K0000=.orig 2003-02-04 13:46:03.000000000 +0000 +++ linux-2.4.20/include/linux/ext3_jbd.h 2003-02-04 13:46:03.000000000 +0000 @@ -28,7 +28,7 @@ * indirection blocks, the group and superblock summaries, and the data * block to complete the transaction. */ -#define EXT3_SINGLEDATA_TRANS_BLOCKS 8 +#define EXT3_SINGLEDATA_TRANS_BLOCKS 8U /* Extended attributes may touch two data buffers, two bitmap buffers, * and two group and summaries. */ @@ -58,7 +58,7 @@ * start off at the maximum transaction size and grow the transaction * optimistically as we go. */ -#define EXT3_MAX_TRANS_DATA 64 +#define EXT3_MAX_TRANS_DATA 64U /* We break up a large truncate or write transaction once the handle's * buffer credits gets this low, we need either to extend the @@ -67,7 +67,7 @@ * one block, plus two quota updates. Quota allocations are not * needed. */ -#define EXT3_RESERVE_TRANS_BLOCKS 12 +#define EXT3_RESERVE_TRANS_BLOCKS 12U int ext3_mark_iloc_dirty(handle_t *handle,