[2.4] reiserfs: fix one more directio vs tails problem, resend]

[2.4] reiserfs: fix one more directio vs tails problem, resend]

Post by Hans Reise » Tue, 13 May 2003 21:40:10



--
Hans

[ Attached Message ]

From: Oleg Drokin <gr...@namesys.com>
To: rei...@namesys.com
Date: Mon, 12 May 2003 18:01:30 +0400
Local: Mon, May 12 2003 10:01 am
Subject: [2.4] reiserfs: fix one more directio vs tails problem, resend
Hello!

    This changeset fixes another set problems related to directio vs packed tails.
    Thanks to Mingming Cao <m...@us.ibm.com> for bringing the issue to our attention.
    Most of the patch was made by Chris Mason.

    Please pull from bk://namesys.com/bk/reiser3-linux-2.4-directiofix2

Diffstat:
 fs/reiserfs/inode.c           |   12 ++++++-
 fs/reiserfs/journal.c         |   66 +++++++++++++++++++++++++++---------------
 fs/reiserfs/tail_conversion.c |    1
 include/linux/reiserfs_fs.h   |    2 +
 include/linux/reiserfs_fs_i.h |    7 ++++
 5 files changed, 63 insertions(+), 25 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.1158  -> 1.1159
#       include/linux/reiserfs_fs_i.h   1.8     -> 1.9    
#        fs/reiserfs/inode.c    1.42    -> 1.43  
#       fs/reiserfs/tail_conversion.c   1.16    -> 1.17  
#       fs/reiserfs/journal.c   1.28    -> 1.29  
#       include/linux/reiserfs_fs.h     1.26    -> 1.27  
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/05/03      gr...@angband.namesys.com      1.1159
# reiserfs: Fix another O_DIRECT vs tails problem. Mostly by Chris Mason.
# Thanks to Mingming Cao <m...@us.ibm.com> for bringing the issue to our attention.
# --------------------------------------------
#
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c       Mon May 12 18:00:53 2003
+++ b/fs/reiserfs/inode.c       Mon May 12 18:00:53 2003
@@ -469,7 +469,7 @@
     tail_end = (tail_start | (bh_result->b_size - 1)) + 1 ;

     index = tail_offset >> PAGE_CACHE_SHIFT ;
-    if (index != hole_page->index) {
+    if ( !hole_page || index != hole_page->index) {
        tail_page = grab_cache_page(inode->i_mapping, index) ;
        retval = -ENOMEM;
        if (!tail_page) {
@@ -1810,7 +1810,12 @@
            flush_dcache_page(page) ;
            kunmap(page) ;
            if (buffer_mapped(bh) && bh->b_blocknr != 0) {
-               mark_buffer_dirty(bh) ;
+               if (!atomic_set_buffer_dirty(bh)) {
+                       set_buffer_flushtime(bh);
+                       refile_buffer(bh);
+                       buffer_insert_inode_data_queue(bh, p_s_inode);
+                       balance_dirty();
+               }
            }
        }
        UnlockPage(page) ;
@@ -2158,6 +2163,9 @@
                               struct kiobuf *iobuf, unsigned long blocknr,
                              int blocksize)
 {
+    lock_kernel();
+    reiserfs_commit_for_tail(inode);
+    unlock_kernel();
     return generic_direct_IO(rw, inode, iobuf, blocknr, blocksize,
                              reiserfs_get_block_direct_io) ;
 }
diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
--- a/fs/reiserfs/journal.c     Mon May 12 18:00:53 2003
+++ b/fs/reiserfs/journal.c     Mon May 12 18:00:53 2003
@@ -2655,32 +2655,52 @@
   inode->u.reiserfs_i.i_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
 }

-static int reiserfs_inode_in_this_transaction(struct inode *inode) {
-  if (inode->u.reiserfs_i.i_trans_id == SB_JOURNAL(inode->i_sb)->j_trans_id ||
-      inode->u.reiserfs_i.i_trans_id == 0) {
-    return 1;
-  }
-  return 0 ;
+void reiserfs_update_tail_transaction(struct inode *inode) {
+  
+  inode->u.reiserfs_i.i_tail_trans_index = SB_JOURNAL_LIST_INDEX(inode->i_sb);
+
+  inode->u.reiserfs_i.i_tail_trans_id = SB_JOURNAL(inode->i_sb)->j_trans_id ;
+}
+
+static void __commit_trans_index(struct inode *inode, unsigned long id,
+                                 unsigned long index)
+{
+    struct reiserfs_journal_list *jl ;
+    struct reiserfs_transaction_handle th ;
+    struct super_block *sb = inode->i_sb ;
+
+    jl = SB_JOURNAL_LIST(sb) + index;
+
+    /* is it from the current transaction, or from an unknown transaction? */
+    if (id == SB_JOURNAL(sb)->j_trans_id) {
+       journal_join(&th, sb, 1) ;
+       journal_end_sync(&th, sb, 1) ;
+    } else if (jl->j_trans_id == id) {
+       flush_commit_list(sb, jl, 1) ;
+    }
+    /* if the transaction id does not match, this list is long since flushed
+    ** and we don't have to do anything here
+    */
 }
+void reiserfs_commit_for_tail(struct inode *inode) {
+    unsigned long id = inode->u.reiserfs_i.i_tail_trans_id;
+    unsigned long index = inode->u.reiserfs_i.i_tail_trans_index;

+    /* for tails, if this info is unset there's nothing to commit */
+    if (id && index)
+       __commit_trans_index(inode, id, index);
+}
 void reiserfs_commit_for_inode(struct inode *inode) {
-  struct reiserfs_journal_list *jl ;
-  struct reiserfs_transaction_handle th ;
-  struct super_block *sb = inode->i_sb ;
-
-  jl = SB_JOURNAL_LIST(sb) + inode->u.reiserfs_i.i_trans_index ;
-
-  /* is it from the current transaction, or from an unknown transaction? */
-  if (reiserfs_inode_in_this_transaction(inode)) {
-    journal_join(&th, sb, 1) ;
-    reiserfs_update_inode_transaction(inode) ;
-    journal_end_sync(&th, sb, 1) ;
-  } else if (jl->j_trans_id == inode->u.reiserfs_i.i_trans_id) {
-    flush_commit_list(sb, jl, 1) ;
-  }
-  /* if the transaction id does not match, this list is long since flushed
-  ** and we don't have to do anything here
-  */
+    unsigned long id = inode->u.reiserfs_i.i_trans_id;
+    unsigned long index = inode->u.reiserfs_i.i_trans_index;
+
+    /* for the whole inode, assume unset id or index means it was
+     * changed in the current transaction.  More conservative
+     */
+    if (!id || !index)
+       reiserfs_update_inode_transaction(inode) ;
+
+    __commit_trans_index(inode, id, index);
 }

 void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb,
diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
--- a/fs/reiserfs/tail_conversion.c     Mon May 12 18:00:53 2003
+++ b/fs/reiserfs/tail_conversion.c     Mon May 12 18:00:53 2003
@@ -133,6 +133,7 @@

     inode->u.reiserfs_i.i_first_direct_byte = U32_MAX;

+    reiserfs_update_tail_transaction(inode);
     return 0;
 }

diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h       Mon May 12 18:00:53 2003
+++ b/include/linux/reiserfs_fs.h       Mon May 12 18:00:53 2003
@@ -1558,7 +1558,9 @@
 #define JOURNAL_BUFFER(j,n) ((j)->j_ap_blocks[((j)->j_start + (n)) % JOURNAL_BLOCK_COUNT])

 void reiserfs_commit_for_inode(struct inode *) ;
+void reiserfs_commit_for_tail(struct inode *) ;
 void reiserfs_update_inode_transaction(struct inode *) ;
+void reiserfs_update_tail_transaction(struct inode *) ;
 void reiserfs_wait_on_write_block(struct super_block *s) ;
 void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
 void reiserfs_allow_writes(struct super_block *s) ;
diff -Nru a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
--- a/include/linux/reiserfs_fs_i.h     Mon May 12 18:00:53 2003
+++ b/include/linux/reiserfs_fs_i.h     Mon May 12 18:00:53 2003
@@ -53,6 +53,13 @@
     ** flushed */
     unsigned long i_trans_id ;
     unsigned long i_trans_index ;
+
+    /* direct io needs to make sure the tail is on disk to avoid
+     * buffer alias problems.  This records the transaction last
+     * involved in a direct->indirect conversion for this file
+     */
+    unsigned long i_tail_trans_id;
+    unsigned long i_tail_trans_index;
 };

 #endif