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.

Essentially, this is the same patch as before, but there was one condition
in which case we would leak and extra reference to the targeted page if
the counts would not allow us to remove the swap cache entry.  The leak in
2.4.1 also applies to 2.4.2 and 2.4.3-pre5.

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,34 @@
                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      */
+               }
+               page_cache_release(page);       /* Remove our reference, we can't do 
+anything */
+       }
        return 0;
 }
 

Reply via email to