2.4.1 has a memory leak (temporary) where anonymous memory pages that have
been moved into the swap cache will stick around after their vma has been
unmapped by the owning process.  These pages are not free'd in free_pte()
because they are still referenced by the page cache.  In addition, if the
pages are dirty, they will be written out to the swap device before they
are reclaimed even though the owning process no longer will be using the
pages.

free_pte in mm/memory.c has been modified to check to see if the page is
only being referenced by the swap cache (and possibly buffers).  If so,
the buffers (if existant) are free'd and the page and swap cache
entry are removed immediately.

Rich Jerrell
[EMAIL PROTECTED]
diff --recursive -u -N linux-2.4.1/mm/memory.c linux-2.4.1-paging-fix/mm/memory.c
--- linux-2.4.1/mm/memory.c     Sat Jan 27 22:12:35 2001
+++ linux-2.4.1-paging-fix/mm/memory.c  Thu Feb 15 13:36:06 2001
@@ -281,6 +285,33 @@
                return 1;
        }
        swap_free(pte_to_swp_entry(pte));
+       {
+               int num, target = 1;
+               struct page *page = lookup_swap_cache(pte_to_swp_entry(pte));
+                                   /* returns the page and takes a reference */
+               
+               if (!page || (!VALID_PAGE(page)) || PageReserved(page))
+                       return 0;
+               
+               num = atomic_read(&page->count);
+               if(page->buffers) target++;             /* 1 count if we have buffers 
+*/
+               if(PageSwapCache(page)) target++;       /* 1 count for the page cache 
+*/
+                                                       /* 1 count for our reference  
+*/
+
+               if((num == target) && PageSwapCache(page)) {
+                       /* SwapCache entry is the only thing referencing this page   
+*/
+                       /* (and maybe buffers) asides from us, so to prevent it from 
+*/
+                       /* sitting around and wasting time/memory, throw it away     
+*/
+                       if((page->buffers)) {
+                               if(!try_to_free_buffers(page,1)) {      /* Can't get 
+rid of buffers   */
+                                       page_cache_release(page);       /* get rid of 
+our reference   */
+                                       return 0;                       /* and let 
+someone else do it */
+                               }
+                       }
+                       free_page_and_swap_cache(page); /* Expects the page to be 
+mapped, so will */
+                       return 1;                       /* account for the reference 
+we have      */
+               }
+       }
        return 0;
 }
 

Reply via email to