Skip to contentSkip to conversation

fix dirty page management

PATCH In review Andrew Morton 1 participant 1 message May 19, 2002

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 4/15 fix dirty page management

Fixes a bug in ext3 - when ext3 decides that it wants to fail its writepage(), it is running SetPageDirty(). But ->writepage has just put the page on ->clean_pages(). The page ends up dirty, on ->clean_pages and the normal writeback paths don't know about it any more.

So run set_page_dirty() instead, to place the page back on the dirty list.

And in move_from_swap_cache(), shuffle the page across to ->dirty_pages so that it's eligible for writeout. ___add_to_page_cache() forgets to look at the page state when deciding which list to attach it to.

All SetPageDirty() callers otherwise look OK.

=====================================

fs/ext3/inode.c renamed from fs/ext3/inode.c~set_page_dirty +1 -1
@@ -1325,7 +1325,7 @@ static int ext3_writepage(struct page *p
 out_fail:
 	
 	unlock_kernel();
-	SetPageDirty(page);
+	set_page_dirty(page);
 	unlock_page(page);
 	return ret;
 }
mm/filemap.c renamed from mm/filemap.c~set_page_dirty +3 -0
@@ -425,6 +425,9 @@ void invalidate_inode_pages2(struct addr
  *  - activate the page so that the page stealer
  *    doesn't try to write it out over and over
  *    again.
+ *
+ * NOTE!  The livelock in fdatasync went away, due to io_pages.
+ * So this function can now call set_page_dirty().
  */
 int fail_writepage(struct page *page)
 {
mm/swap_state.c renamed from mm/swap_state.c~set_page_dirty +8 -0
@@ -220,8 +220,16 @@ int move_from_swap_cache(struct page *pa
 		page->flags &= ~(1 << PG_uptodate | 1 << PG_error |
 				 1 << PG_referenced | 1 << PG_arch_1 |
 				 1 << PG_checked);
+		/*
+		 * ___add_to_page_cache puts the page on ->clean_pages,
+		 * but it's dirty.  If it's on ->clean_pages, it will basically
+		 * never get written out.
+		 */
 		SetPageDirty(page);
 		___add_to_page_cache(page, mapping, index);
+		/* fix that up */
+		list_del(&page->list);
+		list_add(&page->list, &mapping->dirty_pages);
 	}
 
 	write_unlock(&mapping->page_lock);
mm/swapfile.c renamed from mm/swapfile.c~set_page_dirty +5 -0
@@ -311,6 +311,11 @@ int remove_exclusive_swap_page(struct pa
 		write_lock(&swapper_space.page_lock);
 		if (page_count(page) - !!PagePrivate(page) == 2) {
 			__delete_from_swap_cache(page);
+			/*
+			 * NOTE: if/when swap gets buffer/page coherency
+			 * like other mappings, we'll need to mark the buffers
+			 * dirty here too.  set_page_dirty().
+			 */
 			SetPageDirty(page);
 			retval = 1;
 		}

-