# 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      [email protected]       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 ;