Unbreaking nommu mmap, v2
Subsystems (10)
PATCH 1/1 Unbreaking nommu mmap, v2
A while ago (*) I sent out a patch to change mmap behaviour on nommu targets. Currently, the kernel requires a munmap call for every mmap, with the exact same address range; this is inconsistent with behaviour on mmu systems, and complicates the malloc implementation in uClibc. uClibc's malloc requires that the UCLIBC_UCLINUX_BROKEN_MUNMAP config option is used, which introduces additional overhead, and isn't thread safe in the upstream version of uClibc.
To summarize the comments I got last time:
- Better interface: MAP_SPLIT_PAGES has been renamed MAP_TRIM_EXCESS
- Several people complained about a few Blackfin-specific items which I've hopefully eliminated. MAP_TRIM_EXCESS was added to all architectures which can be compiled as nommu.
- Matt Mackall was worried about increased overhead for programs using simplemalloc; however, simplemalloc (which does a mmap system call for every call to malloc) has incredible time and space overhead anyway, and it is to be hoped that either no one is using it, or they can switch to a sane malloc implementation.
- David Howells worried that the kernel might get confused when unmapping a shared mmap of a file which has been mapped multiple times in the same process. The intent seems to be to share the memory for these multiple maps, but this fails in practice even on an unpatched kernel: when I ran a test program to map the same file twice, I triggered this BUG_ON in add_nommu_vma:
/* mappings are at the same address - this can only
* happen for shared-mem chardevs and shared file
* mappings backed by ramfs/tmpfs */
BUG_ON(!(pvma->vm_flags & VM_SHARED));
Also, even without this patch, I'm not sure how unmapping could be handled sanely in this case.
Apart from these comments, most people seemed to be ok with the basic approach.
I'd like to submit this for inclusion. Any acks or objections?
Bernd
(*) http://lkml.org/lkml/2007/6/8/239
Signature · 4 lines
This footer brought to you by insane German lawmakers. Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 40368 Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif
Make nommu mmap more consistent with mmu mmap behaviour.
This changes nommu mmap/munmap in the following ways:
1. munmap can now unmap subparts of previously allocated blocks. This makes behaviour more consistent with mmu Linux, and allows us to simplify and speed up the uClibc malloc implementation.
2. It is no longer possible to get blocks smaller than a page through mmap. This behaviour was used by simplemalloc, which is an insane way of implementing malloc on nommu systems and hopefully not used by anyone anymore.
3. mmap can now be asked not to round up the allocation to the next power of 2 page size. Excess pages will be freed if MAP_TRIM_EXCESS is passed to mmap.
If this flag is used, more memory is kept available, but fragmentation appears to be higher.
Every VMA can be in two states: either it manages a power-of-2 sized compound page, or (if VM_SPLIT_PAGES) is set, a set of single pages exactly covering the area between vm_start and vm_end.
fs/binfmt_elf_fdpic.c +0 -8
@@ -167,9 +167,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,struct elf_fdpic_params exec_params, interp_params;struct elf_phdr *phdr;unsigned long stack_size, entryaddr; -#ifndef CONFIG_MMU -unsigned long fullsize; -#endif #ifdef ELF_FDPIC_PLAT_INIT unsigned long dynaddr;#endif
@@ -389,11 +386,6 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, goto error_kill; } -/* expand the stack mapping to use up the entire allocation granule */ - fullsize =ksize ((char *) current->mm->start_brk); -if (!IS_ERR_VALUE (do_mremap (current->mm->start_brk, stack_size, - fullsize,0 ,0 ))) - stack_size = fullsize;up_write (¤t->mm->mmap_sem); current->mm->brk = current->mm->start_brk;
fs/binfmt_flat.c +14 -23
@@ -417,8 +417,8 @@ static int load_flat_file(struct linux_binprm * bprm,unsigned long textpos =0 , datapos =0 , result;unsigned long realdatastart =0 ;unsigned long text_len, data_len, bss_len, stack_len, flags; -unsigned long len, reallen, memp =0 ; -unsigned long extra, rlim; +unsigned long len, memp =0 ; +unsigned long memp_size, extra, rlim;unsigned long *reloc =0 , *rp;struct inode *inode;int i, rev, relocs =0 ;
@@ -543,17 +543,11 @@ static int load_flat_file(struct linux_binprm * bprm, } len = data_len + extra +MAX_SHARED_LIBS *sizeof (unsigned long ); + len =PAGE_ALIGN (len);down_write (¤t->mm->mmap_sem); realdatastart =do_mmap (0 ,0 , len, -PROT_READ |PROT_WRITE |PROT_EXEC ,MAP_PRIVATE ,0 ); -/* Remap to use all availabe slack region space */ -if (realdatastart && (realdatastart < (unsigned long )-4096 )) { - reallen =ksize ((void *)realdatastart); -if (reallen > len) { - realdatastart =do_mremap (realdatastart, len, - reallen,MREMAP_FIXED , realdatastart); - } - } +PROT_READ |PROT_WRITE |PROT_EXEC , +MAP_PRIVATE ,0 );up_write (¤t->mm->mmap_sem);if (realdatastart ==0 || realdatastart >= (unsigned long )-4096 ) {
@@ -592,20 +586,15 @@ static int load_flat_file(struct linux_binprm * bprm, reloc = (unsigned long *) (datapos+(ntohl (hdr->reloc_start)-text_len)); memp = realdatastart; + memp_size = len; }else { len = text_len + data_len + extra +MAX_SHARED_LIBS *sizeof (unsigned long ); + len =PAGE_ALIGN (len);down_write (¤t->mm->mmap_sem); textpos =do_mmap (0 ,0 , len, -PROT_READ |PROT_EXEC |PROT_WRITE ,MAP_PRIVATE ,0 ); -/* Remap to use all availabe slack region space */ -if (textpos && (textpos < (unsigned long )-4096 )) { - reallen =ksize ((void *)textpos); -if (reallen > len) { - textpos =do_mremap (textpos, len, reallen, -MREMAP_FIXED , textpos); - } - } +PROT_READ |PROT_EXEC |PROT_WRITE , +MAP_PRIVATE ,0 );up_write (¤t->mm->mmap_sem);if (!textpos || textpos >= (unsigned long )-4096 ) {
@@ -622,7 +611,7 @@ static int load_flat_file(struct linux_binprm * bprm, reloc = (unsigned long *) (textpos +ntohl (hdr->reloc_start) +MAX_SHARED_LIBS *sizeof (unsigned long )); memp = textpos; - + memp_size = len;#ifdef CONFIG_BINFMT_ZFLAT /* * load it all in and treat it like a RAM load from now on
@@ -680,10 +669,12 @@ static int load_flat_file(struct linux_binprm * bprm,* set up the brk stuff, uses any slack left in data/bss/stack * allocation. We put the brk after the bss (between the bss * and stack) like other platforms. +* Userspace code relies on the stack pointer starting out at +* an address right at the end of a page. */ current->mm->start_brk = datapos + data_len + bss_len; current->mm->brk = (current->mm->start_brk +3 ) & ~3 ; - current->mm->context.end_brk = memp +ksize ((void *) memp) - stack_len; + current->mm->context.end_brk = memp + memp_size - stack_len; }if (flags &FLAT_FLAG_KTRACE )
@@ -790,7 +781,7 @@ static int load_flat_file(struct linux_binprm * bprm,/* zero the BSS, BRK and stack areas */ memset ((void *)(datapos + data_len),0 , bss_len + - (memp +ksize ((void *) memp) - stack_len -/* end brk */ + (memp + memp_size - stack_len -/* end brk */ libinfo->lib_list[id].start_brk) +/* start brk */ stack_len);
fs/proc/task_nommu.c +12 -6
@@ -20,20 +20,26 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)down_read (&mm->mmap_sem);for (vml = mm->context.vmlist; vml; vml = vml->next) { +unsigned long size, len; +if (!vml->vma)continue ; bytes +=kobjsize (vml); + len = vml->vma->vm_end - vml->vma->vm_start; +if (!(vml->vma->vm_flags &VM_SPLIT_PAGES )) + size =PAGE_SIZE <<get_order (len); +else + size = len;if (atomic_read (&mm->mm_count) >1 ||atomic_read (&vml->vma->vm_usage) >1 ) { - sbytes +=kobjsize ((void *) vml->vma->vm_start); + sbytes += size; sbytes +=kobjsize (vml->vma); }else { - bytes +=kobjsize ((void *) vml->vma->vm_start); + bytes += size; bytes +=kobjsize (vml->vma); - slack +=kobjsize ((void *) vml->vma->vm_start) - - (vml->vma->vm_end - vml->vma->vm_start); + slack += size - len; } }
@@ -76,7 +82,7 @@ unsigned long task_vsize(struct mm_struct *mm)down_read (&mm->mmap_sem);for (tbp = mm->context.vmlist; tbp; tbp = tbp->next) {if (tbp->vma) - vsize +=kobjsize ((void *) tbp->vma->vm_start); + vsize += tbp->vma->vm_end - tbp->vma->vm_start; }up_read (&mm->mmap_sem);return vsize;
@@ -93,7 +99,7 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, size +=kobjsize (tbp);if (tbp->vma) { size +=kobjsize (tbp->vma); - size +=kobjsize ((void *) tbp->vma->vm_start); + size += tbp->vma->vm_end - tbp->vma->vm_start; } }
include/asm-arm/mman.h +1 -0
@@ -10,6 +10,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) page tables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/asm-blackfin/mman.h +1 -0
@@ -22,6 +22,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) pagetables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MS_ASYNC 1/* sync memory asynchronously */ #define MS_INVALIDATE 2/* invalidate the caches */
include/asm-frv/mman.h +1 -0
@@ -10,6 +10,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) pagetables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/asm-generic/mman.h +1 -0
@@ -19,6 +19,7 @@#define MAP_TYPE 0x0f/* Mask for type of mapping */ #define MAP_FIXED 0x10/* Interpret addr exactly */ #define MAP_ANONYMOUS 0x20/* don't use a file */ +#define MAP_TRIM_EXCESS 0x40/* Conserve memory (nommu only). */ #define MS_ASYNC 1/* sync memory asynchronously */ #define MS_INVALIDATE 2/* invalidate the caches */
include/asm-h8300/mman.h +1 -0
@@ -10,6 +10,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) pagetables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/asm-m32r/mman.h +1 -0
@@ -10,6 +10,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) pagetables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/asm-m68k/mman.h +1 -0
@@ -10,6 +10,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) pagetables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/asm-sh/mman.h +1 -0
@@ -10,6 +10,7 @@#define MAP_NORESERVE 0x4000/* don't check for reservations */ #define MAP_POPULATE 0x8000/* populate (prefault) page tables */ #define MAP_NONBLOCK 0x10000/* do not block on IO */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/asm-v850/mman.h +1 -0
@@ -8,6 +8,7 @@#define MAP_EXECUTABLE 0x1000/* mark it as an executable */ #define MAP_LOCKED 0x2000/* pages are locked */ #define MAP_NORESERVE 0x4000/* don't check for reservations */ +#define MAP_TRIM_EXCESS 0x20000/* Conserve memory (nommu only). */ #define MCL_CURRENT 1/* lock all current mappings */ #define MCL_FUTURE 2/* lock all future mappings */
include/linux/mm.h +2 -0
@@ -108,6 +108,7 @@ extern unsigned int kobjsize(const void *objp);#define VM_CAN_NONLINEAR 0x08000000/* Has ->fault & does nonlinear pages */ #define VM_MIXEDMAP 0x10000000/* Can contain "struct page" and pure PFN pages */ +#define VM_SPLIT_PAGES 0x20000000/* T if split_page was used (nommu mmap) */ #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
@@ -307,6 +308,7 @@ void put_page(struct page *page);void put_pages_list (struct list_head *pages);void split_page (struct page *page,unsigned int order); +void split_compound_page (struct page *page,unsigned int order);/* * Compound pages have a destructor function. Provide a
mm/nommu.c +213 -75
418 lines not on this page · raw message
mm/page_alloc.c +10 -0
@@ -1052,6 +1052,16 @@ void split_page(struct page *page, unsigned int order) }/* +* Like split_page, but calls destroy_compound_page first +*/ +void split_compound_page (struct page *page,unsigned int order) +{ +VM_BUG_ON (!PageCompound (page)); +destroy_compound_page (page, order); +split_page (page, order); +} + +/* * Really, prep_compound_page() should be called from __rmqueue_bulk(). But * we cheat by calling it from here, in the order > 0 path. Saves a branch * or two.
Quoted 1 line · Bernd Schmidt
I'd like to submit this for inclusion. Any acks or objections?
I'd like to counter with this patch. This goes for proper VMAs and doesn't make use of compound pages. This makes things more similar to MMU-mode.
Note that this patch unconditionally trims allocations, whereas on yours this is optional. That can be easily remedied, if, in fact, the ability to request untrimmed allocations is worth doing.
David
---
[PATCH] NOMMU: Make VMAs per MM as for MMU-mode linux
From: David Howells <[email protected]>
Make VMAs per mm_struct as for MMU-mode linux. This solves the nattch problem for SYSV SHM where nattch for a segment does not reflect the number of shmat's (and forks) done.
A new struct (vm_region) is introduced to track a mapped region and to remember the circumstances under which it may be shared and the vm_list_struct structure is discarded as it's no longer required.
This patch makes the following additional changes:
(1) Regions are now allocated with alloc_pages() rather than kmalloc() and with no recourse to __GFP_COMP, so the pages are not composite. Instead, each page has a reference on it held by the region. Anything else that is interested in such a page will have to get a reference on it to retain it. When the pages are released due to unmapping, each page is passed to put_page() and will be freed when the page usage count reaches zero.
(2) Excess pages are trimmed after an allocation as the allocation must be made as a power-of-2 quantity of pages.
(3) VMAs are added to the parent MM's R/B tree and mmap lists. As an MM may end up with overlapping VMAs within the tree, the VMA struct address is appended to the sort key.
(4) Non-anonymous VMAs are now added to the backing inode's prio list.
(5) Holes may be punched in anonymous VMAs with munmap(), releasing parts of the backing region. The VMA and region structs will be split if necessary.
(6) sys_shmdt() only releases one attachment to a SYSV IPC shared memory segment instead of all the attachments at that addresss. Multiple shmat()'s return the same address under NOMMU-mode instead of different virtual addresses as under MMU-mode.
(7) Core dumping for ELF-FDPIC requires fewer exceptions for NOMMU-mode.
(8) /proc/maps is now the global list of mapped regions, and may list bits that aren't actually mapped anywhere.
(9) /proc/meminfo gains a line (tagged "MmapCopy") that indicates the amount of RAM currently allocated by mmap to hold mappable regions that can't be mapped directly. These are copies of the backing device or file if not anonymous.
(10) askedalloc and realalloc are removed.
These changes make NOMMU mode more similar to MMU mode. The downside is that NOMMU mode requires some extra memory to track things over NOMMU without this patch (VMAs are no longer shared, and there are now region structs).
---
arch/frv/kernel/ptrace.c | 11 - fs/binfmt_elf_fdpic.c | 29 - fs/proc/internal.h | 2 fs/proc/nommu.c | 71 ++-- fs/proc/proc_misc.c | 6 fs/proc/task_nommu.c | 111 ++++-- include/asm-frv/mmu.h | 1 include/linux/mm.h | 18 - include/linux/mm_types.h | 19 + ipc/shm.c | 12 + kernel/fork.c | 4 mm/mmap.c | 10 + mm/nommu.c | 918 ++++++++++++++++++++++++++++++---------------- 13 files changed, 770 insertions(+), 442 deletions(-)
arch/frv/kernel/ptrace.c +6 -5
@@ -69,7 +69,8 @@ static inline int put_reg(struct task_struct *task, int regno, }/* -* check that an address falls within the bounds of the target process's memory mappings +* check that an address falls within the bounds of the target process's memory +* mappings */ static inline int is_user_addr_valid (struct task_struct *child,unsigned long start,unsigned long len)
@@ -79,11 +80,11 @@ static inline int is_user_addr_valid(struct task_struct *child,return -EIO ;return 0 ;#else -struct vm_list_struct *vml; +struct vm_area_struct *vma; -for (vml = child->mm->context.vmlist; vml; vml = vml->next) -if (start >= vml->vma->vm_start && start + len <= vml->vma->vm_end) -return 0 ; + vma =find_vma (child->mm, start); +if (start >= vma->vm_start && start + len <= vma->vm_end) +return 0 ;return -EIO ;#endif
fs/binfmt_elf_fdpic.c +4 -25
@@ -390,7 +390,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, }/* expand the stack mapping to use up the entire allocation granule */ - fullsize =kobjsize ((char *) current->mm->start_brk); + fullsize =PAGE_ALIGN (current->mm->start_brk);if (!IS_ERR_VALUE (do_mremap (current->mm->start_brk, stack_size, fullsize,0 ,0 ))) stack_size = fullsize;
@@ -1535,11 +1535,9 @@ end_coredump:static int elf_fdpic_dump_segments (struct file *file,size_t *size,unsigned long *limit,unsigned long mm_flags) { -struct vm_list_struct *vml; - -for (vml = current->mm->context.vmlist; vml; vml = vml->next) { -struct vm_area_struct *vma = vml->vma; +struct vm_area_struct *vma; +for (vma = current->mm->mmap; vma; vma = vma->vm_next) {if (!maydump (vma, mm_flags))continue ;
@@ -1586,9 +1584,6 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,elf_fpxregset_t *xfpu =NULL ;#endif int thread_status_size =0 ; -#ifndef CONFIG_MMU -struct vm_list_struct *vml; -#endif elf_addr_t *auxv;unsigned long mm_flags;
@@ -1655,13 +1650,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,fill_prstatus (prstatus, current, signr);elf_core_copy_regs (&prstatus->pr_reg, regs); -#ifdef CONFIG_MMU segs = current->mm->map_count; -#else - segs =0 ; -for (vml = current->mm->context.vmlist; vml; vml = vml->next) - segs++; -#endif #ifdef ELF_CORE_EXTRA_PHDRS segs +=ELF_CORE_EXTRA_PHDRS ;#endif
@@ -1736,20 +1725,10 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, mm_flags = current->mm->flags;/* write program headers for segments dump */ -for ( -#ifdef CONFIG_MMU - vma = current->mm->mmap; vma; vma = vma->vm_next -#else - vml = current->mm->context.vmlist; vml; vml = vml->next -#endif - ) { +for (vma = current->mm->mmap; vma; vma = vma->vm_next) {struct elf_phdr phdr;size_t sz; -#ifndef CONFIG_MMU - vma = vml->vma; -#endif - sz = vma->vm_end - vma->vm_start; phdr.p_type =PT_LOAD ;
fs/proc/internal.h +0 -2
@@ -41,8 +41,6 @@ do { \ (vmi)->used =0 ; \ (vmi)->largest_chunk =0 ; \ } while(0) - -extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *); #endifextern int maps_protect;
fs/proc/nommu.c +32 -39
133 lines not on this page · raw message
fs/proc/proc_misc.c +6 -0
@@ -167,6 +167,9 @@ static int meminfo_read_proc(char *page, char **start, off_t off,"LowTotal: %8lu kB\n" "LowFree: %8lu kB\n"#endif +#ifndef CONFIG_MMU + "MmapCopy: %8lu kB\n" +#endif "SwapTotal: %8lu kB\n" "SwapFree: %8lu kB\n" "Dirty: %8lu kB\n"
@@ -198,6 +201,9 @@ static int meminfo_read_proc(char *page, char **start, off_t off, K(i.totalram-i.totalhigh), K(i.freeram-i.freehigh),#endif +#ifndef CONFIG_MMU +K ((unsigned long )atomic_read (&mmap_pages_allocated)), +#endifK (i.totalswap),K (i.freeswap), K(global_page_state(NR_FILE_DIRTY)),
fs/proc/task_nommu.c +76 -35
176 lines not on this page · raw message
include/asm-frv/mmu.h +0 -1
@@ -22,7 +22,6 @@ typedef struct {unsigned long dtlb_ptd_mapping;/* [DAMR5] PTD mapping for dtlb cached PGE */ #else -struct vm_list_struct *vmlist;unsigned long end_brk;#endif
include/linux/mm.h +6 -12
@@ -52,19 +52,9 @@ extern unsigned long mmap_min_addr;extern struct kmem_cache *vm_area_cachep; -/* -* This struct defines the per-mm list of VMAs for uClinux. If CONFIG_MMU is -* disabled, then there's a single shared list of VMAs maintained by the -* system, and mm's subscribe to these individually -*/ -struct vm_list_struct { -struct vm_list_struct *next; -struct vm_area_struct *vma; -}; -#ifndef CONFIG_MMU -extern struct rb_root nommu_vma_tree; -extern struct rw_semaphore nommu_vma_sem; +extern struct rb_root nommu_region_tree; +extern struct rw_semaphore nommu_region_sem;extern unsigned int kobjsize (const void *objp);#endif
@@ -1020,6 +1010,7 @@ extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long, enum memmap_context);extern void setup_per_zone_pages_min (void );extern void mem_init (void ); +extern void __init mmap_init (void );extern void show_mem (void );extern void si_meminfo (struct sysinfo * val);extern void si_meminfo_node (struct sysinfo *val,int nid);
@@ -1030,6 +1021,9 @@ extern void setup_per_cpu_pageset(void);static inline void setup_per_cpu_pageset (void ) {}#endif +/* nommu.c */ +extern atomic_t mmap_pages_allocated; +/* prio_tree.c */ void vma_prio_tree_add (struct vm_area_struct *,struct vm_area_struct *old);void vma_prio_tree_insert (struct vm_area_struct *,struct prio_tree_root *);
include/linux/mm_types.h +18 -1
@@ -97,6 +97,23 @@ struct page { };/* +* A region containing a mapping of a non-memory backed file under NOMMU +* conditions. These are held in a global tree and are pinned by the VMAs that +* map parts of them. +*/ +struct vm_region { +struct rb_node vm_rb;/* link in global region tree */ +/* the first parameters define the region as for the VMA */ +unsigned long vm_flags; +unsigned long vm_start; +unsigned long vm_end; +unsigned long vm_pgoff; +struct file *vm_file; + +atomic_t vm_usage;/* region usage count */ +}; + +/* * This struct defines a memory VMM memory area. There is one of these * per VM-area/task. A VM area is any part of the process virtual memory * space that has a special rule for the page-fault handlers (ie a shared
@@ -152,7 +169,7 @@ struct vm_area_struct {unsigned long vm_truncate_count;/* truncate_count or restart_addr */ #ifndef CONFIG_MMU -atomic_t vm_usage;/* refcount (VMAs shared if !MMU) */ +struct vm_region *vm_region;/* NOMMU mapping region */ #endif #ifdef CONFIG_NUMA struct mempolicy *vm_policy;/* NUMA policy for the VMA */
ipc/shm.c +12 -0
@@ -1008,6 +1008,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr)*/ vma =find_vma (mm, addr); +#ifdef CONFIG_MMU while (vma) { next = vma->vm_next;
@@ -1052,6 +1053,17 @@ asmlinkage long sys_shmdt(char __user *shmaddr) vma = next; } +#else /* CONFIG_MMU */ +/* under NOMMU conditions, the exact address to be destroyed must be +* given */ + retval = -EINVAL ; +if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) { +do_munmap (mm, vma->vm_start, vma->vm_end - vma->vm_start); + retval =0 ; + } + +#endif +up_write (&mm->mmap_sem);return retval; }
kernel/fork.c +1 -3
@@ -1426,12 +1426,10 @@ void __init proc_caches_init(void) fs_cachep =kmem_cache_create ("fs_cache" ,sizeof (struct fs_struct ),0 ,SLAB_HWCACHE_ALIGN |SLAB_PANIC ,NULL ); - vm_area_cachep =kmem_cache_create ("vm_area_struct" , -sizeof (struct vm_area_struct ),0 , -SLAB_PANIC ,NULL ); mm_cachep =kmem_cache_create ("mm_struct" ,sizeof (struct mm_struct ),ARCH_MIN_MMSTRUCT_ALIGN ,SLAB_HWCACHE_ALIGN |SLAB_PANIC ,NULL ); +mmap_init (); }/*
mm/mmap.c +10 -0
@@ -2255,3 +2255,13 @@ int install_special_mapping(struct mm_struct *mm,return 0 ; } + +/* +* initialise the VMA slab +*/ +void __init mmap_init (void ) +{ + vm_area_cachep =kmem_cache_create ("vm_area_struct" , +sizeof (struct vm_area_struct ),0 , +SLAB_PANIC ,NULL ); +}
mm/nommu.c +599 -319
1,224 lines not on this page · raw message
Quoted 3 lines · David Howells
Note that this patch unconditionally trims allocations, whereas on yours this is optional. That can be easily remedied, if, in fact, the ability to request untrimmed allocations is worth doing.
Have you investigated the effect on fragmentation? I backed off on trimming allocations, as it gave unacceptable results.
Is this patch different from the ones I tested last year? They were not stable in my tests back then (fragmentation may have been an issue).
Bernd
Signature · 4 lines
This footer brought to you by insane German lawmakers. Analog Devices GmbH Wilhelm-Wagenfeld-Str. 6 80807 Muenchen Sitz der Gesellschaft Muenchen, Registergericht Muenchen HRB 40368 Geschaeftsfuehrer Thomas Wessel, William A. Martin, Margaret Seif