Messages in this thread Patches in this message | | | Date | Mon, 12 Apr 1999 21:07:26 +0200 (CEST) | From | Andrea Arcangeli <> | Subject | [patch] fix for cc1 Out of memory [Re: [TESTCASE] `Out of memory for cc1'] |
| |
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/
| |