linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* [RFC] 2/4 Migration Cache - add mm checks
@ 2006-02-17 15:37 Lee Schermerhorn
  2006-02-17 16:32 ` Christoph Lameter
  0 siblings, 1 reply; 3+ messages in thread
From: Lee Schermerhorn @ 2006-02-17 15:37 UTC (permalink / raw)
  To: linux-mm; +Cc: Christoph Lameter, Marcelo Tosatti

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.

Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com>

Index: linux-2.6.16-rc3-mm1/mm/memory.c
===================================================================
--- linux-2.6.16-rc3-mm1.orig/mm/memory.c	2006-02-15 10:50:43.000000000 -0500
+++ linux-2.6.16-rc3-mm1/mm/memory.c	2006-02-15 10:50:53.000000000 -0500
@@ -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);
Index: linux-2.6.16-rc3-mm1/mm/swap_state.c
===================================================================
--- linux-2.6.16-rc3-mm1.orig/mm/swap_state.c	2006-02-15 10:50:47.000000000 -0500
+++ linux-2.6.16-rc3-mm1/mm/swap_state.c	2006-02-15 10:50:53.000000000 -0500
@@ -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
Index: linux-2.6.16-rc3-mm1/mm/swapfile.c
===================================================================
--- linux-2.6.16-rc3-mm1.orig/mm/swapfile.c	2006-02-15 10:50:43.000000000 -0500
+++ linux-2.6.16-rc3-mm1/mm/swapfile.c	2006-02-15 10:50:53.000000000 -0500
@@ -298,6 +298,11 @@ void swap_free(swp_entry_t entry)
 {
 	struct swap_info_struct * p;
 
+	if (unlikely(migration_type(swp_type(entry)))) {
+		migration_remove_entry(entry, 1);
+		return;
+	}
+
 	p = swap_info_get(entry);
 	if (p) {
 		swap_entry_free(p, swp_offset(entry));
@@ -315,6 +320,10 @@ static inline int page_swapcount(struct 
 	swp_entry_t entry;
 
 	entry.val = page_private(page);
+
+	if (unlikely(migration_type(swp_type(entry))))
+		return migration_ref_count(entry);
+
 	p = swap_info_get(entry);
 	if (p) {
 		/* Subtract the 1 for the swap cache itself */
@@ -360,6 +369,24 @@ int remove_exclusive_swap_page(struct pa
 		return 0;
 
 	entry.val = page_private(page);
+	/*
+	 * Don't call swap_info_get() for migration type.
+	 */
+	if (unlikely(migration_type(swp_type(entry)))) {
+		/*
+TODO: following applies to "lazy page migration" only:
+		 * If we get here with a migration cache page,
+		 * do_swap_page() has handled a migration cache page and
+		 * swap is > 1/2 full, or we are in exit/unmap path, and
+		 * page is already present in current's pte.  The reason
+		 * it is still in the migration cache is because the
+		 * page is shared by other processes [ancestors or
+		 * decendants].  So, just ignore it.
+		 * TODO: page_cache_release?
+		 */
+		return 0;
+	}
+
 	p = swap_info_get(entry);
 	if (!p)
 		return 0;
@@ -395,6 +422,11 @@ void free_swap_and_cache(swp_entry_t ent
 	struct swap_info_struct * p;
 	struct page *page = NULL;
 
+	if (unlikely(migration_type(swp_type(entry)))) {
+		migration_remove_entry(entry, 0);
+		return;
+	}
+
 	p = swap_info_get(entry);
 	if (p) {
 		if (swap_entry_free(p, swp_offset(entry)) == 1)
@@ -1415,6 +1447,15 @@ asmlinkage long sys_swapon(const char __
 		spin_unlock(&swap_lock);
 		goto out;
 	}
+
+	/*
+	 * MIGRATION_TYPE is reserved for [stolen by] the migration cache
+	 */
+	if (migration_type(type)) {
+		spin_unlock(&swap_lock);
+		goto out;
+	}
+
 	if (type >= nr_swapfiles)
 		nr_swapfiles = type+1;
 	INIT_LIST_HEAD(&p->extent_list);
@@ -1702,6 +1743,12 @@ int swap_duplicate(swp_entry_t entry)
 	int result = 0;
 
 	type = swp_type(entry);
+
+	if (unlikely(migration_type(type))) {
+		migration_duplicate(entry);
+		return 1;
+	}
+
 	if (type >= nr_swapfiles)
 		goto bad_file;
 	p = type + swap_info;
Index: linux-2.6.16-rc3-mm1/include/linux/mm.h
===================================================================
--- linux-2.6.16-rc3-mm1.orig/include/linux/mm.h	2006-02-15 10:50:43.000000000 -0500
+++ linux-2.6.16-rc3-mm1/include/linux/mm.h	2006-02-15 10:50:53.000000000 -0500
@@ -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;
 }
Index: linux-2.6.16-rc3-mm1/mm/vmscan.c
===================================================================
--- linux-2.6.16-rc3-mm1.orig/mm/vmscan.c	2006-02-15 10:50:43.000000000 -0500
+++ linux-2.6.16-rc3-mm1/mm/vmscan.c	2006-02-15 10:50:53.000000000 -0500
@@ -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 */
 
Index: linux-2.6.16-rc3-mm1/mm/rmap.c
===================================================================
--- linux-2.6.16-rc3-mm1.orig/mm/rmap.c	2006-02-15 10:50:43.000000000 -0500
+++ linux-2.6.16-rc3-mm1/mm/rmap.c	2006-02-15 10:50:53.000000000 -0500
@@ -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 majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC] 2/4 Migration Cache - add mm checks
  2006-02-17 15:37 [RFC] 2/4 Migration Cache - add mm checks Lee Schermerhorn
@ 2006-02-17 16:32 ` Christoph Lameter
  2006-02-17 17:09   ` Lee Schermerhorn
  0 siblings, 1 reply; 3+ messages in thread
From: Christoph Lameter @ 2006-02-17 16:32 UTC (permalink / raw)
  To: Lee Schermerhorn; +Cc: linux-mm, Christoph Lameter, Marcelo Tosatti

On Fri, 17 Feb 2006, Lee Schermerhorn wrote:

> Index: linux-2.6.16-rc3-mm1/mm/vmscan.c
> ===================================================================
> --- linux-2.6.16-rc3-mm1.orig/mm/vmscan.c	2006-02-15 10:50:43.000000000 -0500
> +++ linux-2.6.16-rc3-mm1/mm/vmscan.c	2006-02-15 10:50:53.000000000 -0500
> @@ -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 */


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().

> Index: linux-2.6.16-rc3-mm1/mm/rmap.c
> ===================================================================
> --- linux-2.6.16-rc3-mm1.orig/mm/rmap.c	2006-02-15 10:50:43.000000000 -0500
> +++ linux-2.6.16-rc3-mm1/mm/rmap.c	2006-02-15 10:50:53.000000000 -0500
> @@ -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

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 majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC] 2/4 Migration Cache - add mm checks
  2006-02-17 16:32 ` Christoph Lameter
@ 2006-02-17 17:09   ` Lee Schermerhorn
  0 siblings, 0 replies; 3+ messages in thread
From: Lee Schermerhorn @ 2006-02-17 17:09 UTC (permalink / raw)
  To: Christoph Lameter; +Cc: linux-mm, Christoph Lameter, Marcelo Tosatti

On Fri, 2006-02-17 at 08:32 -0800, Christoph Lameter wrote:
> On Fri, 17 Feb 2006, Lee Schermerhorn wrote:
> 
> > Index: linux-2.6.16-rc3-mm1/mm/vmscan.c
> > ===================================================================
> > --- linux-2.6.16-rc3-mm1.orig/mm/vmscan.c	2006-02-15 10:50:43.000000000 -0500
> > +++ linux-2.6.16-rc3-mm1/mm/vmscan.c	2006-02-15 10:50:53.000000000 -0500
> > @@ -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 */
> 
> 
> 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.

> 
> > Index: linux-2.6.16-rc3-mm1/mm/rmap.c
> > ===================================================================
> > --- linux-2.6.16-rc3-mm1.orig/mm/rmap.c	2006-02-15 10:50:43.000000000 -0500
> > +++ linux-2.6.16-rc3-mm1/mm/rmap.c	2006-02-15 10:50:53.000000000 -0500
> > @@ -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
> 
> 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 majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-02-17 17:09 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-02-17 15:37 [RFC] 2/4 Migration Cache - add mm checks Lee Schermerhorn
2006-02-17 16:32 ` Christoph Lameter
2006-02-17 17:09   ` Lee Schermerhorn

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