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