[PATCH 2/4] swap: Add ability to mark swap pages bad

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add swap_free_markbad(), equivalent to swap_free but marks the swap page
as bad. Update try_to_unuse_entry() and shmem_unuse() to call the new
function when working on pages with errors.

These patches are a based on a patch by Nick Piggin and some of my own
patches/bugfixes as discussed on LKML.

Signed-off-by: Richard Purdie <[email protected]>

---
 include/linux/swap.h |    1 +
 mm/shmem.c           |   17 ++++++++++-------
 mm/swap_state.c      |    2 ++
 mm/swapfile.c        |   38 +++++++++++++++++++++++++++++---------
 4 files changed, 42 insertions(+), 16 deletions(-)

Index: git/include/linux/swap.h
===================================================================
--- git.orig/include/linux/swap.h	2007-01-07 21:39:26.000000000 +0000
+++ git/include/linux/swap.h	2007-01-08 11:39:36.000000000 +0000
@@ -244,6 +244,7 @@ extern swp_entry_t get_swap_page_of_type
 extern int swap_duplicate(swp_entry_t);
 extern int valid_swaphandles(swp_entry_t, unsigned long *);
 extern void swap_free(swp_entry_t);
+extern void swap_free_markbad(swp_entry_t);
 extern void free_swap_and_cache(swp_entry_t);
 extern int swap_type_of(dev_t, sector_t, struct block_device **);
 extern unsigned int count_swap_pages(int, int);
Index: git/mm/shmem.c
===================================================================
--- git.orig/mm/shmem.c	2007-01-07 21:39:29.000000000 +0000
+++ git/mm/shmem.c	2007-01-08 11:39:36.000000000 +0000
@@ -734,7 +734,7 @@ static int shmem_unuse_inode(struct shme
 	struct page **dir;
 	struct page *subdir;
 	swp_entry_t *ptr;
-	int offset;
+	int offset, moved, error;
 
 	idx = 0;
 	ptr = info->i_direct;
@@ -792,17 +792,20 @@ lost2:
 found:
 	idx += offset;
 	inode = &info->vfs_inode;
-	if (move_from_swap_cache(page, idx, inode->i_mapping) == 0) {
+	error = PageError(page);
+	moved = (move_from_swap_cache(page, idx, inode->i_mapping) == 0);
+	if (moved) {
 		info->flags |= SHMEM_PAGEIN;
 		shmem_swp_set(info, ptr + offset, 0);
 	}
 	shmem_swp_unmap(ptr);
 	spin_unlock(&info->lock);
-	/*
-	 * Decrement swap count even when the entry is left behind:
-	 * try_to_unuse will skip over mms, then reincrement count.
-	 */
-	swap_free(entry);
+	if (moved) {
+		if (!error)
+			swap_free(entry);
+		else
+			swap_free_markbad(entry);
+	}
 	return 1;
 }
 
Index: git/mm/swapfile.c
===================================================================
--- git.orig/mm/swapfile.c	2007-01-08 11:39:27.000000000 +0000
+++ git/mm/swapfile.c	2007-01-08 11:39:36.000000000 +0000
@@ -304,6 +304,23 @@ void swap_free(swp_entry_t entry)
 	}
 }
 
+void swap_free_markbad(swp_entry_t entry)
+{
+	struct swap_info_struct * p;
+
+	p = swap_info_get(entry);
+	if (p) {
+		unsigned long offset = swp_offset(entry);
+		if (swap_entry_free(p, offset) == 0) {
+			p->swap_map[offset] = SWAP_MAP_BAD;
+			p->pages--;
+			nr_swap_pages--;
+			total_swap_pages--;
+		}
+		spin_unlock(&swap_lock);
+	}
+}
+
 /*
  * How many references to page are currently swapped out?
  */
@@ -764,11 +781,6 @@ retry:
 	 * remains (rarer), it will be read from disk into another page.
 	 * Splitting into two pages would be incorrect if swap supported
 	 * "shared private" pages, but they are handled by tmpfs files.
-	 *
-	 * Note shmem_unuse already deleted a swappage from the swap cache,
-	 * unless the move to filepage failed: in which case it left swappage
-	 * in cache, lowered its swap count to pass quickly through the loops
-	 * above, and now we must reincrement count to try again later.
 	 */
 	if (PageSwapCache(page)) {
 		if ((*swap_map > 1) && PageDirty(page)) {
@@ -781,11 +793,19 @@ retry:
 			wait_on_page_writeback(page);
 			goto retry;
 		}
+		if (!shmem) {
+			int error = PageError(page);
 
-		if (shmem)
-			swap_duplicate(entry);
-		else
-			delete_from_swap_cache(page);
+			write_lock_irq(&swapper_space.tree_lock);
+			__delete_from_swap_cache(page);
+			write_unlock_irq(&swapper_space.tree_lock);
+			page_cache_release(page); /* the swapcache ref */
+
+			if (!error)
+				swap_free(entry);
+			else
+				swap_free_markbad(entry);
+		}
 	}
 
 	/*
Index: git/mm/swap_state.c
===================================================================
--- git.orig/mm/swap_state.c	2007-01-07 21:39:29.000000000 +0000
+++ git/mm/swap_state.c	2007-01-08 11:39:36.000000000 +0000
@@ -131,6 +131,8 @@ void __delete_from_swap_cache(struct pag
 	radix_tree_delete(&swapper_space.page_tree, page_private(page));
 	set_page_private(page, 0);
 	ClearPageSwapCache(page);
+	if (unlikely(PageError(page)))
+		ClearPageError(page);
 	total_swapcache_pages--;
 	__dec_zone_page_state(page, NR_FILE_PAGES);
 	INC_CACHE_INFO(del_total);


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux