Re: new swap cache regime

Andrea Arcangeli (andrea@e-mind.com)
Fri, 25 Sep 1998 15:41:28 +0200 (CEST)


nOn Thu, 24 Sep 1998, Andrea Arcangeli wrote:

>On Thu, 24 Sep 1998, Andrea Arcangeli wrote:
>
>>I implemented a simple way to handle the swap cache persistence (the
>>suggestion to leave the swap cache always alloced came from Linus btw).
>
>Excuse me, I forgot the subject in my last email...

I produced a new patch. This new one fix a little stupid thing in the last
one (it was setting last_page as the page removed from the swap cache ;-).
This new patch also limit a bit more the search in the swap cache list if
the priority is low (high in number). It also shrink the swap cache when
the swapout code can' t find a free entry. This helps very much (I cheked
that it works most of the time when the system is stressed) and give more
balance the the system.

No problem so far on P5MMXUP. Everything _seems_ stable and not leaking.

Here the latest patch:

diff -urN /home/andrea/devel/kernel-tree/linux-2.1.122/include/linux/swap.h linux/include/linux/swap.h
--- /home/andrea/devel/kernel-tree/linux-2.1.122/include/linux/swap.h Sat Sep 5 14:17:56 1998
+++ linux/include/linux/swap.h Fri Sep 25 14:49:47 1998
@@ -89,6 +89,7 @@
extern int swap_check_entry(unsigned long);
extern struct page * read_swap_cache_async(unsigned long, int);
#define read_swap_cache(entry) read_swap_cache_async(entry, 1);
+extern int shrink_swap_cache(int, int);
/*
* Make these inline later once they are working properly.
*/
@@ -146,14 +147,9 @@
*/
static inline int is_page_shared(struct page *page)
{
- int count = atomic_read(&page->count);
if (PageReserved(page))
return 1;
- if (page->inode == &swapper_inode)
- count--;
- if (PageFreeAfter(page))
- count--;
- return (count > 1);
+ return atomic_read(&page->count) > 1;
}

#endif /* __KERNEL__*/
diff -urN /home/andrea/devel/kernel-tree/linux-2.1.122/mm/page_alloc.c linux/mm/page_alloc.c
--- /home/andrea/devel/kernel-tree/linux-2.1.122/mm/page_alloc.c Thu Sep 10 23:56:48 1998
+++ linux/mm/page_alloc.c Thu Sep 24 17:55:28 1998
@@ -163,9 +163,11 @@
free_pages_ok(page->map_nr, 0);
return;
}
+#if 0
if (PageSwapCache(page) && atomic_read(&page->count) == 1)
printk(KERN_WARNING "VM: Releasing swap cache page at %p",
__builtin_return_address(0));
+#endif
}

void free_pages(unsigned long addr, unsigned long order)
@@ -182,10 +184,12 @@
free_pages_ok(map_nr, order);
return;
}
+#if 0
if (PageSwapCache(map) && atomic_read(&map->count) == 1)
printk(KERN_WARNING
"VM: Releasing swap cache pages at %p",
__builtin_return_address(0));
+#endif
}
}

diff -urN /home/andrea/devel/kernel-tree/linux-2.1.122/mm/swap_state.c linux/mm/swap_state.c
--- /home/andrea/devel/kernel-tree/linux-2.1.122/mm/swap_state.c Thu Sep 10 23:56:48 1998
+++ linux/mm/swap_state.c Fri Sep 25 15:07:47 1998
@@ -5,6 +5,7 @@
* Swap reorganised 29.12.95, Stephen Tweedie
*
* Rewritten to use page cache, (C) 1998 Stephen Tweedie
+ * Shrinking of the swap cache, Andrea Arcangeli
*/

#include <linux/mm.h>
@@ -155,6 +156,7 @@
printk ("VM: Removing swap cache page with wrong inode hash "
"on page %08lx\n", page_address(page));
}
+#if 0
/*
* This is a legal case, but warn about it.
*/
@@ -163,6 +165,7 @@
"VM: Removing page cache on unshared page %08lx\n",
page_address(page));
}
+#endif

#ifdef DEBUG_SWAP
printk("DebugVM: remove_from_swap_cache(%08lx count %d)\n",
@@ -300,4 +303,63 @@
__free_page(new_page);
out:
return found_page;
+}
+
+/*
+ * This routine deal with shrinking the swap cache. -arca
+ */
+int shrink_swap_cache(int priority, int gfp_mask)
+{
+ unsigned long cycles;
+ struct page *page;
+ static struct page *last_page = NULL;
+
+ cycles = (swapper_inode.i_nrpages << 2) >> (priority >> 1);
+ if (cycles > swapper_inode.i_nrpages)
+ cycles = swapper_inode.i_nrpages;
+
+ if (last_page && PageSwapCache(last_page) &&
+ last_page->next && last_page->prev)
+ page = last_page;
+ else
+ page = swapper_inode.i_pages;
+
+ /* PARANOID */
+ if (!page && cycles)
+ {
+ printk(KERN_ERR "VM: swap cache page NULL but not empty "
+ "swap cache list!\n");
+ goto out;
+ }
+ while (cycles--)
+ {
+ /* PARANOID */
+ if (!PageSwapCache(page) ||
+ page->inode != &swapper_inode)
+ {
+ printk(KERN_ERR "VM: found a no swap_cache page "
+ "in the swap cache!\n");
+ goto out;
+ }
+ if ((gfp_mask & __GFP_DMA) && !PageDMA(page))
+ goto next;
+ switch (atomic_read(&page->count))
+ {
+ case 0:
+ printk(KERN_ERR "VM: found a now swap page cache "
+ "in the swap cache!\n");
+ goto out;
+ case 1:
+ last_page = page->next;
+ delete_from_swap_cache(page);
+ return 1;
+ }
+ next:
+ if (!(page = page->next))
+ if (!(page = swapper_inode.i_pages))
+ goto out;
+ }
+ out:
+ last_page = page;
+ return 0;
}
diff -urN /home/andrea/devel/kernel-tree/linux-2.1.122/mm/swapfile.c linux/mm/swapfile.c
--- /home/andrea/devel/kernel-tree/linux-2.1.122/mm/swapfile.c Thu Sep 10 23:56:48 1998
+++ linux/mm/swapfile.c Fri Sep 25 14:53:03 1998
@@ -79,6 +79,7 @@
unsigned long offset, entry;
int type, wrapped = 0;

+ try_again:
type = swap_list.next;
if (type < 0)
return 0;
@@ -111,6 +112,8 @@
wrapped = 1;
}
} else if (type < 0) {
+ if (shrink_swap_cache(0, GFP_KERNEL))
+ goto try_again;
return 0; /* out of swap space */
}
}
diff -urN /home/andrea/devel/kernel-tree/linux-2.1.122/mm/vmscan.c linux/mm/vmscan.c
--- /home/andrea/devel/kernel-tree/linux-2.1.122/mm/vmscan.c Thu Sep 10 23:56:48 1998
+++ linux/mm/vmscan.c Thu Sep 24 18:40:55 1998
@@ -465,18 +465,22 @@
switch (state) {
do {
case 0:
- if (shrink_mmap(i, gfp_mask))
+ if (shrink_swap_cache(i, gfp_mask))
return 1;
state = 1;
case 1:
- if (shm_swap(i, gfp_mask))
+ if (shrink_mmap(i, gfp_mask))
return 1;
state = 2;
case 2:
- if (swap_out(i, gfp_mask))
+ if (shm_swap(i, gfp_mask))
return 1;
state = 3;
case 3:
+ if (swap_out(i, gfp_mask))
+ return 1;
+ state = 4;
+ case 4:
shrink_dcache_memory(i, gfp_mask);
state = 0;
i--;

Andrea[s] Arcangeli

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/