Index: current/include/linux/swap.h =================================================================== --- current.orig/include/linux/swap.h 2007-02-03 18:22:21.000000000 -0800 +++ current/include/linux/swap.h 2007-02-03 18:22:47.000000000 -0800 @@ -181,6 +181,7 @@ extern unsigned int nr_free_pagecache_pa extern void FASTCALL(lru_cache_add(struct page *)); extern void FASTCALL(lru_cache_add_active(struct page *)); extern void FASTCALL(lru_cache_add_tail(struct page *)); +extern void FASTCALL(lru_cache_add_mlock(struct page *)); extern void FASTCALL(activate_page(struct page *)); extern void FASTCALL(mark_page_accessed(struct page *)); extern void lru_add_drain(void); Index: current/mm/memory.c =================================================================== --- current.orig/mm/memory.c 2007-02-03 18:22:55.000000000 -0800 +++ current/mm/memory.c 2007-02-03 18:23:23.000000000 -0800 @@ -682,10 +682,8 @@ static unsigned long zap_pte_range(struc file_rss--; } page_remove_rmap(page, vma); - if (vma->vm_flags & VM_LOCKED) { - __dec_zone_page_state(page, NR_MLOCK); - lru_cache_add_active(page); - } + if (vma->vm_flags & VM_LOCKED) + lru_cache_add_mlock(page); tlb_remove_page(tlb, page); continue; } Index: current/mm/swap.c =================================================================== --- current.orig/mm/swap.c 2007-02-03 18:16:35.000000000 -0800 +++ current/mm/swap.c 2007-02-03 18:24:50.000000000 -0800 @@ -178,6 +178,7 @@ EXPORT_SYMBOL(mark_page_accessed); static DEFINE_PER_CPU(struct pagevec, lru_add_pvecs) = { 0, }; static DEFINE_PER_CPU(struct pagevec, lru_add_active_pvecs) = { 0, }; static DEFINE_PER_CPU(struct pagevec, lru_add_tail_pvecs) = { 0, }; +static DEFINE_PER_CPU(struct pagevec, lru_add_mlock_pvecs) = { 0, }; void fastcall lru_cache_add(struct page *page) { @@ -199,6 +200,16 @@ void fastcall lru_cache_add_active(struc put_cpu_var(lru_add_active_pvecs); } +void fastcall lru_cache_add_mlock(struct page *page) +{ + struct pagevec *pvec = &get_cpu_var(lru_add_mlock_pvecs); + + page_cache_get(page); + if (!pagevec_add(pvec, page)) + __pagevec_lru_add_mlock(pvec); + put_cpu_var(lru_add_mlock_pvecs); +} + static void __pagevec_lru_add_tail(struct pagevec *pvec) { int i; @@ -237,6 +248,9 @@ static void __lru_add_drain(int cpu) pvec = &per_cpu(lru_add_tail_pvecs, cpu); if (pagevec_count(pvec)) __pagevec_lru_add_tail(pvec); + pvec = &per_cpu(lru_add_mlock_pvecs, cpu); + if (pagevec_count(pvec)) + __pagevec_lru_add_mlock(pvec); } void lru_add_drain(void) @@ -432,6 +446,33 @@ void __pagevec_lru_add_active(struct pag pagevec_reinit(pvec); } +void __pagevec_lru_add_mlock(struct pagevec *pvec) +{ + int i; + struct zone *zone = NULL; + + for (i = 0; i < pagevec_count(pvec); i++) { + struct page *page = pvec->pages[i]; + struct zone *pagezone = page_zone(page); + + if (pagezone != zone) { + if (zone) + spin_unlock_irq(&zone->lru_lock); + zone = pagezone; + spin_lock_irq(&zone->lru_lock); + } + if (PageLRU(page)) + continue; + __dec_zone_state(zone, NR_MLOCK); + SetPageLRU(page); + add_page_to_active_list(zone, page); + } + if (zone) + spin_unlock_irq(&zone->lru_lock); + release_pages(pvec->pages, pvec->nr, pvec->cold); + pagevec_reinit(pvec); +} + /* * Function used uniquely to put pages back to the lru at the end of the * inactive list to preserve the lru order. Currently only used by swap Index: current/include/linux/pagevec.h =================================================================== --- current.orig/include/linux/pagevec.h 2007-02-03 18:25:29.000000000 -0800 +++ current/include/linux/pagevec.h 2007-02-03 18:25:39.000000000 -0800 @@ -25,6 +25,7 @@ void __pagevec_release_nonlru(struct pag void __pagevec_free(struct pagevec *pvec); void __pagevec_lru_add(struct pagevec *pvec); void __pagevec_lru_add_active(struct pagevec *pvec); +void __pagevec_lru_add_mlock(struct pagevec *pvec); void pagevec_strip(struct pagevec *pvec); unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, pgoff_t start, unsigned nr_pages); Index: current/mm/mlock.c =================================================================== --- current.orig/mm/mlock.c 2007-02-03 18:29:40.000000000 -0800 +++ current/mm/mlock.c 2007-02-03 18:34:54.000000000 -0800 @@ -10,7 +10,7 @@ #include #include #include - +#include static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, unsigned long start, unsigned long end, unsigned int newflags) @@ -63,6 +63,23 @@ success: pages = -pages; if (!(newflags & VM_IO)) ret = make_pages_present(start, end); + } else { + unsigned long addr; + /* + * We are clearing VM_LOCKED. Feed all pages back via + * to the LRU via lru_cache_add_mlock() + */ + for (addr = start; addr < end; addr += PAGE_SIZE) { + /* + * No need to get a page reference. mmap_sem + * writelock is held. + */ + struct page *page = follow_page(vma, start, 0); + + if (page) + lru_cache_add_mlock(page); + cond_resched(); + } } mm->locked_vm -= pages;