[patch] fix for cc1 Out of memory [Re: [TESTCASE] `Out of memory for cc1']

Andrea Arcangeli (andrea@e-mind.com)
Mon, 12 Apr 1999 21:07:26 +0200 (CEST)


On Fri, 9 Apr 1999, Mike Galbraith wrote:

>I took a look at what the clisp package is doing which leads up
>to the error condition, and find that it's shm. The following

It's triggered by shmdt but I think that the bug is in munmap
(free_pgtable() more precisely).

Patch against 2.2.5:

Index: mmap.c
===================================================================
RCS file: /var/cvs/linux/mm/mmap.c,v
retrieving revision 1.1.2.15
diff -u -r1.1.2.15 mmap.c
--- mmap.c 1999/04/09 16:53:46 1.1.2.15
+++ linux/mm/mmap.c 1999/04/12 18:51:26
@@ -557,8 +557,8 @@
static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
unsigned long start, unsigned long end)
{
- unsigned long first = start & PGDIR_MASK;
- unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK;
+ unsigned long first = start + PGDIR_SIZE - 1;
+ unsigned long last = end;

if (!prev) {
prev = mm->mmap;

This looks like to me the obvious fix since we want to free pagetables
only for the part of mapping that completly fits in the PGD_SIZE regions.

So according to me we must move `first' _ahead_ to the start of the next
PGDIR_SIZE if it was not PGDIR_SIZE aligned. And instead we must _cut_
`end' to make it PAGE_ALIGNED _back_ to the previous alignment.

The patch works here. But why are we playing with prev for example? Right
now I think something like that should be just fine:

Index: mmap.c
===================================================================
RCS file: /var/cvs/linux/mm/mmap.c,v
retrieving revision 1.1.2.15
diff -u -r1.1.2.15 mmap.c
--- mmap.c 1999/04/09 16:53:46 1.1.2.15
+++ linux/mm/mmap.c 1999/04/12 19:03:16
@@ -550,44 +550,13 @@
* PGDIR-aligned area that got free'd up. We could be more
* granular if we want to, but this is fast and simple,
* and covers the bad cases.
- *
- * "prev", if it exists, points to a vma before the one
- * we just free'd - but there's no telling how much before.
*/
-static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
- unsigned long start, unsigned long end)
+static inline void free_pgtables(struct mm_struct * mm,
+ unsigned long start, unsigned long size)
{
- unsigned long first = start & PGDIR_MASK;
- unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK;
+ unsigned long first = start + PGDIR_SIZE - 1 >> PGDIR_SHIFT;
+ unsigned long last = start + size >> PGDIR_SHIFT;

- if (!prev) {
- prev = mm->mmap;
- if (!prev)
- goto no_mmaps;
- if (prev->vm_end > start) {
- if (last > prev->vm_end)
- last = prev->vm_end;
- goto no_mmaps;
- }
- }
- for (;;) {
- struct vm_area_struct *next = prev->vm_next;
-
- if (next) {
- if (next->vm_start < start) {
- prev = next;
- continue;
- }
- if (last > next->vm_start)
- last = next->vm_start;
- }
- if (prev->vm_end > first)
- first = prev->vm_end + PGDIR_SIZE - 1;
- break;
- }
-no_mmaps:
- first = first >> PGDIR_SHIFT;
- last = last >> PGDIR_SHIFT;
if (last > first)
clear_page_tables(mm, first, last-first);
}
@@ -675,13 +644,13 @@
*/
if (!unmap_fixup(mpnt, st, size, &extra))
kmem_cache_free(vm_area_cachep, mpnt);
+
+ free_pgtables(mm, st, size);
}

/* Release the extra vma struct if it wasn't used */
if (extra)
kmem_cache_free(vm_area_cachep, extra);
-
- free_pgtables(mm, prev, addr, addr+len);

mm->mmap_cache = NULL; /* Kill the cache. */
return 0;

Andrea 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/