patch-2.1.51 linux/mm/memory.c

Next file: linux/mm/mmap.c
Previous file: linux/kernel/ksyms.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.50/linux/mm/memory.c linux/mm/memory.c
@@ -291,19 +291,20 @@
 	return error;
 }
 
-static inline void free_pte(pte_t page)
+/*
+ * Return indicates whether a page was freed so caller can adjust rss
+ */
+static inline int free_pte(pte_t page)
 {
 	if (pte_present(page)) {
 		unsigned long addr = pte_page(page);
 		if (MAP_NR(addr) >= max_mapnr || PageReserved(mem_map+MAP_NR(addr)))
-			return;
+			return 0;
 		free_page(addr);
-		if (current->mm->rss <= 0)
-			return;
-		current->mm->rss--;
-		return;
+		return 1;
 	}
 	swap_free(pte_val(page));
+	return 0;
 }
 
 static inline void forget_pte(pte_t page)
@@ -314,22 +315,24 @@
 	}
 }
 
-static inline void zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+static inline int zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
 {
 	pte_t * pte;
+	int freed;
 
 	if (pmd_none(*pmd))
-		return;
+		return 0;
 	if (pmd_bad(*pmd)) {
 		printk("zap_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
 		pmd_clear(pmd);
-		return;
+		return 0;
 	}
 	pte = pte_offset(pmd, address);
 	address &= ~PMD_MASK;
 	if (address + size > PMD_SIZE)
 		size = PMD_SIZE - address;
 	size >>= PAGE_SHIFT;
+	freed = 0;
 	for (;;) {
 		pte_t page;
 		if (!size)
@@ -340,32 +343,36 @@
 		if (pte_none(page))
 			continue;
 		pte_clear(pte-1);
-		free_pte(page);
+		freed += free_pte(page);
 	}
+	return freed;
 }
 
-static inline void zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+static inline int zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
 {
 	pmd_t * pmd;
 	unsigned long end;
+	int freed;
 
 	if (pgd_none(*dir))
-		return;
+		return 0;
 	if (pgd_bad(*dir)) {
 		printk("zap_pmd_range: bad pgd (%08lx)\n", pgd_val(*dir));
 		pgd_clear(dir);
-		return;
+		return 0;
 	}
 	pmd = pmd_offset(dir, address);
 	address &= ~PGDIR_MASK;
 	end = address + size;
 	if (end > PGDIR_SIZE)
 		end = PGDIR_SIZE;
+	freed = 0;
 	do {
-		zap_pte_range(pmd, address, end - address);
+		freed += zap_pte_range(pmd, address, end - address);
 		address = (address + PMD_SIZE) & PMD_MASK; 
 		pmd++;
 	} while (address < end);
+	return freed;
 }
 
 /*
@@ -375,12 +382,21 @@
 {
 	pgd_t * dir;
 	unsigned long end = address + size;
+	int freed = 0;
 
 	dir = pgd_offset(mm, address);
 	while (address < end) {
-		zap_pmd_range(dir, address, end - address);
+		freed += zap_pmd_range(dir, address, end - address);
 		address = (address + PGDIR_SIZE) & PGDIR_MASK;
 		dir++;
+	}
+	/*
+	 * Update rss for the mm_struct (not necessarily current->mm)
+	 */
+	if (mm->rss > 0) {
+		mm->rss -= freed;
+		if (mm->rss < 0)
+			mm->rss = 0;
 	}
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov