11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/mm/nommu.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Replacement code for mm functions to support CPU's that don't 51da177e4SLinus Torvalds * have any form of memory management unit (thus no virtual memory). 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * See Documentation/nommu-mmap.txt 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Copyright (c) 2004-2005 David Howells <dhowells@redhat.com> 101da177e4SLinus Torvalds * Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com> 111da177e4SLinus Torvalds * Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org> 121da177e4SLinus Torvalds * Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com> 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <linux/mm.h> 161da177e4SLinus Torvalds #include <linux/mman.h> 171da177e4SLinus Torvalds #include <linux/swap.h> 181da177e4SLinus Torvalds #include <linux/file.h> 191da177e4SLinus Torvalds #include <linux/highmem.h> 201da177e4SLinus Torvalds #include <linux/pagemap.h> 211da177e4SLinus Torvalds #include <linux/slab.h> 221da177e4SLinus Torvalds #include <linux/vmalloc.h> 231da177e4SLinus Torvalds #include <linux/ptrace.h> 241da177e4SLinus Torvalds #include <linux/blkdev.h> 251da177e4SLinus Torvalds #include <linux/backing-dev.h> 261da177e4SLinus Torvalds #include <linux/mount.h> 271da177e4SLinus Torvalds #include <linux/personality.h> 281da177e4SLinus Torvalds #include <linux/security.h> 291da177e4SLinus Torvalds #include <linux/syscalls.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #include <asm/uaccess.h> 321da177e4SLinus Torvalds #include <asm/tlb.h> 331da177e4SLinus Torvalds #include <asm/tlbflush.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds void *high_memory; 361da177e4SLinus Torvalds struct page *mem_map; 371da177e4SLinus Torvalds unsigned long max_mapnr; 381da177e4SLinus Torvalds unsigned long num_physpages; 391da177e4SLinus Torvalds unsigned long askedalloc, realalloc; 401da177e4SLinus Torvalds atomic_t vm_committed_space = ATOMIC_INIT(0); 411da177e4SLinus Torvalds int sysctl_overcommit_memory = OVERCOMMIT_GUESS; /* heuristic overcommit */ 421da177e4SLinus Torvalds int sysctl_overcommit_ratio = 50; /* default is 50% */ 431da177e4SLinus Torvalds int sysctl_max_map_count = DEFAULT_MAX_MAP_COUNT; 441da177e4SLinus Torvalds int heap_stack_gap = 0; 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds EXPORT_SYMBOL(mem_map); 471da177e4SLinus Torvalds EXPORT_SYMBOL(sysctl_max_map_count); 481da177e4SLinus Torvalds EXPORT_SYMBOL(sysctl_overcommit_memory); 491da177e4SLinus Torvalds EXPORT_SYMBOL(sysctl_overcommit_ratio); 501da177e4SLinus Torvalds EXPORT_SYMBOL(vm_committed_space); 511da177e4SLinus Torvalds EXPORT_SYMBOL(__vm_enough_memory); 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /* list of shareable VMAs */ 541da177e4SLinus Torvalds struct rb_root nommu_vma_tree = RB_ROOT; 551da177e4SLinus Torvalds DECLARE_RWSEM(nommu_vma_sem); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds struct vm_operations_struct generic_file_vm_ops = { 581da177e4SLinus Torvalds }; 591da177e4SLinus Torvalds 60*66aa2b4bSGreg Ungerer EXPORT_SYMBOL(vmalloc); 61*66aa2b4bSGreg Ungerer EXPORT_SYMBOL(vfree); 62*66aa2b4bSGreg Ungerer EXPORT_SYMBOL(vmalloc_to_page); 63*66aa2b4bSGreg Ungerer EXPORT_SYMBOL(vmalloc_32); 64*66aa2b4bSGreg Ungerer 651da177e4SLinus Torvalds /* 661da177e4SLinus Torvalds * Handle all mappings that got truncated by a "truncate()" 671da177e4SLinus Torvalds * system call. 681da177e4SLinus Torvalds * 691da177e4SLinus Torvalds * NOTE! We have to be ready to update the memory sharing 701da177e4SLinus Torvalds * between the file and the memory map for a potential last 711da177e4SLinus Torvalds * incomplete page. Ugly, but necessary. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds int vmtruncate(struct inode *inode, loff_t offset) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds struct address_space *mapping = inode->i_mapping; 761da177e4SLinus Torvalds unsigned long limit; 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds if (inode->i_size < offset) 791da177e4SLinus Torvalds goto do_expand; 801da177e4SLinus Torvalds i_size_write(inode, offset); 811da177e4SLinus Torvalds 821da177e4SLinus Torvalds truncate_inode_pages(mapping, offset); 831da177e4SLinus Torvalds goto out_truncate; 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds do_expand: 861da177e4SLinus Torvalds limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 871da177e4SLinus Torvalds if (limit != RLIM_INFINITY && offset > limit) 881da177e4SLinus Torvalds goto out_sig; 891da177e4SLinus Torvalds if (offset > inode->i_sb->s_maxbytes) 901da177e4SLinus Torvalds goto out; 911da177e4SLinus Torvalds i_size_write(inode, offset); 921da177e4SLinus Torvalds 931da177e4SLinus Torvalds out_truncate: 941da177e4SLinus Torvalds if (inode->i_op && inode->i_op->truncate) 951da177e4SLinus Torvalds inode->i_op->truncate(inode); 961da177e4SLinus Torvalds return 0; 971da177e4SLinus Torvalds out_sig: 981da177e4SLinus Torvalds send_sig(SIGXFSZ, current, 0); 991da177e4SLinus Torvalds out: 1001da177e4SLinus Torvalds return -EFBIG; 1011da177e4SLinus Torvalds } 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds EXPORT_SYMBOL(vmtruncate); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds /* 1061da177e4SLinus Torvalds * Return the total memory allocated for this pointer, not 1071da177e4SLinus Torvalds * just what the caller asked for. 1081da177e4SLinus Torvalds * 1091da177e4SLinus Torvalds * Doesn't have to be accurate, i.e. may have races. 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds unsigned int kobjsize(const void *objp) 1121da177e4SLinus Torvalds { 1131da177e4SLinus Torvalds struct page *page; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds if (!objp || !((page = virt_to_page(objp)))) 1161da177e4SLinus Torvalds return 0; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds if (PageSlab(page)) 1191da177e4SLinus Torvalds return ksize(objp); 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds BUG_ON(page->index < 0); 1221da177e4SLinus Torvalds BUG_ON(page->index >= MAX_ORDER); 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds return (PAGE_SIZE << page->index); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds /* 1281da177e4SLinus Torvalds * The nommu dodgy version :-) 1291da177e4SLinus Torvalds */ 1301da177e4SLinus Torvalds int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, 1311da177e4SLinus Torvalds unsigned long start, int len, int write, int force, 1321da177e4SLinus Torvalds struct page **pages, struct vm_area_struct **vmas) 1331da177e4SLinus Torvalds { 1341da177e4SLinus Torvalds int i; 1351da177e4SLinus Torvalds static struct vm_area_struct dummy_vma; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds for (i = 0; i < len; i++) { 1381da177e4SLinus Torvalds if (pages) { 1391da177e4SLinus Torvalds pages[i] = virt_to_page(start); 1401da177e4SLinus Torvalds if (pages[i]) 1411da177e4SLinus Torvalds page_cache_get(pages[i]); 1421da177e4SLinus Torvalds } 1431da177e4SLinus Torvalds if (vmas) 1441da177e4SLinus Torvalds vmas[i] = &dummy_vma; 1451da177e4SLinus Torvalds start += PAGE_SIZE; 1461da177e4SLinus Torvalds } 1471da177e4SLinus Torvalds return(i); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 150*66aa2b4bSGreg Ungerer EXPORT_SYMBOL(get_user_pages); 151*66aa2b4bSGreg Ungerer 1521da177e4SLinus Torvalds DEFINE_RWLOCK(vmlist_lock); 1531da177e4SLinus Torvalds struct vm_struct *vmlist; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds void vfree(void *addr) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds kfree(addr); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1607a019225SAdrian Bunk void *__vmalloc(unsigned long size, unsigned int __nocast gfp_mask, 1617a019225SAdrian Bunk pgprot_t prot) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds /* 1641da177e4SLinus Torvalds * kmalloc doesn't like __GFP_HIGHMEM for some reason 1651da177e4SLinus Torvalds */ 1661da177e4SLinus Torvalds return kmalloc(size, gfp_mask & ~__GFP_HIGHMEM); 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds struct page * vmalloc_to_page(void *addr) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds return virt_to_page(addr); 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds unsigned long vmalloc_to_pfn(void *addr) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds return page_to_pfn(virt_to_page(addr)); 1771da177e4SLinus Torvalds } 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds long vread(char *buf, char *addr, unsigned long count) 1811da177e4SLinus Torvalds { 1821da177e4SLinus Torvalds memcpy(buf, addr, count); 1831da177e4SLinus Torvalds return count; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds 1861da177e4SLinus Torvalds long vwrite(char *buf, char *addr, unsigned long count) 1871da177e4SLinus Torvalds { 1881da177e4SLinus Torvalds /* Don't allow overflow */ 1891da177e4SLinus Torvalds if ((unsigned long) addr + count < count) 1901da177e4SLinus Torvalds count = -(unsigned long) addr; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds memcpy(addr, buf, count); 1931da177e4SLinus Torvalds return(count); 1941da177e4SLinus Torvalds } 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds /* 1971da177e4SLinus Torvalds * vmalloc - allocate virtually continguos memory 1981da177e4SLinus Torvalds * 1991da177e4SLinus Torvalds * @size: allocation size 2001da177e4SLinus Torvalds * 2011da177e4SLinus Torvalds * Allocate enough pages to cover @size from the page level 2021da177e4SLinus Torvalds * allocator and map them into continguos kernel virtual space. 2031da177e4SLinus Torvalds * 2041da177e4SLinus Torvalds * For tight cotrol over page level allocator and protection flags 2051da177e4SLinus Torvalds * use __vmalloc() instead. 2061da177e4SLinus Torvalds */ 2071da177e4SLinus Torvalds void *vmalloc(unsigned long size) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* 2131da177e4SLinus Torvalds * vmalloc_32 - allocate virtually continguos memory (32bit addressable) 2141da177e4SLinus Torvalds * 2151da177e4SLinus Torvalds * @size: allocation size 2161da177e4SLinus Torvalds * 2171da177e4SLinus Torvalds * Allocate enough 32bit PA addressable pages to cover @size from the 2181da177e4SLinus Torvalds * page level allocator and map them into continguos kernel virtual space. 2191da177e4SLinus Torvalds */ 2201da177e4SLinus Torvalds void *vmalloc_32(unsigned long size) 2211da177e4SLinus Torvalds { 2221da177e4SLinus Torvalds return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds BUG(); 2281da177e4SLinus Torvalds return NULL; 2291da177e4SLinus Torvalds } 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds void vunmap(void *addr) 2321da177e4SLinus Torvalds { 2331da177e4SLinus Torvalds BUG(); 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds /* 2371da177e4SLinus Torvalds * sys_brk() for the most part doesn't need the global kernel 2381da177e4SLinus Torvalds * lock, except when an application is doing something nasty 2391da177e4SLinus Torvalds * like trying to un-brk an area that has already been mapped 2401da177e4SLinus Torvalds * to a regular file. in this case, the unmapping will need 2411da177e4SLinus Torvalds * to invoke file system routines that need the global lock. 2421da177e4SLinus Torvalds */ 2431da177e4SLinus Torvalds asmlinkage unsigned long sys_brk(unsigned long brk) 2441da177e4SLinus Torvalds { 2451da177e4SLinus Torvalds struct mm_struct *mm = current->mm; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds if (brk < mm->start_brk || brk > mm->context.end_brk) 2481da177e4SLinus Torvalds return mm->brk; 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds if (mm->brk == brk) 2511da177e4SLinus Torvalds return mm->brk; 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds /* 2541da177e4SLinus Torvalds * Always allow shrinking brk 2551da177e4SLinus Torvalds */ 2561da177e4SLinus Torvalds if (brk <= mm->brk) { 2571da177e4SLinus Torvalds mm->brk = brk; 2581da177e4SLinus Torvalds return brk; 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds /* 2621da177e4SLinus Torvalds * Ok, looks good - let it rip. 2631da177e4SLinus Torvalds */ 2641da177e4SLinus Torvalds return mm->brk = brk; 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds #ifdef DEBUG 2681da177e4SLinus Torvalds static void show_process_blocks(void) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds struct vm_list_struct *vml; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds printk("Process blocks %d:", current->pid); 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds for (vml = ¤t->mm->context.vmlist; vml; vml = vml->next) { 2751da177e4SLinus Torvalds printk(" %p: %p", vml, vml->vma); 2761da177e4SLinus Torvalds if (vml->vma) 2771da177e4SLinus Torvalds printk(" (%d @%lx #%d)", 2781da177e4SLinus Torvalds kobjsize((void *) vml->vma->vm_start), 2791da177e4SLinus Torvalds vml->vma->vm_start, 2801da177e4SLinus Torvalds atomic_read(&vml->vma->vm_usage)); 2811da177e4SLinus Torvalds printk(vml->next ? " ->" : ".\n"); 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds } 2841da177e4SLinus Torvalds #endif /* DEBUG */ 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds static inline struct vm_area_struct *find_nommu_vma(unsigned long start) 2871da177e4SLinus Torvalds { 2881da177e4SLinus Torvalds struct vm_area_struct *vma; 2891da177e4SLinus Torvalds struct rb_node *n = nommu_vma_tree.rb_node; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds while (n) { 2921da177e4SLinus Torvalds vma = rb_entry(n, struct vm_area_struct, vm_rb); 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds if (start < vma->vm_start) 2951da177e4SLinus Torvalds n = n->rb_left; 2961da177e4SLinus Torvalds else if (start > vma->vm_start) 2971da177e4SLinus Torvalds n = n->rb_right; 2981da177e4SLinus Torvalds else 2991da177e4SLinus Torvalds return vma; 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds return NULL; 3031da177e4SLinus Torvalds } 3041da177e4SLinus Torvalds 3051da177e4SLinus Torvalds static void add_nommu_vma(struct vm_area_struct *vma) 3061da177e4SLinus Torvalds { 3071da177e4SLinus Torvalds struct vm_area_struct *pvma; 3081da177e4SLinus Torvalds struct address_space *mapping; 3091da177e4SLinus Torvalds struct rb_node **p = &nommu_vma_tree.rb_node; 3101da177e4SLinus Torvalds struct rb_node *parent = NULL; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds /* add the VMA to the mapping */ 3131da177e4SLinus Torvalds if (vma->vm_file) { 3141da177e4SLinus Torvalds mapping = vma->vm_file->f_mapping; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds flush_dcache_mmap_lock(mapping); 3171da177e4SLinus Torvalds vma_prio_tree_insert(vma, &mapping->i_mmap); 3181da177e4SLinus Torvalds flush_dcache_mmap_unlock(mapping); 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* add the VMA to the master list */ 3221da177e4SLinus Torvalds while (*p) { 3231da177e4SLinus Torvalds parent = *p; 3241da177e4SLinus Torvalds pvma = rb_entry(parent, struct vm_area_struct, vm_rb); 3251da177e4SLinus Torvalds 3261da177e4SLinus Torvalds if (vma->vm_start < pvma->vm_start) { 3271da177e4SLinus Torvalds p = &(*p)->rb_left; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds else if (vma->vm_start > pvma->vm_start) { 3301da177e4SLinus Torvalds p = &(*p)->rb_right; 3311da177e4SLinus Torvalds } 3321da177e4SLinus Torvalds else { 3331da177e4SLinus Torvalds /* mappings are at the same address - this can only 3341da177e4SLinus Torvalds * happen for shared-mem chardevs and shared file 3351da177e4SLinus Torvalds * mappings backed by ramfs/tmpfs */ 3361da177e4SLinus Torvalds BUG_ON(!(pvma->vm_flags & VM_SHARED)); 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds if (vma < pvma) 3391da177e4SLinus Torvalds p = &(*p)->rb_left; 3401da177e4SLinus Torvalds else if (vma > pvma) 3411da177e4SLinus Torvalds p = &(*p)->rb_right; 3421da177e4SLinus Torvalds else 3431da177e4SLinus Torvalds BUG(); 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds rb_link_node(&vma->vm_rb, parent, p); 3481da177e4SLinus Torvalds rb_insert_color(&vma->vm_rb, &nommu_vma_tree); 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds static void delete_nommu_vma(struct vm_area_struct *vma) 3521da177e4SLinus Torvalds { 3531da177e4SLinus Torvalds struct address_space *mapping; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds /* remove the VMA from the mapping */ 3561da177e4SLinus Torvalds if (vma->vm_file) { 3571da177e4SLinus Torvalds mapping = vma->vm_file->f_mapping; 3581da177e4SLinus Torvalds 3591da177e4SLinus Torvalds flush_dcache_mmap_lock(mapping); 3601da177e4SLinus Torvalds vma_prio_tree_remove(vma, &mapping->i_mmap); 3611da177e4SLinus Torvalds flush_dcache_mmap_unlock(mapping); 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds /* remove from the master list */ 3651da177e4SLinus Torvalds rb_erase(&vma->vm_rb, &nommu_vma_tree); 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds 3681da177e4SLinus Torvalds /* 3691da177e4SLinus Torvalds * determine whether a mapping should be permitted and, if so, what sort of 3701da177e4SLinus Torvalds * mapping we're capable of supporting 3711da177e4SLinus Torvalds */ 3721da177e4SLinus Torvalds static int validate_mmap_request(struct file *file, 3731da177e4SLinus Torvalds unsigned long addr, 3741da177e4SLinus Torvalds unsigned long len, 3751da177e4SLinus Torvalds unsigned long prot, 3761da177e4SLinus Torvalds unsigned long flags, 3771da177e4SLinus Torvalds unsigned long pgoff, 3781da177e4SLinus Torvalds unsigned long *_capabilities) 3791da177e4SLinus Torvalds { 3801da177e4SLinus Torvalds unsigned long capabilities; 3811da177e4SLinus Torvalds unsigned long reqprot = prot; 3821da177e4SLinus Torvalds int ret; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds /* do the simple checks first */ 3851da177e4SLinus Torvalds if (flags & MAP_FIXED || addr) { 3861da177e4SLinus Torvalds printk(KERN_DEBUG 3871da177e4SLinus Torvalds "%d: Can't do fixed-address/overlay mmap of RAM\n", 3881da177e4SLinus Torvalds current->pid); 3891da177e4SLinus Torvalds return -EINVAL; 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds if ((flags & MAP_TYPE) != MAP_PRIVATE && 3931da177e4SLinus Torvalds (flags & MAP_TYPE) != MAP_SHARED) 3941da177e4SLinus Torvalds return -EINVAL; 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds if (PAGE_ALIGN(len) == 0) 3971da177e4SLinus Torvalds return addr; 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds if (len > TASK_SIZE) 4001da177e4SLinus Torvalds return -EINVAL; 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds /* offset overflow? */ 4031da177e4SLinus Torvalds if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) 4041da177e4SLinus Torvalds return -EINVAL; 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds if (file) { 4071da177e4SLinus Torvalds /* validate file mapping requests */ 4081da177e4SLinus Torvalds struct address_space *mapping; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds /* files must support mmap */ 4111da177e4SLinus Torvalds if (!file->f_op || !file->f_op->mmap) 4121da177e4SLinus Torvalds return -ENODEV; 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /* work out if what we've got could possibly be shared 4151da177e4SLinus Torvalds * - we support chardevs that provide their own "memory" 4161da177e4SLinus Torvalds * - we support files/blockdevs that are memory backed 4171da177e4SLinus Torvalds */ 4181da177e4SLinus Torvalds mapping = file->f_mapping; 4191da177e4SLinus Torvalds if (!mapping) 4201da177e4SLinus Torvalds mapping = file->f_dentry->d_inode->i_mapping; 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds capabilities = 0; 4231da177e4SLinus Torvalds if (mapping && mapping->backing_dev_info) 4241da177e4SLinus Torvalds capabilities = mapping->backing_dev_info->capabilities; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds if (!capabilities) { 4271da177e4SLinus Torvalds /* no explicit capabilities set, so assume some 4281da177e4SLinus Torvalds * defaults */ 4291da177e4SLinus Torvalds switch (file->f_dentry->d_inode->i_mode & S_IFMT) { 4301da177e4SLinus Torvalds case S_IFREG: 4311da177e4SLinus Torvalds case S_IFBLK: 4321da177e4SLinus Torvalds capabilities = BDI_CAP_MAP_COPY; 4331da177e4SLinus Torvalds break; 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds case S_IFCHR: 4361da177e4SLinus Torvalds capabilities = 4371da177e4SLinus Torvalds BDI_CAP_MAP_DIRECT | 4381da177e4SLinus Torvalds BDI_CAP_READ_MAP | 4391da177e4SLinus Torvalds BDI_CAP_WRITE_MAP; 4401da177e4SLinus Torvalds break; 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds default: 4431da177e4SLinus Torvalds return -EINVAL; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds /* eliminate any capabilities that we can't support on this 4481da177e4SLinus Torvalds * device */ 4491da177e4SLinus Torvalds if (!file->f_op->get_unmapped_area) 4501da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 4511da177e4SLinus Torvalds if (!file->f_op->read) 4521da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_COPY; 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds if (flags & MAP_SHARED) { 4551da177e4SLinus Torvalds /* do checks for writing, appending and locking */ 4561da177e4SLinus Torvalds if ((prot & PROT_WRITE) && 4571da177e4SLinus Torvalds !(file->f_mode & FMODE_WRITE)) 4581da177e4SLinus Torvalds return -EACCES; 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds if (IS_APPEND(file->f_dentry->d_inode) && 4611da177e4SLinus Torvalds (file->f_mode & FMODE_WRITE)) 4621da177e4SLinus Torvalds return -EACCES; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds if (locks_verify_locked(file->f_dentry->d_inode)) 4651da177e4SLinus Torvalds return -EAGAIN; 4661da177e4SLinus Torvalds 4671da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_DIRECT)) 4681da177e4SLinus Torvalds return -ENODEV; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds if (((prot & PROT_READ) && !(capabilities & BDI_CAP_READ_MAP)) || 4711da177e4SLinus Torvalds ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) || 4721da177e4SLinus Torvalds ((prot & PROT_EXEC) && !(capabilities & BDI_CAP_EXEC_MAP)) 4731da177e4SLinus Torvalds ) { 4741da177e4SLinus Torvalds printk("MAP_SHARED not completely supported on !MMU\n"); 4751da177e4SLinus Torvalds return -EINVAL; 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds /* we mustn't privatise shared mappings */ 4791da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_COPY; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds else { 4821da177e4SLinus Torvalds /* we're going to read the file into private memory we 4831da177e4SLinus Torvalds * allocate */ 4841da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_COPY)) 4851da177e4SLinus Torvalds return -ENODEV; 4861da177e4SLinus Torvalds 4871da177e4SLinus Torvalds /* we don't permit a private writable mapping to be 4881da177e4SLinus Torvalds * shared with the backing device */ 4891da177e4SLinus Torvalds if (prot & PROT_WRITE) 4901da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 4911da177e4SLinus Torvalds } 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds /* handle executable mappings and implied executable 4941da177e4SLinus Torvalds * mappings */ 4951da177e4SLinus Torvalds if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) { 4961da177e4SLinus Torvalds if (prot & PROT_EXEC) 4971da177e4SLinus Torvalds return -EPERM; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) { 5001da177e4SLinus Torvalds /* handle implication of PROT_EXEC by PROT_READ */ 5011da177e4SLinus Torvalds if (current->personality & READ_IMPLIES_EXEC) { 5021da177e4SLinus Torvalds if (capabilities & BDI_CAP_EXEC_MAP) 5031da177e4SLinus Torvalds prot |= PROT_EXEC; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds } 5061da177e4SLinus Torvalds else if ((prot & PROT_READ) && 5071da177e4SLinus Torvalds (prot & PROT_EXEC) && 5081da177e4SLinus Torvalds !(capabilities & BDI_CAP_EXEC_MAP) 5091da177e4SLinus Torvalds ) { 5101da177e4SLinus Torvalds /* backing file is not executable, try to copy */ 5111da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds else { 5151da177e4SLinus Torvalds /* anonymous mappings are always memory backed and can be 5161da177e4SLinus Torvalds * privately mapped 5171da177e4SLinus Torvalds */ 5181da177e4SLinus Torvalds capabilities = BDI_CAP_MAP_COPY; 5191da177e4SLinus Torvalds 5201da177e4SLinus Torvalds /* handle PROT_EXEC implication by PROT_READ */ 5211da177e4SLinus Torvalds if ((prot & PROT_READ) && 5221da177e4SLinus Torvalds (current->personality & READ_IMPLIES_EXEC)) 5231da177e4SLinus Torvalds prot |= PROT_EXEC; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds /* allow the security API to have its say */ 5271da177e4SLinus Torvalds ret = security_file_mmap(file, reqprot, prot, flags); 5281da177e4SLinus Torvalds if (ret < 0) 5291da177e4SLinus Torvalds return ret; 5301da177e4SLinus Torvalds 5311da177e4SLinus Torvalds /* looks okay */ 5321da177e4SLinus Torvalds *_capabilities = capabilities; 5331da177e4SLinus Torvalds return 0; 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds /* 5371da177e4SLinus Torvalds * we've determined that we can make the mapping, now translate what we 5381da177e4SLinus Torvalds * now know into VMA flags 5391da177e4SLinus Torvalds */ 5401da177e4SLinus Torvalds static unsigned long determine_vm_flags(struct file *file, 5411da177e4SLinus Torvalds unsigned long prot, 5421da177e4SLinus Torvalds unsigned long flags, 5431da177e4SLinus Torvalds unsigned long capabilities) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds unsigned long vm_flags; 5461da177e4SLinus Torvalds 5471da177e4SLinus Torvalds vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags); 5481da177e4SLinus Torvalds vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; 5491da177e4SLinus Torvalds /* vm_flags |= mm->def_flags; */ 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_DIRECT)) { 5521da177e4SLinus Torvalds /* attempt to share read-only copies of mapped file chunks */ 5531da177e4SLinus Torvalds if (file && !(prot & PROT_WRITE)) 5541da177e4SLinus Torvalds vm_flags |= VM_MAYSHARE; 5551da177e4SLinus Torvalds } 5561da177e4SLinus Torvalds else { 5571da177e4SLinus Torvalds /* overlay a shareable mapping on the backing device or inode 5581da177e4SLinus Torvalds * if possible - used for chardevs, ramfs/tmpfs/shmfs and 5591da177e4SLinus Torvalds * romfs/cramfs */ 5601da177e4SLinus Torvalds if (flags & MAP_SHARED) 5611da177e4SLinus Torvalds vm_flags |= VM_MAYSHARE | VM_SHARED; 5621da177e4SLinus Torvalds else if ((((vm_flags & capabilities) ^ vm_flags) & BDI_CAP_VMFLAGS) == 0) 5631da177e4SLinus Torvalds vm_flags |= VM_MAYSHARE; 5641da177e4SLinus Torvalds } 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds /* refuse to let anyone share private mappings with this process if 5671da177e4SLinus Torvalds * it's being traced - otherwise breakpoints set in it may interfere 5681da177e4SLinus Torvalds * with another untraced process 5691da177e4SLinus Torvalds */ 5701da177e4SLinus Torvalds if ((flags & MAP_PRIVATE) && (current->ptrace & PT_PTRACED)) 5711da177e4SLinus Torvalds vm_flags &= ~VM_MAYSHARE; 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds return vm_flags; 5741da177e4SLinus Torvalds } 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /* 5771da177e4SLinus Torvalds * set up a shared mapping on a file 5781da177e4SLinus Torvalds */ 5791da177e4SLinus Torvalds static int do_mmap_shared_file(struct vm_area_struct *vma, unsigned long len) 5801da177e4SLinus Torvalds { 5811da177e4SLinus Torvalds int ret; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); 5841da177e4SLinus Torvalds if (ret != -ENOSYS) 5851da177e4SLinus Torvalds return ret; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds /* getting an ENOSYS error indicates that direct mmap isn't 5881da177e4SLinus Torvalds * possible (as opposed to tried but failed) so we'll fall 5891da177e4SLinus Torvalds * through to making a private copy of the data and mapping 5901da177e4SLinus Torvalds * that if we can */ 5911da177e4SLinus Torvalds return -ENODEV; 5921da177e4SLinus Torvalds } 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds /* 5951da177e4SLinus Torvalds * set up a private mapping or an anonymous shared mapping 5961da177e4SLinus Torvalds */ 5971da177e4SLinus Torvalds static int do_mmap_private(struct vm_area_struct *vma, unsigned long len) 5981da177e4SLinus Torvalds { 5991da177e4SLinus Torvalds void *base; 6001da177e4SLinus Torvalds int ret; 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* invoke the file's mapping function so that it can keep track of 6031da177e4SLinus Torvalds * shared mappings on devices or memory 6041da177e4SLinus Torvalds * - VM_MAYSHARE will be set if it may attempt to share 6051da177e4SLinus Torvalds */ 6061da177e4SLinus Torvalds if (vma->vm_file) { 6071da177e4SLinus Torvalds ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); 6081da177e4SLinus Torvalds if (ret != -ENOSYS) { 6091da177e4SLinus Torvalds /* shouldn't return success if we're not sharing */ 6101da177e4SLinus Torvalds BUG_ON(ret == 0 && !(vma->vm_flags & VM_MAYSHARE)); 6111da177e4SLinus Torvalds return ret; /* success or a real error */ 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds /* getting an ENOSYS error indicates that direct mmap isn't 6151da177e4SLinus Torvalds * possible (as opposed to tried but failed) so we'll try to 6161da177e4SLinus Torvalds * make a private copy of the data and map that instead */ 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* allocate some memory to hold the mapping 6201da177e4SLinus Torvalds * - note that this may not return a page-aligned address if the object 6211da177e4SLinus Torvalds * we're allocating is smaller than a page 6221da177e4SLinus Torvalds */ 6231da177e4SLinus Torvalds base = kmalloc(len, GFP_KERNEL); 6241da177e4SLinus Torvalds if (!base) 6251da177e4SLinus Torvalds goto enomem; 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds vma->vm_start = (unsigned long) base; 6281da177e4SLinus Torvalds vma->vm_end = vma->vm_start + len; 6291da177e4SLinus Torvalds vma->vm_flags |= VM_MAPPED_COPY; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds #ifdef WARN_ON_SLACK 6321da177e4SLinus Torvalds if (len + WARN_ON_SLACK <= kobjsize(result)) 6331da177e4SLinus Torvalds printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n", 6341da177e4SLinus Torvalds len, current->pid, kobjsize(result) - len); 6351da177e4SLinus Torvalds #endif 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds if (vma->vm_file) { 6381da177e4SLinus Torvalds /* read the contents of a file into the copy */ 6391da177e4SLinus Torvalds mm_segment_t old_fs; 6401da177e4SLinus Torvalds loff_t fpos; 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds fpos = vma->vm_pgoff; 6431da177e4SLinus Torvalds fpos <<= PAGE_SHIFT; 6441da177e4SLinus Torvalds 6451da177e4SLinus Torvalds old_fs = get_fs(); 6461da177e4SLinus Torvalds set_fs(KERNEL_DS); 6471da177e4SLinus Torvalds ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos); 6481da177e4SLinus Torvalds set_fs(old_fs); 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds if (ret < 0) 6511da177e4SLinus Torvalds goto error_free; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds /* clear the last little bit */ 6541da177e4SLinus Torvalds if (ret < len) 6551da177e4SLinus Torvalds memset(base + ret, 0, len - ret); 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds } else { 6581da177e4SLinus Torvalds /* if it's an anonymous mapping, then just clear it */ 6591da177e4SLinus Torvalds memset(base, 0, len); 6601da177e4SLinus Torvalds } 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds return 0; 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds error_free: 6651da177e4SLinus Torvalds kfree(base); 6661da177e4SLinus Torvalds vma->vm_start = 0; 6671da177e4SLinus Torvalds return ret; 6681da177e4SLinus Torvalds 6691da177e4SLinus Torvalds enomem: 6701da177e4SLinus Torvalds printk("Allocation of length %lu from process %d failed\n", 6711da177e4SLinus Torvalds len, current->pid); 6721da177e4SLinus Torvalds show_free_areas(); 6731da177e4SLinus Torvalds return -ENOMEM; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds /* 6771da177e4SLinus Torvalds * handle mapping creation for uClinux 6781da177e4SLinus Torvalds */ 6791da177e4SLinus Torvalds unsigned long do_mmap_pgoff(struct file *file, 6801da177e4SLinus Torvalds unsigned long addr, 6811da177e4SLinus Torvalds unsigned long len, 6821da177e4SLinus Torvalds unsigned long prot, 6831da177e4SLinus Torvalds unsigned long flags, 6841da177e4SLinus Torvalds unsigned long pgoff) 6851da177e4SLinus Torvalds { 6861da177e4SLinus Torvalds struct vm_list_struct *vml = NULL; 6871da177e4SLinus Torvalds struct vm_area_struct *vma = NULL; 6881da177e4SLinus Torvalds struct rb_node *rb; 6891da177e4SLinus Torvalds unsigned long capabilities, vm_flags; 6901da177e4SLinus Torvalds void *result; 6911da177e4SLinus Torvalds int ret; 6921da177e4SLinus Torvalds 6931da177e4SLinus Torvalds /* decide whether we should attempt the mapping, and if so what sort of 6941da177e4SLinus Torvalds * mapping */ 6951da177e4SLinus Torvalds ret = validate_mmap_request(file, addr, len, prot, flags, pgoff, 6961da177e4SLinus Torvalds &capabilities); 6971da177e4SLinus Torvalds if (ret < 0) 6981da177e4SLinus Torvalds return ret; 6991da177e4SLinus Torvalds 7001da177e4SLinus Torvalds /* we've determined that we can make the mapping, now translate what we 7011da177e4SLinus Torvalds * now know into VMA flags */ 7021da177e4SLinus Torvalds vm_flags = determine_vm_flags(file, prot, flags, capabilities); 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /* we're going to need to record the mapping if it works */ 7051da177e4SLinus Torvalds vml = kmalloc(sizeof(struct vm_list_struct), GFP_KERNEL); 7061da177e4SLinus Torvalds if (!vml) 7071da177e4SLinus Torvalds goto error_getting_vml; 7081da177e4SLinus Torvalds memset(vml, 0, sizeof(*vml)); 7091da177e4SLinus Torvalds 7101da177e4SLinus Torvalds down_write(&nommu_vma_sem); 7111da177e4SLinus Torvalds 7121da177e4SLinus Torvalds /* if we want to share, we need to check for VMAs created by other 7131da177e4SLinus Torvalds * mmap() calls that overlap with our proposed mapping 7141da177e4SLinus Torvalds * - we can only share with an exact match on most regular files 7151da177e4SLinus Torvalds * - shared mappings on character devices and memory backed files are 7161da177e4SLinus Torvalds * permitted to overlap inexactly as far as we are concerned for in 7171da177e4SLinus Torvalds * these cases, sharing is handled in the driver or filesystem rather 7181da177e4SLinus Torvalds * than here 7191da177e4SLinus Torvalds */ 7201da177e4SLinus Torvalds if (vm_flags & VM_MAYSHARE) { 7211da177e4SLinus Torvalds unsigned long pglen = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 7221da177e4SLinus Torvalds unsigned long vmpglen; 7231da177e4SLinus Torvalds 7241da177e4SLinus Torvalds for (rb = rb_first(&nommu_vma_tree); rb; rb = rb_next(rb)) { 7251da177e4SLinus Torvalds vma = rb_entry(rb, struct vm_area_struct, vm_rb); 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds if (!(vma->vm_flags & VM_MAYSHARE)) 7281da177e4SLinus Torvalds continue; 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds /* search for overlapping mappings on the same file */ 7311da177e4SLinus Torvalds if (vma->vm_file->f_dentry->d_inode != file->f_dentry->d_inode) 7321da177e4SLinus Torvalds continue; 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds if (vma->vm_pgoff >= pgoff + pglen) 7351da177e4SLinus Torvalds continue; 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds vmpglen = vma->vm_end - vma->vm_start + PAGE_SIZE - 1; 7381da177e4SLinus Torvalds vmpglen >>= PAGE_SHIFT; 7391da177e4SLinus Torvalds if (pgoff >= vma->vm_pgoff + vmpglen) 7401da177e4SLinus Torvalds continue; 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds /* handle inexactly overlapping matches between mappings */ 7431da177e4SLinus Torvalds if (vma->vm_pgoff != pgoff || vmpglen != pglen) { 7441da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_DIRECT)) 7451da177e4SLinus Torvalds goto sharing_violation; 7461da177e4SLinus Torvalds continue; 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds /* we've found a VMA we can share */ 7501da177e4SLinus Torvalds atomic_inc(&vma->vm_usage); 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds vml->vma = vma; 7531da177e4SLinus Torvalds result = (void *) vma->vm_start; 7541da177e4SLinus Torvalds goto shared; 7551da177e4SLinus Torvalds } 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds vma = NULL; 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds /* obtain the address at which to make a shared mapping 7601da177e4SLinus Torvalds * - this is the hook for quasi-memory character devices to 7611da177e4SLinus Torvalds * tell us the location of a shared mapping 7621da177e4SLinus Torvalds */ 7631da177e4SLinus Torvalds if (file && file->f_op->get_unmapped_area) { 7641da177e4SLinus Torvalds addr = file->f_op->get_unmapped_area(file, addr, len, 7651da177e4SLinus Torvalds pgoff, flags); 7661da177e4SLinus Torvalds if (IS_ERR((void *) addr)) { 7671da177e4SLinus Torvalds ret = addr; 7681da177e4SLinus Torvalds if (ret != (unsigned long) -ENOSYS) 7691da177e4SLinus Torvalds goto error; 7701da177e4SLinus Torvalds 7711da177e4SLinus Torvalds /* the driver refused to tell us where to site 7721da177e4SLinus Torvalds * the mapping so we'll have to attempt to copy 7731da177e4SLinus Torvalds * it */ 7741da177e4SLinus Torvalds ret = (unsigned long) -ENODEV; 7751da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_COPY)) 7761da177e4SLinus Torvalds goto error; 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds /* we're going to need a VMA struct as well */ 7841da177e4SLinus Torvalds vma = kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); 7851da177e4SLinus Torvalds if (!vma) 7861da177e4SLinus Torvalds goto error_getting_vma; 7871da177e4SLinus Torvalds 7881da177e4SLinus Torvalds memset(vma, 0, sizeof(*vma)); 7891da177e4SLinus Torvalds INIT_LIST_HEAD(&vma->anon_vma_node); 7901da177e4SLinus Torvalds atomic_set(&vma->vm_usage, 1); 7911da177e4SLinus Torvalds if (file) 7921da177e4SLinus Torvalds get_file(file); 7931da177e4SLinus Torvalds vma->vm_file = file; 7941da177e4SLinus Torvalds vma->vm_flags = vm_flags; 7951da177e4SLinus Torvalds vma->vm_start = addr; 7961da177e4SLinus Torvalds vma->vm_end = addr + len; 7971da177e4SLinus Torvalds vma->vm_pgoff = pgoff; 7981da177e4SLinus Torvalds 7991da177e4SLinus Torvalds vml->vma = vma; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds /* set up the mapping */ 8021da177e4SLinus Torvalds if (file && vma->vm_flags & VM_SHARED) 8031da177e4SLinus Torvalds ret = do_mmap_shared_file(vma, len); 8041da177e4SLinus Torvalds else 8051da177e4SLinus Torvalds ret = do_mmap_private(vma, len); 8061da177e4SLinus Torvalds if (ret < 0) 8071da177e4SLinus Torvalds goto error; 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds /* okay... we have a mapping; now we have to register it */ 8101da177e4SLinus Torvalds result = (void *) vma->vm_start; 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds if (vma->vm_flags & VM_MAPPED_COPY) { 8131da177e4SLinus Torvalds realalloc += kobjsize(result); 8141da177e4SLinus Torvalds askedalloc += len; 8151da177e4SLinus Torvalds } 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds realalloc += kobjsize(vma); 8181da177e4SLinus Torvalds askedalloc += sizeof(*vma); 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds current->mm->total_vm += len >> PAGE_SHIFT; 8211da177e4SLinus Torvalds 8221da177e4SLinus Torvalds add_nommu_vma(vma); 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds shared: 8251da177e4SLinus Torvalds realalloc += kobjsize(vml); 8261da177e4SLinus Torvalds askedalloc += sizeof(*vml); 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds vml->next = current->mm->context.vmlist; 8291da177e4SLinus Torvalds current->mm->context.vmlist = vml; 8301da177e4SLinus Torvalds 8311da177e4SLinus Torvalds up_write(&nommu_vma_sem); 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds if (prot & PROT_EXEC) 8341da177e4SLinus Torvalds flush_icache_range((unsigned long) result, 8351da177e4SLinus Torvalds (unsigned long) result + len); 8361da177e4SLinus Torvalds 8371da177e4SLinus Torvalds #ifdef DEBUG 8381da177e4SLinus Torvalds printk("do_mmap:\n"); 8391da177e4SLinus Torvalds show_process_blocks(); 8401da177e4SLinus Torvalds #endif 8411da177e4SLinus Torvalds 8421da177e4SLinus Torvalds return (unsigned long) result; 8431da177e4SLinus Torvalds 8441da177e4SLinus Torvalds error: 8451da177e4SLinus Torvalds up_write(&nommu_vma_sem); 8461da177e4SLinus Torvalds kfree(vml); 8471da177e4SLinus Torvalds if (vma) { 8481da177e4SLinus Torvalds fput(vma->vm_file); 8491da177e4SLinus Torvalds kfree(vma); 8501da177e4SLinus Torvalds } 8511da177e4SLinus Torvalds return ret; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds sharing_violation: 8541da177e4SLinus Torvalds up_write(&nommu_vma_sem); 8551da177e4SLinus Torvalds printk("Attempt to share mismatched mappings\n"); 8561da177e4SLinus Torvalds kfree(vml); 8571da177e4SLinus Torvalds return -EINVAL; 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds error_getting_vma: 8601da177e4SLinus Torvalds up_write(&nommu_vma_sem); 8611da177e4SLinus Torvalds kfree(vml); 862*66aa2b4bSGreg Ungerer printk("Allocation of vma for %lu byte allocation from process %d failed\n", 8631da177e4SLinus Torvalds len, current->pid); 8641da177e4SLinus Torvalds show_free_areas(); 8651da177e4SLinus Torvalds return -ENOMEM; 8661da177e4SLinus Torvalds 8671da177e4SLinus Torvalds error_getting_vml: 8681da177e4SLinus Torvalds printk("Allocation of vml for %lu byte allocation from process %d failed\n", 8691da177e4SLinus Torvalds len, current->pid); 8701da177e4SLinus Torvalds show_free_areas(); 8711da177e4SLinus Torvalds return -ENOMEM; 8721da177e4SLinus Torvalds } 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds /* 8751da177e4SLinus Torvalds * handle mapping disposal for uClinux 8761da177e4SLinus Torvalds */ 8771da177e4SLinus Torvalds static void put_vma(struct vm_area_struct *vma) 8781da177e4SLinus Torvalds { 8791da177e4SLinus Torvalds if (vma) { 8801da177e4SLinus Torvalds down_write(&nommu_vma_sem); 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds if (atomic_dec_and_test(&vma->vm_usage)) { 8831da177e4SLinus Torvalds delete_nommu_vma(vma); 8841da177e4SLinus Torvalds 8851da177e4SLinus Torvalds if (vma->vm_ops && vma->vm_ops->close) 8861da177e4SLinus Torvalds vma->vm_ops->close(vma); 8871da177e4SLinus Torvalds 8881da177e4SLinus Torvalds /* IO memory and memory shared directly out of the pagecache from 8891da177e4SLinus Torvalds * ramfs/tmpfs mustn't be released here */ 8901da177e4SLinus Torvalds if (vma->vm_flags & VM_MAPPED_COPY) { 8911da177e4SLinus Torvalds realalloc -= kobjsize((void *) vma->vm_start); 8921da177e4SLinus Torvalds askedalloc -= vma->vm_end - vma->vm_start; 8931da177e4SLinus Torvalds kfree((void *) vma->vm_start); 8941da177e4SLinus Torvalds } 8951da177e4SLinus Torvalds 8961da177e4SLinus Torvalds realalloc -= kobjsize(vma); 8971da177e4SLinus Torvalds askedalloc -= sizeof(*vma); 8981da177e4SLinus Torvalds 8991da177e4SLinus Torvalds if (vma->vm_file) 9001da177e4SLinus Torvalds fput(vma->vm_file); 9011da177e4SLinus Torvalds kfree(vma); 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds up_write(&nommu_vma_sem); 9051da177e4SLinus Torvalds } 9061da177e4SLinus Torvalds } 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) 9091da177e4SLinus Torvalds { 9101da177e4SLinus Torvalds struct vm_list_struct *vml, **parent; 9111da177e4SLinus Torvalds unsigned long end = addr + len; 9121da177e4SLinus Torvalds 9131da177e4SLinus Torvalds #ifdef DEBUG 9141da177e4SLinus Torvalds printk("do_munmap:\n"); 9151da177e4SLinus Torvalds #endif 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) 9181da177e4SLinus Torvalds if ((*parent)->vma->vm_start == addr && 919*66aa2b4bSGreg Ungerer ((len == 0) || ((*parent)->vma->vm_end == end))) 9201da177e4SLinus Torvalds goto found; 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds printk("munmap of non-mmaped memory by process %d (%s): %p\n", 9231da177e4SLinus Torvalds current->pid, current->comm, (void *) addr); 9241da177e4SLinus Torvalds return -EINVAL; 9251da177e4SLinus Torvalds 9261da177e4SLinus Torvalds found: 9271da177e4SLinus Torvalds vml = *parent; 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds put_vma(vml->vma); 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds *parent = vml->next; 9321da177e4SLinus Torvalds realalloc -= kobjsize(vml); 9331da177e4SLinus Torvalds askedalloc -= sizeof(*vml); 9341da177e4SLinus Torvalds kfree(vml); 9351da177e4SLinus Torvalds mm->total_vm -= len >> PAGE_SHIFT; 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds #ifdef DEBUG 9381da177e4SLinus Torvalds show_process_blocks(); 9391da177e4SLinus Torvalds #endif 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds return 0; 9421da177e4SLinus Torvalds } 9431da177e4SLinus Torvalds 9441da177e4SLinus Torvalds /* Release all mmaps. */ 9451da177e4SLinus Torvalds void exit_mmap(struct mm_struct * mm) 9461da177e4SLinus Torvalds { 9471da177e4SLinus Torvalds struct vm_list_struct *tmp; 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds if (mm) { 9501da177e4SLinus Torvalds #ifdef DEBUG 9511da177e4SLinus Torvalds printk("Exit_mmap:\n"); 9521da177e4SLinus Torvalds #endif 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds mm->total_vm = 0; 9551da177e4SLinus Torvalds 9561da177e4SLinus Torvalds while ((tmp = mm->context.vmlist)) { 9571da177e4SLinus Torvalds mm->context.vmlist = tmp->next; 9581da177e4SLinus Torvalds put_vma(tmp->vma); 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds realalloc -= kobjsize(tmp); 9611da177e4SLinus Torvalds askedalloc -= sizeof(*tmp); 9621da177e4SLinus Torvalds kfree(tmp); 9631da177e4SLinus Torvalds } 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds #ifdef DEBUG 9661da177e4SLinus Torvalds show_process_blocks(); 9671da177e4SLinus Torvalds #endif 9681da177e4SLinus Torvalds } 9691da177e4SLinus Torvalds } 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds asmlinkage long sys_munmap(unsigned long addr, size_t len) 9721da177e4SLinus Torvalds { 9731da177e4SLinus Torvalds int ret; 9741da177e4SLinus Torvalds struct mm_struct *mm = current->mm; 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds down_write(&mm->mmap_sem); 9771da177e4SLinus Torvalds ret = do_munmap(mm, addr, len); 9781da177e4SLinus Torvalds up_write(&mm->mmap_sem); 9791da177e4SLinus Torvalds return ret; 9801da177e4SLinus Torvalds } 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds unsigned long do_brk(unsigned long addr, unsigned long len) 9831da177e4SLinus Torvalds { 9841da177e4SLinus Torvalds return -ENOMEM; 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds /* 9881da177e4SLinus Torvalds * Expand (or shrink) an existing mapping, potentially moving it at the 9891da177e4SLinus Torvalds * same time (controlled by the MREMAP_MAYMOVE flag and available VM space) 9901da177e4SLinus Torvalds * 9911da177e4SLinus Torvalds * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise 9921da177e4SLinus Torvalds * This option implies MREMAP_MAYMOVE. 9931da177e4SLinus Torvalds * 9941da177e4SLinus Torvalds * on uClinux, we only permit changing a mapping's size, and only as long as it stays within the 9951da177e4SLinus Torvalds * hole allocated by the kmalloc() call in do_mmap_pgoff() and the block is not shareable 9961da177e4SLinus Torvalds */ 9971da177e4SLinus Torvalds unsigned long do_mremap(unsigned long addr, 9981da177e4SLinus Torvalds unsigned long old_len, unsigned long new_len, 9991da177e4SLinus Torvalds unsigned long flags, unsigned long new_addr) 10001da177e4SLinus Torvalds { 10011da177e4SLinus Torvalds struct vm_list_struct *vml = NULL; 10021da177e4SLinus Torvalds 10031da177e4SLinus Torvalds /* insanity checks first */ 10041da177e4SLinus Torvalds if (new_len == 0) 10051da177e4SLinus Torvalds return (unsigned long) -EINVAL; 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds if (flags & MREMAP_FIXED && new_addr != addr) 10081da177e4SLinus Torvalds return (unsigned long) -EINVAL; 10091da177e4SLinus Torvalds 10101da177e4SLinus Torvalds for (vml = current->mm->context.vmlist; vml; vml = vml->next) 10111da177e4SLinus Torvalds if (vml->vma->vm_start == addr) 10121da177e4SLinus Torvalds goto found; 10131da177e4SLinus Torvalds 10141da177e4SLinus Torvalds return (unsigned long) -EINVAL; 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds found: 10171da177e4SLinus Torvalds if (vml->vma->vm_end != vml->vma->vm_start + old_len) 10181da177e4SLinus Torvalds return (unsigned long) -EFAULT; 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds if (vml->vma->vm_flags & VM_MAYSHARE) 10211da177e4SLinus Torvalds return (unsigned long) -EPERM; 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds if (new_len > kobjsize((void *) addr)) 10241da177e4SLinus Torvalds return (unsigned long) -ENOMEM; 10251da177e4SLinus Torvalds 10261da177e4SLinus Torvalds /* all checks complete - do it */ 10271da177e4SLinus Torvalds vml->vma->vm_end = vml->vma->vm_start + new_len; 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds askedalloc -= old_len; 10301da177e4SLinus Torvalds askedalloc += new_len; 10311da177e4SLinus Torvalds 10321da177e4SLinus Torvalds return vml->vma->vm_start; 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds /* 10361da177e4SLinus Torvalds * Look up the first VMA which satisfies addr < vm_end, NULL if none 10371da177e4SLinus Torvalds */ 10381da177e4SLinus Torvalds struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) 10391da177e4SLinus Torvalds { 10401da177e4SLinus Torvalds struct vm_list_struct *vml; 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds for (vml = mm->context.vmlist; vml; vml = vml->next) 10431da177e4SLinus Torvalds if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end) 10441da177e4SLinus Torvalds return vml->vma; 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds return NULL; 10471da177e4SLinus Torvalds } 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds EXPORT_SYMBOL(find_vma); 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds struct page * follow_page(struct mm_struct *mm, unsigned long addr, int write) 10521da177e4SLinus Torvalds { 10531da177e4SLinus Torvalds return NULL; 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) 10571da177e4SLinus Torvalds { 10581da177e4SLinus Torvalds return NULL; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, 10621da177e4SLinus Torvalds unsigned long to, unsigned long size, pgprot_t prot) 10631da177e4SLinus Torvalds { 1064*66aa2b4bSGreg Ungerer vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; 1065*66aa2b4bSGreg Ungerer return 0; 10661da177e4SLinus Torvalds } 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) 10691da177e4SLinus Torvalds { 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds unsigned long arch_get_unmapped_area(struct file *file, unsigned long addr, 10731da177e4SLinus Torvalds unsigned long len, unsigned long pgoff, unsigned long flags) 10741da177e4SLinus Torvalds { 10751da177e4SLinus Torvalds return -ENOMEM; 10761da177e4SLinus Torvalds } 10771da177e4SLinus Torvalds 10781363c3cdSWolfgang Wander void arch_unmap_area(struct mm_struct *mm, unsigned long addr) 10791da177e4SLinus Torvalds { 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 10821da177e4SLinus Torvalds void update_mem_hiwater(struct task_struct *tsk) 10831da177e4SLinus Torvalds { 1084*66aa2b4bSGreg Ungerer unsigned long rss; 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds if (likely(tsk->mm)) { 1087*66aa2b4bSGreg Ungerer rss = get_mm_counter(tsk->mm, rss); 10881da177e4SLinus Torvalds if (tsk->mm->hiwater_rss < rss) 10891da177e4SLinus Torvalds tsk->mm->hiwater_rss = rss; 10901da177e4SLinus Torvalds if (tsk->mm->hiwater_vm < tsk->mm->total_vm) 10911da177e4SLinus Torvalds tsk->mm->hiwater_vm = tsk->mm->total_vm; 10921da177e4SLinus Torvalds } 10931da177e4SLinus Torvalds } 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds void unmap_mapping_range(struct address_space *mapping, 10961da177e4SLinus Torvalds loff_t const holebegin, loff_t const holelen, 10971da177e4SLinus Torvalds int even_cows) 10981da177e4SLinus Torvalds { 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds 11011da177e4SLinus Torvalds /* 11021da177e4SLinus Torvalds * Check that a process has enough memory to allocate a new virtual 11031da177e4SLinus Torvalds * mapping. 0 means there is enough memory for the allocation to 11041da177e4SLinus Torvalds * succeed and -ENOMEM implies there is not. 11051da177e4SLinus Torvalds * 11061da177e4SLinus Torvalds * We currently support three overcommit policies, which are set via the 11071da177e4SLinus Torvalds * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting 11081da177e4SLinus Torvalds * 11091da177e4SLinus Torvalds * Strict overcommit modes added 2002 Feb 26 by Alan Cox. 11101da177e4SLinus Torvalds * Additional code 2002 Jul 20 by Robert Love. 11111da177e4SLinus Torvalds * 11121da177e4SLinus Torvalds * cap_sys_admin is 1 if the process has admin privileges, 0 otherwise. 11131da177e4SLinus Torvalds * 11141da177e4SLinus Torvalds * Note this is a helper function intended to be used by LSMs which 11151da177e4SLinus Torvalds * wish to use this logic. 11161da177e4SLinus Torvalds */ 11171da177e4SLinus Torvalds int __vm_enough_memory(long pages, int cap_sys_admin) 11181da177e4SLinus Torvalds { 11191da177e4SLinus Torvalds unsigned long free, allowed; 11201da177e4SLinus Torvalds 11211da177e4SLinus Torvalds vm_acct_memory(pages); 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds /* 11241da177e4SLinus Torvalds * Sometimes we want to use more memory than we have 11251da177e4SLinus Torvalds */ 11261da177e4SLinus Torvalds if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) 11271da177e4SLinus Torvalds return 0; 11281da177e4SLinus Torvalds 11291da177e4SLinus Torvalds if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { 11301da177e4SLinus Torvalds unsigned long n; 11311da177e4SLinus Torvalds 11321da177e4SLinus Torvalds free = get_page_cache_size(); 11331da177e4SLinus Torvalds free += nr_swap_pages; 11341da177e4SLinus Torvalds 11351da177e4SLinus Torvalds /* 11361da177e4SLinus Torvalds * Any slabs which are created with the 11371da177e4SLinus Torvalds * SLAB_RECLAIM_ACCOUNT flag claim to have contents 11381da177e4SLinus Torvalds * which are reclaimable, under pressure. The dentry 11391da177e4SLinus Torvalds * cache and most inode caches should fall into this 11401da177e4SLinus Torvalds */ 11411da177e4SLinus Torvalds free += atomic_read(&slab_reclaim_pages); 11421da177e4SLinus Torvalds 11431da177e4SLinus Torvalds /* 11441da177e4SLinus Torvalds * Leave the last 3% for root 11451da177e4SLinus Torvalds */ 11461da177e4SLinus Torvalds if (!cap_sys_admin) 11471da177e4SLinus Torvalds free -= free / 32; 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds if (free > pages) 11501da177e4SLinus Torvalds return 0; 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds /* 11531da177e4SLinus Torvalds * nr_free_pages() is very expensive on large systems, 11541da177e4SLinus Torvalds * only call if we're about to fail. 11551da177e4SLinus Torvalds */ 11561da177e4SLinus Torvalds n = nr_free_pages(); 11571da177e4SLinus Torvalds if (!cap_sys_admin) 11581da177e4SLinus Torvalds n -= n / 32; 11591da177e4SLinus Torvalds free += n; 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds if (free > pages) 11621da177e4SLinus Torvalds return 0; 11631da177e4SLinus Torvalds vm_unacct_memory(pages); 11641da177e4SLinus Torvalds return -ENOMEM; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds 11671da177e4SLinus Torvalds allowed = totalram_pages * sysctl_overcommit_ratio / 100; 11681da177e4SLinus Torvalds /* 11691da177e4SLinus Torvalds * Leave the last 3% for root 11701da177e4SLinus Torvalds */ 11711da177e4SLinus Torvalds if (!cap_sys_admin) 11721da177e4SLinus Torvalds allowed -= allowed / 32; 11731da177e4SLinus Torvalds allowed += total_swap_pages; 11741da177e4SLinus Torvalds 11751da177e4SLinus Torvalds /* Don't let a single process grow too big: 11761da177e4SLinus Torvalds leave 3% of the size of this process for other processes */ 11771da177e4SLinus Torvalds allowed -= current->mm->total_vm / 32; 11781da177e4SLinus Torvalds 11792f60f8d3SSimon Derr /* 11802f60f8d3SSimon Derr * cast `allowed' as a signed long because vm_committed_space 11812f60f8d3SSimon Derr * sometimes has a negative value 11822f60f8d3SSimon Derr */ 11832f60f8d3SSimon Derr if (atomic_read(&vm_committed_space) < (long)allowed) 11841da177e4SLinus Torvalds return 0; 11851da177e4SLinus Torvalds 11861da177e4SLinus Torvalds vm_unacct_memory(pages); 11871da177e4SLinus Torvalds 11881da177e4SLinus Torvalds return -ENOMEM; 11891da177e4SLinus Torvalds } 11901da177e4SLinus Torvalds 11911da177e4SLinus Torvalds int in_gate_area_no_task(unsigned long addr) 11921da177e4SLinus Torvalds { 11931da177e4SLinus Torvalds return 0; 11941da177e4SLinus Torvalds } 1195