Skip to contentSkip to conversation

reiserfs cleanup -- flush routines

PATCH New Chris Mason 1 participant 1 message May 31, 2001

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 reiserfs cleanup -- flush routines

Hi guys,

When packed tails get converted, reiserfs makes sure the new full block is flushed before transaction commit, which avoids losing old file data if we crash. But, of all the possible ways I could have coded this, I probably picked the worst one.

So, this patch rips out all that crap, and instead puts the new buffers onto the buffer list for a dummy inode. fsync_inode_buffers is used to flush the list before a commit. The old way involved pinned pages, so this should be much more VM friendly.

This is also a building block for a few other patches, so it is important to get this part right. It works for me, but I'd really appreciate a few more testers.

If you are testing with reiserfs as a module, make sure to recompile the entire kernel (in-core inode/super structures have changed).

-chris

fs/reiserfs/inode.c +19 -74
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
@@ -43,7 +43,6 @@
 	windex = push_journal_writer("delete_inode") ;
 
 	reiserfs_delete_object (&th, inode);
-	reiserfs_remove_page_from_flush_list(&th, inode) ;
 	pop_journal_writer(windex) ;
 	reiserfs_release_objectid (&th, inode->i_ino);
 
@@ -102,6 +101,11 @@
     ih->u.ih_entry_count = cpu_to_le16 (entry_count);
 }
 
+static void add_to_flushlist(struct inode *inode, struct buffer_head *bh) {
+    struct inode *jinode = &(SB_JOURNAL(inode->i_sb)->j_dummy_inode) ;
+
+    buffer_insert_inode_queue(bh, jinode) ;
+}
 
 //
 // FIXME: we might cache recently accessed indirect item (or at least
@@ -128,60 +132,6 @@
 ** --chris
 */
 
-/* people who call journal_begin with a page locked must call this
-** BEFORE calling journal_begin
-*/
-static int prevent_flush_page_lock(struct page *page, 
-				   struct inode *inode) {
-  struct reiserfs_page_list *pl ;
-  struct super_block *s = inode->i_sb ;
-  /* we don't care if the inode has a stale pointer from an old
-  ** transaction
-  */
-  if(!page || inode->u.reiserfs_i.i_conversion_trans_id != SB_JOURNAL(s)->j_trans_id) {
-    return 0 ;
-  }
-  pl = inode->u.reiserfs_i.i_converted_page ;
-  if (pl && pl->page == page) {
-    pl->do_not_lock = 1 ;
-  }
-  /* this last part is really important.  The address space operations have
-  ** the page locked before they call the journal functions.  So it is possible
-  ** for one process to be waiting in flush_pages_before_commit for a 
-  ** page, then for the process with the page locked to call journal_begin.
-  **
-  ** We'll deadlock because the process flushing pages will never notice
-  ** the process with the page locked has called prevent_flush_page_lock.
-  ** So, we wake up the page waiters, even though the page is still locked.
-  ** The process waiting in flush_pages_before_commit must check the
-  ** pl->do_not_lock flag, and stop trying to lock the page.
-  */
-  wake_up(&page->wait) ;
-  return 0 ;
- 
-}
-/* people who call journal_end with a page locked must call this
-** AFTER calling journal_end
-*/
-static int allow_flush_page_lock(struct page *page, 
-				   struct inode *inode) {
-
-  struct reiserfs_page_list *pl ;
-  struct super_block *s = inode->i_sb ;
-  /* we don't care if the inode has a stale pointer from an old
-  ** transaction
-  */
-  if(!page || inode->u.reiserfs_i.i_conversion_trans_id != SB_JOURNAL(s)->j_trans_id) {
-    return 0 ;
-  }
-  pl = inode->u.reiserfs_i.i_converted_page ;
-  if (pl && pl->page == page) {
-    pl->do_not_lock = 0 ;
-  }
-  return 0 ;
- 
-}
-
 /* If this page has a file tail in it, and
 ** it was read in by get_block_create_0, the page data is valid,
 ** but tail is still sitting in a direct item, and we can't write to
@@ -593,7 +543,6 @@
 	return -EIO;
     }
 
-    prevent_flush_page_lock(bh_result->b_page, inode) ;
     inode->u.reiserfs_i.i_pack_on_close = 1 ;
 
     windex = push_journal_writer("reiserfs_get_block") ;
@@ -687,7 +636,6 @@
 	if (transaction_started)
 	    journal_end(&th, inode->i_sb, jbegin_count) ;
 
-	allow_flush_page_lock(bh_result->b_page, inode) ;
 	unlock_kernel() ;
 	 
 	/* the item was found, so new blocks were not added to the file
@@ -796,8 +744,12 @@
 	    /* we've converted the tail, so we must 
 	    ** flush unbh before the transaction commits
 	    */
-	    reiserfs_add_page_to_flush_list(&th, inode, unbh) ;
-	    mark_buffer_dirty(unbh) ;
+	    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) ;
 		  
 	    //inode->i_blocks += inode->i_sb->s_blocksize / 512;
 	    //mark_tail_converted (inode);
@@ -891,7 +843,6 @@
       journal_end(&th, inode->i_sb, jbegin_count) ;
     }
     pop_journal_writer(windex) ;
-    allow_flush_page_lock(bh_result->b_page, inode) ;
     unlock_kernel() ;
     reiserfs_check_path(&path) ;
     return retval;
@@ -1658,13 +1609,11 @@
     ** because the truncate might pack the item anyway 
     ** (it will unmap bh if it packs).
     */
-    prevent_flush_page_lock(page, p_s_inode) ;
     journal_begin(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
     windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
     reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
     pop_journal_writer(windex) ;
     journal_end(&th, p_s_inode->i_sb,  JOURNAL_PER_BALANCE_CNT * 2 ) ;
-    allow_flush_page_lock(page, p_s_inode) ;
 
     if (page) {
         length = offset & (blocksize - 1) ;
@@ -1706,7 +1655,6 @@
 
 start_over:
     lock_kernel() ;
-    prevent_flush_page_lock(bh_result->b_page, inode) ;
     journal_begin(&th, inode->i_sb, jbegin_count) ;
 
     make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3) ;
@@ -1772,7 +1720,6 @@
 out:
     pathrelse(&path) ;
     journal_end(&th, inode->i_sb, jbegin_count) ;
-    allow_flush_page_lock(bh_result->b_page, inode) ;
     unlock_kernel() ;
 
     /* this is where we fill in holes in the file. */
@@ -1936,29 +1883,27 @@
   return generic_block_bmap(as, block, reiserfs_bmap) ;
 }
 
+static int reiserfs_commit_write(struct file *f, struct page *page,
+			         unsigned from, unsigned to) {
+    struct inode *inode = page->mapping->host;
+    int ret ;
 
-static int reiserfs_commit_write(struct file *f, struct page *page, 
-                                 unsigned from, unsigned to) {
-    struct inode *inode = page->mapping->host ;
-    int ret ; 
-    struct reiserfs_transaction_handle th ;
-    
     reiserfs_wait_on_write_block(inode->i_sb) ;
-    lock_kernel();
-    prevent_flush_page_lock(page, inode) ;
     ret = generic_commit_write(f, page, from, to) ;
+
     /* we test for O_SYNC here so we can commit the transaction
     ** for any packed tails the file might have had
     */
     if (f->f_flags & O_SYNC) {
+	struct reiserfs_transaction_handle th ;
+	lock_kernel() ;
 	journal_begin(&th, inode->i_sb, 1) ;
 	reiserfs_prepare_for_journal(inode->i_sb, 
 	                             SB_BUFFER_WITH_SB(inode->i_sb), 1) ;
 	journal_mark_dirty(&th, inode->i_sb, SB_BUFFER_WITH_SB(inode->i_sb)) ;
 	journal_end_sync(&th, inode->i_sb, 1) ;
+	unlock_kernel() ;
     }
-    allow_flush_page_lock(page, inode) ;
-    unlock_kernel();
     return ret ;
 }
 
fs/reiserfs/journal.c +5 -282

323 lines not on this page · raw message

fs/reiserfs/stree.c +19 -34

73 lines not on this page · raw message

include/linux/reiserfs_fs.h +0 -23
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
@@ -1541,29 +1541,6 @@
   __u32 j_mount_id ;
 } ;
 
-/* these are used to keep flush pages that contain converted direct items.
-** if the page is not flushed before the transaction that converted it
-** is committed, we risk losing data
-**
-** note, while a page is in this list, its counter is incremented.
-*/
-struct reiserfs_page_list {
-  struct reiserfs_page_list *next ;
-  struct reiserfs_page_list *prev ;
-  struct page *page ;
-  unsigned long blocknr ; /* block number holding converted data */
-
-  /* if a transaction writer has the page locked the flush_page_list
-  ** function doesn't need to (and can't) get the lock while flushing
-  ** the page.  do_not_lock needs to be set by anyone who calls journal_end
-  ** with a page lock held.  They have to look in the inode and see
-  ** if the inode has the page they have locked in the flush list.
-  **
-  ** this sucks.
-  */
-  int do_not_lock ; 
-} ;
-
 extern task_queue reiserfs_commit_thread_tq ;
 extern wait_queue_head_t reiserfs_commit_thread_wait ;
 
include/linux/reiserfs_fs_i.h +0 -20
diff -Nru a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
@@ -3,11 +3,6 @@
 
 #include <linux/list.h>
 
-/* these are used to keep track of the pages that need
-** flushing before the current transaction can commit
-*/
-struct reiserfs_page_list ;
-
 struct reiserfs_inode_info {
   __u32 i_key [4];/* key is still 4 32 bit integers */
   
@@ -21,21 +16,6 @@
   int i_pack_on_close ; // file might need tail packing on close 
 
   __u32 i_first_direct_byte; // offset of first byte stored in direct item.
-
-  /* pointer to the page that must be flushed before 
-  ** the current transaction can commit.
-  **
-  ** this pointer is only used when the tail is converted back into
-  ** a direct item, or the file is deleted
-  */
-  struct reiserfs_page_list *i_converted_page ;
-
-  /* we save the id of the transaction when we did the direct->indirect
-  ** conversion.  That allows us to flush the buffers to disk
-  ** without having to update this inode to zero out the converted
-  ** page variable
-  */
-  int i_conversion_trans_id ;
 
 				/* My guess is this contains the first
                                    unused block of a sequence of
include/linux/reiserfs_fs_sb.h +1 -0
diff -Nru a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
@@ -249,6 +249,7 @@
   int j_free_bitmap_nodes ;
   int j_used_bitmap_nodes ;
   struct list_head j_bitmap_nodes ;
+  struct inode j_dummy_inode ;
   struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ;	/* array of bitmaps to record the deleted blocks */
   struct reiserfs_journal_list j_journal_list[JOURNAL_LIST_COUNT] ;	    /* array of all the journal lists */
   struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; 	    /* hash table for real buffer heads in current trans */