Commit 375f73f9 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ext3: direct-io transaction extending fix

ext3_direct_io_get_blocks() is misinterpreting the return value from
ext3_journal_extend(), and is consequently running out of buffer credits and
going BUG on tremendously large direct-io writes.  Fix that up.

Also, I note that the really large direct-io writes can hold a transaction
open for the entire duration, which can be minutes.  This violates ext3's
attempt to commit data at regular intervals.  Fix that up by looking at the
transaction state: if it's T_LOCKED, shut off the current handle so the
pending commit can complete.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 924cfe97
...@@ -881,26 +881,42 @@ ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock, ...@@ -881,26 +881,42 @@ ext3_direct_io_get_blocks(struct inode *inode, sector_t iblock,
handle_t *handle = journal_current_handle(); handle_t *handle = journal_current_handle();
int ret = 0; int ret = 0;
if (handle && handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { if (!handle)
goto get_block; /* A read */
if (handle->h_transaction->t_state == T_LOCKED) {
/*
* Huge direct-io writes can hold off commits for long
* periods of time. Let this commit run.
*/
ext3_journal_stop(handle);
handle = ext3_journal_start(inode, DIO_CREDITS);
if (IS_ERR(handle))
ret = PTR_ERR(handle);
goto get_block;
}
if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) {
/* /*
* Getting low on buffer credits... * Getting low on buffer credits...
*/ */
if (!ext3_journal_extend(handle, DIO_CREDITS)) { ret = ext3_journal_extend(handle, DIO_CREDITS);
if (ret > 0) {
/* /*
* Couldn't extend the transaction. Start a new one * Couldn't extend the transaction. Start a new one.
*/ */
ret = ext3_journal_restart(handle, DIO_CREDITS); ret = ext3_journal_restart(handle, DIO_CREDITS);
} }
} }
get_block:
if (ret == 0) if (ret == 0)
ret = ext3_get_block_handle(handle, inode, iblock, ret = ext3_get_block_handle(handle, inode, iblock,
bh_result, create, 0); bh_result, create, 0);
if (ret == 0) bh_result->b_size = (1 << inode->i_blkbits);
bh_result->b_size = (1 << inode->i_blkbits);
return ret; return ret;
} }
/* /*
* `handle' can be NULL if create is zero * `handle' can be NULL if create is zero
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment