Skip to contentSkip to conversation

2/4 Migration Cache - add mm checks

RFC In review Lee Schermerhorn 2 participants 3 messages Feb 17, 2006

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

RFC 1/1 2/4 Migration Cache - add mm checks

Migration Cache "V8" 2/4

This patch add the necessary checks for whether a page that appears to be in the swap cache is really in the migration cache. Most of these checks are hidden behind the normal swap interfaces, and are, thus, limited to the swap sources. However, a couple of them spill over into mm/memory.c and vmscan.c.

mm/memory.c +8 -0
Index: linux-2.6.16-rc3-mm1/mm/memory.c
===================================================================
@@ -1825,6 +1825,14 @@ void swapin_readahead(swp_entry_t entry,
 	unsigned long offset;
 
 	/*
+	 * no-op for migration cache entries.
+	 * do_swap_page() or shmem_getpage() might hand us one of these.
+TODO:   should be BUG_ON()?
+	 */
+	if (migration_type(swp_type(entry)))
+		return;
+
+	/*
 	 * Get the number of handles we should do readahead io to.
 	 */
 	num = valid_swaphandles(entry, &offset);
mm/swap_state.c +14 -0
Index: linux-2.6.16-rc3-mm1/mm/swap_state.c
===================================================================
@@ -393,6 +393,7 @@ int add_to_swap(struct page * page, gfp_
 
 	if (!PageLocked(page))
 		BUG();
+	BUG_ON(page_is_migration(page));
 
 	for (;;) {
 		entry = get_swap_page();
@@ -543,6 +544,11 @@ struct page * lookup_swap_cache(swp_entr
 {
 	struct page *page;
 
+	if (migration_type(swp_type(entry))) {
+		page = lookup_migration_cache(entry);
+		return page;
+	}
+
 	page = find_get_page(&swapper_space, entry.val);
 
 	if (page)
@@ -564,6 +570,14 @@ struct page *read_swap_cache_async(swp_e
 	struct page *found_page, *new_page = NULL;
 	int err;
 
+	/*
+	 * return NULL for migration cache entries.
+	 * do_swap_page() or shmem_swapin() might hand us one of these.
+TODO:  should be BUG_ON() ?
+	 */
+	if (migration_type(swp_type(entry)))
+		return NULL;
+
 	do {
 		/*
 		 * First check the swap cache.  Since this is normally
mm/swapfile.c +47 -0

83 lines not on this page · raw message

include/linux/mm.h +14 -3
Index: linux-2.6.16-rc3-mm1/include/linux/mm.h
===================================================================
@@ -547,6 +547,14 @@ void page_address_init(void);
 #define page_address_init()  do { } while(0)
 #endif
 
+#ifdef CONFIG_MIGRATION
+//TODO:  can I make this 'static inline' here?  header dependencies?
+extern int page_is_migration(struct page *);
+extern struct address_space migration_space;
+#else
+#define page_is_migration(p) (0)
+#endif
+
 /*
  * On an anonymous page mapped into a user virtual memory area,
  * page->mapping points to its anon_vma, not to a struct address_space;
@@ -563,9 +571,12 @@ static inline struct address_space *page
 {
 	struct address_space *mapping = page->mapping;
 
-	if (unlikely(PageSwapCache(page)))
-		mapping = &swapper_space;
-	else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
+	if (unlikely(PageSwapCache(page))) {
+		if (unlikely(page_is_migration(page)))
+			mapping = &migration_space;
+		else
+			mapping = &swapper_space;
+	} else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
 		mapping = NULL;
 	return mapping;
 }
mm/vmscan.c +12 -4
Index: linux-2.6.16-rc3-mm1/mm/vmscan.c
===================================================================
@@ -457,11 +457,19 @@ static unsigned long shrink_page_list(st
 		 * Anonymous process memory has backing store?
 		 * Try to allocate it some swap space here.
 		 */
-		if (PageAnon(page) && !PageSwapCache(page)) {
-			if (!sc->may_swap)
+		if (PageAnon(page)) {
+			if (!PageSwapCache(page)) {
+				if (!sc->may_swap)
+					goto keep_locked;
+				if (!add_to_swap(page, GFP_ATOMIC))
+					goto activate_locked;
+			} else if (page_is_migration(page)) {
+				/*
+				 * For now, skip migration cache pages.
+				 * TODO:  move to swap cache [difficult?]
+				 */
 				goto keep_locked;
-			if (!add_to_swap(page, GFP_ATOMIC))
-				goto activate_locked;
+			}
 		}
 #endif /* CONFIG_SWAP */
 
mm/rmap.c +7 -1
Index: linux-2.6.16-rc3-mm1/mm/rmap.c
===================================================================
@@ -232,7 +232,13 @@ void remove_from_swap(struct page *page)
 
 	spin_unlock(&anon_vma->lock);
 
-	delete_from_swap_cache(page);
+	if (PageSwapCache(page))
+		delete_from_swap_cache(page);
+	/*
+	 * if page was in migration cache, it will have been
+	 * removed when the last swap pte referencing the entry
+	 * was removed by the loop above.
+	 */
 }
 EXPORT_SYMBOL(remove_from_swap);
 #endif

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw
Quoted 17 lines · Lee Schermerhorn

Index: linux-2.6.16-rc3-mm1/mm/vmscan.c
===================================================================

mm/vmscan.c +7 -2
@@ -457,11 +457,19 @@ static unsigned long shrink_page_list(st
 		 * Anonymous process memory has backing store?
 		 * Try to allocate it some swap space here.
 		 */
-		if (PageAnon(page) && !PageSwapCache(page)) {
-			if (!sc->may_swap)
+		if (PageAnon(page)) {
+			if (!PageSwapCache(page)) {
+				if (!sc->may_swap)
+					goto keep_locked;
+				if (!add_to_swap(page, GFP_ATOMIC))
+					goto activate_locked;
+			} else if (page_is_migration(page)) {

mm/vmscan.c static unsigned long shrink_page_list(st · line 474

Quoted 10 lines
mm/vmscan.c +5 -2
+				/*
+				 * For now, skip migration cache pages.
+				 * TODO:  move to swap cache [difficult?]
+				 */
 				goto keep_locked;
-			if (!add_to_swap(page, GFP_ATOMIC))
-				goto activate_locked;
+			}
 		}
 #endif /* CONFIG_SWAP */

Would it not be simpler to modify add_to_swap to switch from migration pte to a real swap pte or simply fail? Then you wont have to touch shrink_page().

Quoted 9 lines

Index: linux-2.6.16-rc3-mm1/mm/rmap.c
===================================================================

mm/rmap.c +0 -1
@@ -232,7 +232,13 @@ void remove_from_swap(struct page *page)
 
 	spin_unlock(&anon_vma->lock);
 
-	delete_from_swap_cache(page);

mm/rmap.c void remove_from_swap(struct page *page) · line 244

Quoted 10 lines
mm/rmap.c +7 -0
+	if (PageSwapCache(page))
+		delete_from_swap_cache(page);
+	/*
+	 * if page was in migration cache, it will have been
+	 * removed when the last swap pte referencing the entry
+	 * was removed by the loop above.
+	 */
 }
 EXPORT_SYMBOL(remove_from_swap);
 #endif

Hmmm. That points to inconsistent behavior of the swap functions in case these are working on the migration cache. Could you keep PageSwapCache until delete_from_swap_cache is called?

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#2 lore raw
Quoted 26 lines · Christoph Lameter
Quoted 24 lines · Lee Schermerhorn

Index: linux-2.6.16-rc3-mm1/mm/vmscan.c
===================================================================

mm/vmscan.c +11 -4
@@ -457,11 +457,19 @@ static unsigned long shrink_page_list(st
 		 * Anonymous process memory has backing store?
 		 * Try to allocate it some swap space here.
 		 */
-		if (PageAnon(page) && !PageSwapCache(page)) {
-			if (!sc->may_swap)
+		if (PageAnon(page)) {
+			if (!PageSwapCache(page)) {
+				if (!sc->may_swap)
+					goto keep_locked;
+				if (!add_to_swap(page, GFP_ATOMIC))
+					goto activate_locked;
+			} else if (page_is_migration(page)) {
+				/*
+				 * For now, skip migration cache pages.
+				 * TODO:  move to swap cache [difficult?]
+				 */
 				goto keep_locked;
-			if (!add_to_swap(page, GFP_ATOMIC))
-				goto activate_locked;
Quoted 8 lines

mm/vmscan.c static unsigned long shrink_page_list(st · line 474

Quoted 3 lines
mm/vmscan.c +1 -0
+			}
 		}
 #endif /* CONFIG_SWAP */

Would it not be simpler to modify add_to_swap to switch from migration pte to a real swap pte or simply fail? Then you wont have to touch shrink_page().

I can look into that. This is new, untested code for comment, so thanks.

Quoted 9 lines
Quoted 9 lines

Index: linux-2.6.16-rc3-mm1/mm/rmap.c
===================================================================

mm/rmap.c +0 -0
@@ -232,7 +232,13 @@ void remove_from_swap(struct page *page)
 
 	spin_unlock(&anon_vma->lock);
 
Quoted 15 lines

mm/rmap.c void remove_from_swap(struct page *page) · line 244

Quoted 11 lines
mm/rmap.c +7 -1
-	delete_from_swap_cache(page);
+	if (PageSwapCache(page))
+		delete_from_swap_cache(page);
+	/*
+	 * if page was in migration cache, it will have been
+	 * removed when the last swap pte referencing the entry
+	 * was removed by the loop above.
+	 */
 }
 EXPORT_SYMBOL(remove_from_swap);
 #endif

Hmmm. That points to inconsistent behavior of the swap functions in case these are working on the migration cache. Could you keep PageSwapCache until delete_from_swap_cache is called?

Well, one could redesign the migration cache such that the cache held a ref
on the entry, like the swap cache. Then we'd need an explicit call later to
destroy the entry. I guess this would happen when we free the page. Pages
would just tend to hang around in the migration cache for no reason after
all ptes references had been removed. Short of that, I don't think we can
keep the PageSwapCache() set when the page really isn't in either the swap
nor migration cache.

A simpler, but perhaps riskier?, approach would be to have delete_from_swap_cache() silently ingnore pages that are no longer in the swap cache. Currently, the lower level __delete_from_swap_cache() will BUG_ON this case. Making delete_from_swap_cache() forgiving in this case would handle the call from remove_from_swap() above.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>