public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 9/19] leave swapcache pages unlocked during writeout
@ 2002-06-17  6:52 Andrew Morton
  0 siblings, 0 replies; only message in thread
From: Andrew Morton @ 2002-06-17  6:52 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: lkml, Hugh Dickins



Convert swap pages so that they are PageWriteback and !PageLocked while
under writeout, like all other block-backed pages.  (Network
filesystems aren't doing this yet - their pages are still locked while
under writeout)



--- 2.5.22/mm/swapfile.c~swap-pages-unlocked	Sun Jun 16 22:50:18 2002
+++ 2.5.22-akpm/mm/swapfile.c	Sun Jun 16 23:22:47 2002
@@ -298,6 +298,8 @@ int remove_exclusive_swap_page(struct pa
 		BUG();
 	if (!PageSwapCache(page))
 		return 0;
+	if (PageWriteback(page))
+		return 0;
 	if (page_count(page) - !!PagePrivate(page) != 2) /* 2: us + cache */
 		return 0;
 
@@ -311,7 +313,8 @@ int remove_exclusive_swap_page(struct pa
 	if (p->swap_map[swp_offset(entry)] == 1) {
 		/* Recheck the page count with the pagecache lock held.. */
 		write_lock(&swapper_space.page_lock);
-		if (page_count(page) - !!PagePrivate(page) == 2) {
+		if ((page_count(page) - !!page_has_buffers(page) == 2) &&
+					!PageWriteback(page)) {
 			__delete_from_swap_cache(page);
 			/*
 			 * NOTE: if/when swap gets buffer/page coherency
@@ -326,7 +329,6 @@ int remove_exclusive_swap_page(struct pa
 	swap_info_put(p);
 
 	if (retval) {
-		BUG_ON(PageWriteback(page));
 		if (page_has_buffers(page) && !try_to_free_buffers(page))
 			BUG();
 		swap_free(entry);
@@ -352,9 +354,12 @@ void free_swap_and_cache(swp_entry_t ent
 		swap_info_put(p);
 	}
 	if (page) {
+		int one_user;
+
 		page_cache_get(page);
+		one_user = (page_count(page) - !!page_has_buffers(page) == 2);
 		/* Only cache user (+us), or swap space full? Free it! */
-		if (page_count(page) - !!PagePrivate(page) == 2 || vm_swap_full()) {
+		if (!PageWriteback(page) && (one_user || vm_swap_full())) {
 			delete_from_swap_cache(page);
 			SetPageDirty(page);
 		}
@@ -606,6 +611,7 @@ static int try_to_unuse(unsigned int typ
 		wait_on_page_locked(page);
 		wait_on_page_writeback(page);
 		lock_page(page);
+		wait_on_page_writeback(page);
 
 		/*
 		 * Remove all references to entry, without blocking.
@@ -688,8 +694,10 @@ static int try_to_unuse(unsigned int typ
 			rw_swap_page(WRITE, page);
 			lock_page(page);
 		}
-		if (PageSwapCache(page))
+		if (PageSwapCache(page)) {
+			wait_on_page_writeback(page);
 			delete_from_swap_cache(page);
+		}
 
 		/*
 		 * So we could skip searching mms once swap count went
--- 2.5.22/mm/swap_state.c~swap-pages-unlocked	Sun Jun 16 22:50:18 2002
+++ 2.5.22-akpm/mm/swap_state.c	Sun Jun 16 23:22:47 2002
@@ -131,10 +131,9 @@ int add_to_swap_cache(struct page *page,
  */
 void __delete_from_swap_cache(struct page *page)
 {
-	if (!PageLocked(page))
-		BUG();
-	if (!PageSwapCache(page))
-		BUG();
+	BUG_ON(!PageLocked(page));
+	BUG_ON(!PageSwapCache(page));
+	BUG_ON(PageWriteback(page));
 	ClearPageDirty(page);
 	__remove_inode_page(page);
 	INC_CACHE_INFO(del_total);
--- 2.5.22/mm/shmem.c~swap-pages-unlocked	Sun Jun 16 22:50:18 2002
+++ 2.5.22-akpm/mm/shmem.c	Sun Jun 16 22:50:18 2002
@@ -426,15 +426,22 @@ found:
 	swap_free(entry);
 	ptr[offset] = (swp_entry_t) {0};
 
-	while (inode && move_from_swap_cache(page, idx, inode->i_mapping)) {
+	while (inode && (PageWriteback(page) ||
+			move_from_swap_cache(page, idx, inode->i_mapping))) {
 		/*
 		 * Yield for kswapd, and try again - but we're still
 		 * holding the page lock - ugh! fix this up later on.
 		 * Beware of inode being unlinked or truncated: just
 		 * leave try_to_unuse to delete_from_swap_cache if so.
+		 *
+		 * AKPM: We now wait on writeback too.  Note that it's
+		 * the page lock which prevents new writeback from starting.
 		 */
 		spin_unlock(&info->lock);
-		yield();
+		if (PageWriteback(page))
+			wait_on_page_writeback(page);
+		else
+			yield();
 		spin_lock(&info->lock);
 		ptr = shmem_swp_entry(info, idx, 0);
 		if (IS_ERR(ptr))
@@ -594,9 +601,14 @@ repeat:
 		}
 
 		/* We have to do this with page locked to prevent races */
-		if (TestSetPageLocked(page)) 
+		if (TestSetPageLocked(page))
 			goto wait_retry;
-
+		if (PageWriteback(page)) {
+			spin_unlock(&info->lock);
+			wait_on_page_writeback(page);
+			unlock_page(page);
+			goto repeat;
+		}
 		error = move_from_swap_cache(page, idx, mapping);
 		if (error < 0) {
 			unlock_page(page);
@@ -651,7 +663,7 @@ no_space:
 	return ERR_PTR(-ENOSPC);
 
 wait_retry:
-	spin_unlock (&info->lock);
+	spin_unlock(&info->lock);
 	wait_on_page_locked(page);
 	page_cache_release(page);
 	goto repeat;
--- 2.5.22/fs/buffer.c~swap-pages-unlocked	Sun Jun 16 22:50:18 2002
+++ 2.5.22-akpm/fs/buffer.c	Sun Jun 16 23:22:47 2002
@@ -542,14 +542,6 @@ static void end_buffer_async_read(struct
 	 */
 	if (page_uptodate && !PageError(page))
 		SetPageUptodate(page);
-
-	/*
-	 * swap page handling is a bit hacky.  A standalone completion handler
-	 * for swapout pages would fix that up.  swapin can use this function.
-	 */
-	if (PageSwapCache(page) && PageWriteback(page))
-		end_page_writeback(page);
-
 	unlock_page(page);
 	return;
 
@@ -559,8 +551,9 @@ still_busy:
 }
 
 /*
- * Completion handler for block_write_full_page() - pages which are unlocked
- * during I/O, and which have PageWriteback cleared upon I/O completion.
+ * Completion handler for block_write_full_page() and for brw_page() - pages
+ * which are unlocked during I/O, and which have PageWriteback cleared
+ * upon I/O completion.
  */
 static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
 {
@@ -2283,16 +2276,6 @@ int brw_kiovec(int rw, int nr, struct ki
  *
  * FIXME: we need a swapper_inode->get_block function to remove
  *        some of the bmap kludges and interface ugliness here.
- *
- * NOTE: unlike file pages, swap pages are locked while under writeout.
- * This is to throttle processes which reuse their swapcache pages while
- * they are under writeout, and to ensure that there is no I/O going on
- * when the page has been successfully locked.  Functions such as
- * free_swap_and_cache() need to guarantee that there is no I/O in progress
- * because they will be freeing up swap blocks, which may then be reused.
- *
- * Swap pages are also marked PageWriteback when they are being written
- * so that memory allocators will throttle on them.
  */
 int brw_page(int rw, struct page *page,
 		struct block_device *bdev, sector_t b[], int size)
@@ -2314,18 +2297,17 @@ int brw_page(int rw, struct page *page,
 		if (rw == WRITE) {
 			set_buffer_uptodate(bh);
 			clear_buffer_dirty(bh);
+			mark_buffer_async_write(bh);
+		} else {
+			mark_buffer_async_read(bh);
 		}
-		/*
-		 * Swap pages are locked during writeout, so use
-		 * buffer_async_read in strange ways.
-		 */
-		mark_buffer_async_read(bh);
 		bh = bh->b_this_page;
 	} while (bh != head);
 
 	if (rw == WRITE) {
 		BUG_ON(PageWriteback(page));
 		SetPageWriteback(page);
+		unlock_page(page);
 	}
 
 	/* Stage 2: start the IO */

-

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-06-17  6:51 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-06-17  6:52 [patch 9/19] leave swapcache pages unlocked during writeout Andrew Morton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox