[BK] 2.4 ReiserFS Direct IO bugfix patch

From: Hans Reiser (reiser@namesys.com)
Date: Thu Feb 13 2003 - 13:31:53 EST


-- 
Hans

attached mail follows:


Hello!

This is the fix for the problem where DIRECT IO on a file that later will be tail-packed can cause reiserfs to crash in 2.4 kernels.

It can be pulled from bk://namesys.com/bk/reiser3-linux-2.4-directio-fix

Please apply, thanks.

Diffstat: inode.c | 43 +++++++++++++++++++++++++++++++++++-------- tail_conversion.c | 4 +++- 2 files changed, 38 insertions(+), 9 deletions(-)

Plain text patch:

# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.967 -> 1.968 # fs/reiserfs/inode.c 1.41 -> 1.42 # fs/reiserfs/tail_conversion.c 1.15 -> 1.16 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/02/13 green@angband.namesys.com 1.968 # reiserfs: Fix DIRECT IO interference with tail packing # -------------------------------------------- # diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c --- a/fs/reiserfs/inode.c Thu Feb 13 16:22:56 2003 +++ b/fs/reiserfs/inode.c Thu Feb 13 16:22:56 2003 @@ -418,6 +418,7 @@ struct buffer_head * bh_result, int create) { int ret ; + bh_result->b_page = NULL; ret = reiserfs_get_block(inode, block, bh_result, create) ; /* don't allow direct io onto tail pages */ @@ -428,6 +429,14 @@ reiserfs_unmap_buffer(bh_result); ret = -EINVAL ; } + /* Possible unpacked tail. Flush the data before pages have + disappeared */ + if (inode->u.reiserfs_i.i_flags & i_pack_on_close_mask) { + lock_kernel(); + reiserfs_commit_for_inode(inode); + inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask; + unlock_kernel(); + } return ret ; } @@ -566,7 +575,12 @@ return ret; } - inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask; + /* If file is of such a size, that it might have a tail and tails are enabled + ** we should mark it as possibly needing tail packing on close + */ + if ( (have_large_tails (inode->i_sb) && inode->i_size < block_size (inode)*4) || + (have_small_tails (inode->i_sb) && inode->i_size < block_size(inode)) ) + inode->u.reiserfs_i.i_flags |= i_pack_on_close_mask; windex = push_journal_writer("reiserfs_get_block") ; @@ -757,15 +771,21 @@ */ mark_buffer_uptodate (unbh, 1); - /* we've converted the tail, so we must - ** flush unbh before the transaction commits + /* unbh->b_page == NULL in case of DIRECT_IO request, this means + buffer will disappear shortly, so it should not be added to + any of our lists. */ - add_to_flushlist(inode, unbh) ; + if ( unbh->b_page ) { + /* we've converted the tail, so we must + ** flush unbh before the transaction commits + */ + add_to_flushlist(inode, unbh) ; - /* mark it dirty now to prevent commit_write from adding - ** this buffer to the inode's dirty buffer list - */ - __mark_buffer_dirty(unbh) ; + /* mark it dirty now to prevent commit_write from adding + ** this buffer to the inode's dirty buffer list + */ + __mark_buffer_dirty(unbh) ; + } //inode->i_blocks += inode->i_sb->s_blocksize / 512; //mark_tail_converted (inode); @@ -2062,6 +2082,13 @@ if (pos > inode->i_size) { struct reiserfs_transaction_handle th ; lock_kernel(); + /* If the file have grown beyond the border where it + can have a tail, unmark it as needing a tail + packing */ + if ( (have_large_tails (inode->i_sb) && inode->i_size < block_size (inode)*4) || + (have_small_tails (inode->i_sb) && inode->i_size < block_size(inode)) ) + inode->u.reiserfs_i.i_flags &= ~i_pack_on_close_mask; + journal_begin(&th, inode->i_sb, 1) ; reiserfs_update_inode_transaction(inode) ; inode->i_size = pos ; diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c --- a/fs/reiserfs/tail_conversion.c Thu Feb 13 16:22:56 2003 +++ b/fs/reiserfs/tail_conversion.c Thu Feb 13 16:22:56 2003 @@ -105,8 +105,10 @@ /* we only send the unbh pointer if the buffer is not up to date. ** this avoids overwriting good data from writepage() with old data ** from the disk or buffer cache + ** Special case: unbh->b_page will be NULL if we are coming through + ** DIRECT_IO handler here. */ - if (buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) { + if ( !unbh->b_page || buffer_uptodate(unbh) || Page_Uptodate(unbh->b_page)) { up_to_date_bh = NULL ; } else { up_to_date_bh = unbh ;

Bye, Oleg

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Feb 15 2003 - 22:00:48 EST