Skip to contentSkip to conversation

Migration cache

PATCH In review Marcelo Tosatti 3 participants 11 messages Oct 14, 2004 – Oct 24, 2004

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

PATCH 1/1 Migration cache

Hi MM fellows,

So as I've said before in my opinion moving pages to the swapcache to migrate them is unnacceptable for several reasons. Not to mention live memory defragmentation.

So the following patch, on top of the v2.6 -memoryhotplug tree, creates a migration cache - which is basically a swapcache without using the swap map - it instead uses a on-memory idr structure.

For that we decrease SWP_TYPE_SHIFT from 5 to 4, and use that now-free bit to indicate pte's which point to pages on the migration cache.

It still needs more testing, but it successfully migrates a zone while "fillmem" runs on it, on an SMP box.

Need more testing for integration into -mhp, its being done.

I think it needs to be able to transform "migration cache pages" (which still exist until all pte's referencing a page fault-in) into "swapcache pages" by going through the reserve mapping and transforming the "migration pte's" into "swapcache pte's" (with allocated swap space).

As soon as we have this working and stable we can go for "nonblocking" version of mmigrate.c work for defragmentation.

Comments are very welcome

Be warned, it contains debug printk's.

include/linux/mm.h +4 -1
diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/include/linux/mm.h linux-2.6.9-rc2-mm4.build/include/linux/mm.h
@@ -458,12 +458,15 @@
 #define PAGE_MAPPING_ANON	1
 
 extern struct address_space swapper_space;
+extern struct address_space migration_space;
 static inline struct address_space *page_mapping(struct page *page)
 {
 	struct address_space *mapping = page->mapping;
 
 	if (unlikely(PageSwapCache(page)))
 		mapping = &swapper_space;
+	else if (unlikely(PageMigration(page)))
+		mapping = &migration_space;
 	else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON))
 		mapping = NULL;
 	return mapping;
@@ -480,7 +483,7 @@
  */
 static inline pgoff_t page_index(struct page *page)
 {
-	if (unlikely(PageSwapCache(page)))
+	if (unlikely(PageSwapCache(page)) || unlikely(PageMigration(page)))
 		return page->private;
 	return page->index;
 }
include/linux/page-flags.h +5 -0
diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/include/linux/page-flags.h linux-2.6.9-rc2-mm4.build/include/linux/page-flags.h
@@ -83,6 +83,7 @@
  * -- daveh
  */
 #define PG_capture		19	/* Remove page for memory hotplug */
+#define PG_migration		20	/* Remove page for memory hotplug */
 
 /*
  * Global page accounting.  One instance per CPU.  Only unsigned longs are
@@ -339,6 +340,10 @@
 #define SetPageUnderCapture(page)	set_bit(PG_capture, &(page)->flags)
 #define ClearPageUnderCapture(page)	clear_bit(PG_capture, &(page)->flags)
 
+#define PageMigration(page)	test_bit(PG_migration, &(page)->flags)
+#define SetPageMigration(page)	set_bit(PG_migration, &(page)->flags)
+#define ClearPageMigration(page)	clear_bit(PG_migration, &(page)->flags)
+
 static inline void set_page_under_capture(struct page *page)
 {
 	SetPageUnderCapture(page);
include/linux/swap.h +1 -1
diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/include/linux/swap.h linux-2.6.9-rc2-mm4.build/include/linux/swap.h
@@ -27,7 +27,7 @@
  * on 32-bit-pgoff_t architectures.  And that assumes that the architecture packs
  * the type/offset into the pte as 5/27 as well.
  */
-#define MAX_SWAPFILES_SHIFT	5
+#define MAX_SWAPFILES_SHIFT	4
 #define MAX_SWAPFILES		(1 << MAX_SWAPFILES_SHIFT)
 
 /*
include/linux/swapops.h +31 -4
diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/include/linux/swapops.h linux-2.6.9-rc2-mm4.build/include/linux/swapops.h
@@ -10,7 +10,7 @@
  * swp_entry_t's are *never* stored anywhere in their arch-dependent format.
  */
 #define SWP_TYPE_SHIFT(e)	(sizeof(e.val) * 8 - MAX_SWAPFILES_SHIFT)
-#define SWP_OFFSET_MASK(e)	((1UL << SWP_TYPE_SHIFT(e)) - 1)
+#define SWP_OFFSET_MASK(e)	((1UL << (SWP_TYPE_SHIFT(e)-1))  - 1)
 
 /*
  * Store a type+offset into a swp_entry_t in an arch-independent format
@@ -19,7 +19,7 @@
 {
 	swp_entry_t ret;
 
-	ret.val = (type << SWP_TYPE_SHIFT(ret)) |
+	ret.val = type << SWP_TYPE_SHIFT(ret) |
 			(offset & SWP_OFFSET_MASK(ret));
 	return ret;
 }
@@ -30,8 +30,12 @@
  */
 static inline unsigned swp_type(swp_entry_t entry)
 {
-	return (entry.val >> SWP_TYPE_SHIFT(entry)) &
-			((1 << MAX_SWAPFILES_SHIFT) - 1);
+	return ((entry.val >> SWP_TYPE_SHIFT(entry)));
+}
+
+static inline unsigned migration_type(swp_entry_t entry)
+{
+	return 1;
 }
 
 /*
@@ -68,3 +72,26 @@
 	BUG_ON(pte_file(__swp_entry_to_pte(arch_entry)));
 	return __swp_entry_to_pte(arch_entry);
 }
+
+static inline int pte_is_migration(pte_t pte)
+{
+	unsigned long swp_type;
+	swp_entry_t arch_entry;
+
+	arch_entry = __pte_to_swp_entry(pte);
+
+	swp_type = __swp_type(arch_entry);
+
+	if (swp_type & 1)
+		return 1;
+	else 
+		return 0;
+}
+
+static inline pte_t migration_entry_to_pte(swp_entry_t entry)
+{
+	swp_entry_t arch_entry;
+	
+	arch_entry = __swp_entry(migration_type(entry), swp_offset(entry));
+	return __swp_entry_to_pte(arch_entry);
+}
mm/memory.c +25 -7
diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/memory.c linux-2.6.9-rc2-mm4.build/mm/memory.c
@@ -456,8 +456,13 @@
 		 */
 		if (unlikely(details))
 			continue;
-		if (!pte_file(pte))
-			free_swap_and_cache(pte_to_swp_entry(pte));
+		if (!pte_file(pte)) {
+			swp_entry_t swp_entry = pte_to_swp_entry(pte);
+			if (pte_is_migration(pte)) {
+				migration_remove_entry(swp_entry);
+			} else
+				free_swap_and_cache(swp_entry);
+		}
 		pte_clear(ptep);
 	}
 	pte_unmap(ptep-1);
@@ -1408,6 +1413,9 @@
 	pte_unmap(page_table);
 	spin_unlock(&mm->page_table_lock);
 again:
+	if (pte_is_migration(orig_pte)) {
+		page = lookup_migration_cache(entry.val & SWP_OFFSET_MASK(entry));
+	} else {
 	page = lookup_swap_cache(entry);
 	if (!page) {
  		swapin_readahead(entry, address, vma);
@@ -1433,7 +1441,6 @@
 		inc_page_state(pgmajfault);
 		grab_swap_token();
 	}
-
 	mark_page_accessed(page);
 	lock_page(page);
 	if (!PageSwapCache(page)) {
@@ -1442,6 +1449,13 @@
 		page_cache_release(page);
 		goto again;
 	}
+	}
+
+
+	if (pte_is_migration(orig_pte)) {
+		mark_page_accessed(page);
+		lock_page(page);
+	}
 
 	/*
 	 * Back out if somebody else faulted in this pte while we
@@ -1459,10 +1473,14 @@
 	}
 
 	/* The page isn't present yet, go ahead with the fault. */
-		
-	swap_free(entry);
-	if (vm_swap_full())
-		remove_exclusive_swap_page(page);
+
+	if (!pte_is_migration(orig_pte)) {
+		swap_free(entry);
+		if (vm_swap_full())
+			remove_exclusive_swap_page(page);
+	} else {
+		migration_remove_reference(page);
+	}
 
 	mm->rss++;
 	pte = mk_pte(page, vma->vm_page_prot);
mm/mmigrate.c +183 -5

239 lines not on this page · raw message

mm/rmap.c +29 -15

51 lines not on this page · raw message

mm/vmscan.c +1 -1
diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/vmscan.c linux-2.6.9-rc2-mm4.build/mm/vmscan.c
@@ -354,7 +354,7 @@
 		 * Anonymous process memory has backing store?
 		 * Try to allocate it some swap space here.
 		 */
-		if (PageAnon(page) && !PageSwapCache(page)) {
+		if (PageAnon(page) && !PageSwapCache(page) && !PageMigration(page)) {
 			if (!add_to_swap(page, GFP_ATOMIC))
 				goto activate_locked;
 		}

--
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

Hi, Marcelo,

Give me few days to check it.

Quoted 9 lines

Hi MM fellows,

So as I've said before in my opinion moving pages to the swapcache to migrate them is unnacceptable for several reasons. Not to mention live memory defragmentation.

So the following patch, on top of the v2.6 -memoryhotplug tree, creates a migration cache - which is basically a swapcache without using the swap map - it instead uses a on-memory idr structure.

Thanks,
Hirokazu Takahashi.
--
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
In reply to Marcelo Tosatti

Hi, Marcelo,

Quoted 10 lines

So as I've said before in my opinion moving pages to the swapcache to migrate them is unnacceptable for several reasons. Not to mention live memory defragmentation.

So the following patch, on top of the v2.6 -memoryhotplug tree, creates a migration cache - which is basically a swapcache without using the swap map - it instead uses a on-memory idr structure.

For that we decrease SWP_TYPE_SHIFT from 5 to 4, and use that now-free bit to indicate pte's which point to pages on the migration cache.

I guess it would be better to reserve one swap type for the migration cache instead of reserving the bit to reduce the impact of the maximum number of swap types.
However, I think your approach is good enough for the first implementation.

Quoted 1 line

Comments are very welcome

I'll continue to check the code.

include/linux/swapops.h line 22

Quoted 9 lines

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/include/linux/swapops.h linux-2.6.9-rc2-mm4.build/include/linux/swapops.h

include/linux/swapops.h +1 -1
@@ -19,7 +19,7 @@
 {
 	swp_entry_t ret;
 
-	ret.val = (type << SWP_TYPE_SHIFT(ret)) |
+	ret.val = type << SWP_TYPE_SHIFT(ret) |

I guess it's just for cleanups to remove the brackets, right?

mm/memory.c line 1446

Quoted 11 lines

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/memory.c linux-2.6.9-rc2-mm4.build/mm/memory.c

mm/memory.c +0 -1
@@ -1433,7 +1441,6 @@
 		inc_page_state(pgmajfault);
 		grab_swap_token();
 	}
-
 	mark_page_accessed(page);
 	lock_page(page);
 	if (!PageSwapCache(page)) {

I think the previous line should be
if (!PageSwapCache(page) && !PageMigration(page)) {

This line means to redo everything from the beginning if the page is not either in the swap-cache or in the migration-cache.

Quoted 18 lines
mm/memory.c +7 -0
@@ -1442,6 +1449,13 @@
 		page_cache_release(page);
 		goto again;
 	}
+	}
+
+
+	if (pte_is_migration(orig_pte)) {
+		mark_page_accessed(page);
+		lock_page(page);
+	}
 
 	/*
 	 * Back out if somebody else faulted in this pte while we

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/mmigrate.c linux-2.6.9-rc2-mm4.build/mm/mmigrate.c

mm/mmigrate.c line 121

Quoted 6 lines
mm/mmigrate.c +5 -0
 
+int migration_remove_entry(swp_entry_t entry)
+{
+	struct page *page;
+	
+	page = find_trylock_page(&migration_space, entry.val);

I guess there exits a race condition here.
If the page is locked unfortunately at this moment, who release it? Another process on another CPU may be handling page-fault against the page if it is shared with other processes.

The following code would be better?

	page = find_get_page(&migration_space, entry.val);
	if (page)
		lock_page(page);
Quoted 16 lines
mm/mmigrate.c +14 -0
+
+
+	if (printk_ratelimit())
+		printk(KERN_ERR "remove_from_migration_cache!!\n");
+
+
+	if (page) {
+		migration_remove_reference(page);
+		unlock_page(page);
+		page_cache_release(page);
+	}
+
+}
 
 
+int add_to_migration_cache(struct page *page, int gfp_mask) 

mm/mmigrate.c line 169

Quoted 10 lines
mm/mmigrate.c +10 -0
+{
+	int error, offset;
+	struct counter *counter;
+
+	BUG_ON(PageSwapCache(page));
+	BUG_ON(PagePrivate(page));
+	BUG_ON(PageMigration(page));
+
+        if (idr_pre_get(&migration_idr, GFP_ATOMIC) == 0)
+                return -ENOMEM;

GFP_KERNEL would be appropriate for the memory migration code, because the swap-code will make free pages in case of low memory. This is one of the different points from the swap-code, which can't specify such gfp_mask, as no one can prepare free pages for it.

mm/mmigrate.c line 173

Quoted 4 lines
mm/mmigrate.c +4 -0
+
+	error = radix_tree_preload(gfp_mask);
+
+	counter = kmalloc(sizeof(struct counter), GFP_KERNEL);

kmalloc() should be called before radix_tree_preload() because radix_tree_preload() disables preemption not to switch other processes during handling radix trees. However kmalloc() with GFP_KERNEL may be blocked to break this assumption.

Quoted 31 lines
mm/mmigrate.c +28 -0
+
+	counter->i = 0;
+	counter->magic = 0xdeadbeef;
+
+	if (!error) {
+		write_lock_irq(&migration_space.tree_lock);
+	        error = idr_get_new_above(&migration_idr, counter, 1, &offset);
+
+		if (error < 0)
+			BUG();
+
+		error = radix_tree_insert(&migration_space.page_tree, offset,
+							page);
+
+		if (!error) {
+			page_cache_get(page);
+			SetPageLocked(page);
+			page->private = offset;
+//			page->mapping = &migration_space;
+			SetPageMigration(page);
+		}
+		write_unlock_irq(&migration_space.tree_lock);
+                radix_tree_preload_end();
+
+	}
+
+	return error;
+}

mm/mmigrate.c line 574

Quoted 6 lines
mm/mmigrate.c +1 -2
@@ -399,11 +571,15 @@
 	 * Put the page in a radix tree if it isn't in the tree yet.
 	 */
 #ifdef CONFIG_SWAP
-	if (PageAnon(page) && !PageSwapCache(page))
-		if (!add_to_swap(page, GFP_KERNEL)) {
+	if (PageAnon(page) && !PageSwapCache(page) && !PageMigration(page))

I guess calling BUG() would be good if the page is already in the migration cache.

Quoted 16 lines
mm/mmigrate.c +5 -0
+		if (!add_to_migration_cache(page, GFP_KERNEL)) {
 			unlock_page(page);
 			return ERR_PTR(-ENOSPC);
 		}
+/*		if (!add_to_swap(page, GFP_KERNEL)) {
+			unlock_page(page);
+			return ERR_PTR(-ENOSPC);
+		} */
 #endif /* CONFIG_SWAP */
 	if ((mapping = page_mapping(page)) == NULL) {
 		/* truncation is in progress */

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/vmscan.c linux-2.6.9-rc2-mm4.build/mm/vmscan.c

mm/vmscan.c line 357

Quoted 5 lines
mm/vmscan.c +1 -1
@@ -354,7 +354,7 @@
 		 * Anonymous process memory has backing store?
 		 * Try to allocate it some swap space here.
 		 */
-		if (PageAnon(page) && !PageSwapCache(page)) {
+		if (PageAnon(page) && !PageSwapCache(page) && !PageMigration(page)) {

BUG_ON(PageMigration(page)) would be better, because it must not exist in the LRU. Target pages to migrate must have been removed from the LRU lists in advance, so that the swap code never grabs them.

mm/vmscan.c line 360

Quoted 3 lines
mm/vmscan.c +0 -0
 			if (!add_to_swap(page, GFP_ATOMIC))
 				goto activate_locked;
 		}

--
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>

#3 lore raw

Hi Hirokazu!

Quoted 10 lines · Hirokazu Takahashi

Hi, Marcelo,

Quoted 8 lines

So as I've said before in my opinion moving pages to the swapcache to migrate them is unnacceptable for several reasons. Not to mention live memory defragmentation.

So the following patch, on top of the v2.6 -memoryhotplug tree, creates a migration cache - which is basically a swapcache without using the swap map - it instead uses a on-memory idr structure.

Quoted 7 lines
Quoted 2 lines

For that we decrease SWP_TYPE_SHIFT from 5 to 4, and use that now-free bit to indicate pte's which point to pages on the migration cache.

I guess it would be better to reserve one swap type for the migration cache instead of reserving the bit to reduce the impact of the maximum number of swap types.
However, I think your approach is good enough for the first implementation.

By reserving one swap type we would also use a bit. Using a swap type is the same thing as using a bit in the swap pagetableentry. (the swap type has 5 bits reserved for swap devices, 2^5 = 32 swap devices).

?

Quoted 12 lines
Quoted 1 line

Comments are very welcome

I'll continue to check the code.

Quoted 7 lines

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/include/linux/swapops.h linux-2.6.9-rc2-mm4.build/include/linux/swapops.h

include/linux/swapops.h +0 -0
@@ -19,7 +19,7 @@
 {
 	swp_entry_t ret;
 
Quoted 4 lines

include/linux/swapops.h line 22

Quoted 2 lines
include/linux/swapops.h +1 -1
-	ret.val = (type << SWP_TYPE_SHIFT(ret)) |
+	ret.val = type << SWP_TYPE_SHIFT(ret) |

I guess it's just for cleanups to remove the brackets, right?

Actually its just because I've been messing around with this code.

It shouldnt be changed in the final patch :)

Quoted 15 lines

mm/memory.c line 1446

Quoted 11 lines

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/memory.c linux-2.6.9-rc2-mm4.build/mm/memory.c

mm/memory.c +0 -1
@@ -1433,7 +1441,6 @@
 		inc_page_state(pgmajfault);
 		grab_swap_token();
 	}
-
 	mark_page_accessed(page);
 	lock_page(page);
 	if (!PageSwapCache(page)) {

I think the previous line should be
if (!PageSwapCache(page) && !PageMigration(page)) {

Quoted 2 lines

This line means to redo everything from the beginning if the page is not either in the swap-cache or in the migration-cache.

Right. Added to the todo list.

Quoted 30 lines
Quoted 18 lines
mm/memory.c +7 -0
@@ -1442,6 +1449,13 @@
 		page_cache_release(page);
 		goto again;
 	}
+	}
+
+
+	if (pte_is_migration(orig_pte)) {
+		mark_page_accessed(page);
+		lock_page(page);
+	}
 
 	/*
 	 * Back out if somebody else faulted in this pte while we

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/mmigrate.c linux-2.6.9-rc2-mm4.build/mm/mmigrate.c

mm/mmigrate.c line 121

Quoted 6 lines
mm/mmigrate.c +5 -0
 
+int migration_remove_entry(swp_entry_t entry)
+{
+	struct page *page;
+	
+	page = find_trylock_page(&migration_space, entry.val);

I guess there exits a race condition here.
If the page is locked unfortunately at this moment, who release it? Another process on another CPU may be handling page-fault against the page if it is shared with other processes.

Quoted 4 lines

The following code would be better?

	page = find_get_page(&migration_space, entry.val);
	if (page)
		lock_page(page);

Correct! Now I also noticed that locking of the IDR structure needs to be done correctly for eg migration_remove_reference does idr_find() without any lock.

Quoted 24 lines
Quoted 24 lines
mm/mmigrate.c +22 -0
+
+
+	if (printk_ratelimit())
+		printk(KERN_ERR "remove_from_migration_cache!!\n");
+
+
+	if (page) {
+		migration_remove_reference(page);
+		unlock_page(page);
+		page_cache_release(page);
+	}
+
+}
 
 
+int add_to_migration_cache(struct page *page, int gfp_mask) 
+{
+	int error, offset;
+	struct counter *counter;
+
+	BUG_ON(PageSwapCache(page));
+	BUG_ON(PagePrivate(page));
+	BUG_ON(PageMigration(page));
+
Quoted 8 lines

mm/mmigrate.c line 169

Quoted 2 lines
mm/mmigrate.c +2 -0
+        if (idr_pre_get(&migration_idr, GFP_ATOMIC) == 0)
+                return -ENOMEM;

GFP_KERNEL would be appropriate for the memory migration code, because the swap-code will make free pages in case of low memory. This is one of the different points from the swap-code, which can't specify such gfp_mask, as no one can prepare free pages for it.

OK!

Quoted 10 lines

mm/mmigrate.c line 173

Quoted 5 lines
mm/mmigrate.c +4 -0
+
+	error = radix_tree_preload(gfp_mask);
+
+	counter = kmalloc(sizeof(struct counter), GFP_KERNEL);

kmalloc() should be called before radix_tree_preload() because radix_tree_preload() disables preemption not to switch other processes during handling radix trees. However kmalloc() with GFP_KERNEL may be blocked to break this assumption.

OK!

Quoted 30 lines
Quoted 28 lines
mm/mmigrate.c +28 -0
+
+	counter->i = 0;
+	counter->magic = 0xdeadbeef;
+
+	if (!error) {
+		write_lock_irq(&migration_space.tree_lock);
+	        error = idr_get_new_above(&migration_idr, counter, 1, &offset);
+
+		if (error < 0)
+			BUG();
+
+		error = radix_tree_insert(&migration_space.page_tree, offset,
+							page);
+
+		if (!error) {
+			page_cache_get(page);
+			SetPageLocked(page);
+			page->private = offset;
+//			page->mapping = &migration_space;
+			SetPageMigration(page);
+		}
+		write_unlock_irq(&migration_space.tree_lock);
+                radix_tree_preload_end();
+
+	}
+
+	return error;
+}
Quoted 10 lines

mm/mmigrate.c line 574

Quoted 7 lines
mm/mmigrate.c +1 -2
@@ -399,11 +571,15 @@
 	 * Put the page in a radix tree if it isn't in the tree yet.
 	 */
 #ifdef CONFIG_SWAP
-	if (PageAnon(page) && !PageSwapCache(page))
-		if (!add_to_swap(page, GFP_KERNEL)) {
+	if (PageAnon(page) && !PageSwapCache(page) && !PageMigration(page))

I guess calling BUG() would be good if the page is already in the migration cache.

Sure, can be done.

Quoted 13 lines
Quoted 12 lines
mm/mmigrate.c +5 -0
+		if (!add_to_migration_cache(page, GFP_KERNEL)) {
 			unlock_page(page);
 			return ERR_PTR(-ENOSPC);
 		}
+/*		if (!add_to_swap(page, GFP_KERNEL)) {
+			unlock_page(page);
+			return ERR_PTR(-ENOSPC);
+		} */
 #endif /* CONFIG_SWAP */
 	if ((mapping = page_mapping(page)) == NULL) {
 		/* truncation is in progress */
Quoted 13 lines

mm/vmscan.c line 357

Quoted 9 lines

diff -Nur linux-2.6.9-rc2-mm4.mhp.orig/mm/vmscan.c linux-2.6.9-rc2-mm4.build/mm/vmscan.c

mm/vmscan.c +1 -1
@@ -354,7 +354,7 @@
 		 * Anonymous process memory has backing store?
 		 * Try to allocate it some swap space here.
 		 */
-		if (PageAnon(page) && !PageSwapCache(page)) {
+		if (PageAnon(page) && !PageSwapCache(page) && !PageMigration(page)) {

BUG_ON(PageMigration(page)) would be better, because it must not exist in the LRU. Target pages to migrate must have been removed from the LRU lists in advance, so that the swap code never grabs them.

OK too!

Quoted 3 lines

mm/vmscan.c line 360

Quoted 3 lines
mm/vmscan.c +0 -0
 			if (!add_to_swap(page, GFP_ATOMIC))
 				goto activate_locked;
 		}

I'm working on something else today and probably tomorrow, later on I'll be making the changes you suggest and find any remaining bugs (I didnt mention but this is still oopsing for some reason in odd places).

So then we do some wider testing and merge it in the mainline -mhp patch!

Thanks for your comments.
--
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>

#4 lore raw
Quoted 5 lines · Marcelo Tosatti
Quoted 4 lines · Hirokazu Takahashi

I guess it would be better to reserve one swap type for the migration cache instead of reserving the bit to reduce the impact of the maximum number of swap types.

I thought the same ...

Quoted 3 lines

By reserving one swap type we would also use a bit. Using a swap type is the same thing as using a bit in the swap pagetableentry. (the swap type has 5 bits reserved for swap devices, 2^5 = 32 swap devices).

... and don't understand your response.

Reserving a swap type leaves 31 swap devices for normal use, okay; but reserving a bit leaves only 16 swap devices for normal use.

Hugh

--
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>

#5 lore raw
Quoted 9 lines · Hugh Dickins
Quoted 5 lines · Marcelo Tosatti
Quoted 4 lines · Hirokazu Takahashi

I guess it would be better to reserve one swap type for the migration cache instead of reserving the bit to reduce the impact of the maximum number of swap types.

I thought the same ...

Quoted 8 lines
Quoted 3 lines

By reserving one swap type we would also use a bit. Using a swap type is the same thing as using a bit in the swap pagetableentry. (the swap type has 5 bits reserved for swap devices, 2^5 = 32 swap devices).

... and don't understand your response.

Reserving a swap type leaves 31 swap devices for normal use, okay; but reserving a bit leaves only 16 swap devices for normal use.

Oh stupid idiot I am! Of course, we can then remove "pte_is_migration" (and all the related pte handling code).

Added to TODO list.

If anyone wants to contribute that it would be cool cause I'm quite busy with other stuff right now.

Thanks guys!
--
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>

#6 lore raw

Hi,

Quoted 19 lines · Hugh Dickins
Quoted 9 lines · Marcelo Tosatti
Quoted 5 lines · Hirokazu Takahashi
Quoted 4 lines

I guess it would be better to reserve one swap type for the migration cache instead of reserving the bit to reduce the impact of the maximum number of swap types.

I thought the same ...

Quoted 8 lines
Quoted 3 lines

By reserving one swap type we would also use a bit. Using a swap type is the same thing as using a bit in the swap pagetableentry. (the swap type has 5 bits reserved for swap devices, 2^5 = 32 swap devices).

... and don't understand your response.

Reserving a swap type leaves 31 swap devices for normal use, okay; but reserving a bit leaves only 16 swap devices for normal use.

Quoted 7 lines

Oh stupid idiot I am! Of course, we can then remove "pte_is_migration" (and all the related pte handling code).

Added to TODO list.

If anyone wants to contribute that it would be cool cause I'm quite busy with other stuff right now.

The following code is my simple idea, which might help you.

#define MIGRATION_TYPE (MAX_SWAPFILES - 1)

static inline int pte_is_migration(pte_t pte)

{
	unsigned long swp_type;
	swp_entry_t arch_entry;

	arch_entry = __pte_to_swp_entry(pte);

	swp_type = __swp_type(arch_entry);

	return swp_type == MIGRATION_TYPE;
}

static inline int PageMigration(page)

{ 
      swp_entry_t entry = { .val = page->private,};
      return (PageSwapCache(page) && swp_type(entry) == MIGRATION_TYPE);
}

Thanks,
Hirokazu Takahashi.
--
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>

#7 lore raw
Quoted 35 lines · Hirokazu Takahashi

Hi,

Quoted 19 lines · Hugh Dickins
Quoted 9 lines · Marcelo Tosatti
Quoted 5 lines · Hirokazu Takahashi
Quoted 4 lines

I guess it would be better to reserve one swap type for the migration cache instead of reserving the bit to reduce the impact of the maximum number of swap types.

I thought the same ...

Quoted 8 lines
Quoted 3 lines

By reserving one swap type we would also use a bit. Using a swap type is the same thing as using a bit in the swap pagetableentry. (the swap type has 5 bits reserved for swap devices, 2^5 = 32 swap devices).

... and don't understand your response.

Reserving a swap type leaves 31 swap devices for normal use, okay; but reserving a bit leaves only 16 swap devices for normal use.

Quoted 7 lines

Oh stupid idiot I am! Of course, we can then remove "pte_is_migration" (and all the related pte handling code).

Added to TODO list.

If anyone wants to contribute that it would be cool cause I'm quite busy with other stuff right now.

The following code is my simple idea, which might help you.

#define MIGRATION_TYPE (MAX_SWAPFILES - 1)

static inline int pte_is_migration(pte_t pte)

Quoted 10 lines
{
	unsigned long swp_type;
	swp_entry_t arch_entry;

	arch_entry = __pte_to_swp_entry(pte);

	swp_type = __swp_type(arch_entry);

	return swp_type == MIGRATION_TYPE;
}

OK thanks this code works fine (just pasted into swapops.h and tested). Thanks.

Quoted 5 lines

static inline int PageMigration(page)

{ 
      swp_entry_t entry = { .val = page->private,};
      return (PageSwapCache(page) && swp_type(entry) == MIGRATION_TYPE);
}

Oh and with that we no longer need PG_migration bit, but, page->private does not contain swp_type information (MIGRATION_TYPE bit) in it. Its simply an offset counting from 0 increasing sequentially.

ANDing migration type bit into the offset should work. --
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>

#8 lore raw
Quoted 6 lines · Marcelo Tosatti

Oh and with that we no longer need PG_migration bit, but, page->private does not contain swp_type information (MIGRATION_TYPE bit) in it. Its simply an offset counting from 0 increasing sequentially.

ANDing migration type bit into the offset should work.

I haven't looked, but wouldn't it be a lot easier to use the normal swap allocation code rather than going such a different idr way here?

Hugh

--
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>

#9 lore raw
Quoted 10 lines · Hugh Dickins
Quoted 6 lines · Marcelo Tosatti

Oh and with that we no longer need PG_migration bit, but, page->private does not contain swp_type information (MIGRATION_TYPE bit) in it. Its simply an offset counting from 0 increasing sequentially.

ANDing migration type bit into the offset should work.

I haven't looked, but wouldn't it be a lot easier to use the normal swap allocation code rather than going such a different idr way here?

Hi Hugh,

Well, the idr code is quite simple, but yes,
we could probably reuse the swap allocation code.

Would have to create a swap_info_struct, without
the swap extent stuff and no bdev pointer. May
require some modifications but should work.

BTW, while I was reading the code, I wondered:

struct swap_info_struct swap_info[MAX_SWAPFILES];

This array should be created dynamically. Worth
the trouble?
--
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>

#10 lore raw
Quoted 7 lines · Marcelo Tosatti

BTW, while I was reading the code, I wondered:

struct swap_info_struct swap_info[MAX_SWAPFILES];

This array should be created dynamically. Worth
the trouble?

It is rather primitive, but I don't think it's worth the trouble to change it on its own - certainly not worth changing it to allocate the full array at runtime, and if you changed it to allocate slot by slot then quite a few places (within swapfile.c) would need changing. I can imagine someone doing a big cleanup of swapfile.c in which that static array vanished, but I don't think it's worth doing on its own.

Hugh

--
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>