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); 486a04de6dSWu, Bryan EXPORT_SYMBOL(num_physpages); 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* list of shareable VMAs */ 511da177e4SLinus Torvalds struct rb_root nommu_vma_tree = RB_ROOT; 521da177e4SLinus Torvalds DECLARE_RWSEM(nommu_vma_sem); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds struct vm_operations_struct generic_file_vm_ops = { 551da177e4SLinus Torvalds }; 561da177e4SLinus Torvalds 5766aa2b4bSGreg Ungerer EXPORT_SYMBOL(vfree); 5866aa2b4bSGreg Ungerer EXPORT_SYMBOL(vmalloc_to_page); 5966aa2b4bSGreg Ungerer EXPORT_SYMBOL(vmalloc_32); 607a9166e3SLuke Yang EXPORT_SYMBOL(vmap); 617a9166e3SLuke Yang EXPORT_SYMBOL(vunmap); 6266aa2b4bSGreg Ungerer 631da177e4SLinus Torvalds /* 641da177e4SLinus Torvalds * Handle all mappings that got truncated by a "truncate()" 651da177e4SLinus Torvalds * system call. 661da177e4SLinus Torvalds * 671da177e4SLinus Torvalds * NOTE! We have to be ready to update the memory sharing 681da177e4SLinus Torvalds * between the file and the memory map for a potential last 691da177e4SLinus Torvalds * incomplete page. Ugly, but necessary. 701da177e4SLinus Torvalds */ 711da177e4SLinus Torvalds int vmtruncate(struct inode *inode, loff_t offset) 721da177e4SLinus Torvalds { 731da177e4SLinus Torvalds struct address_space *mapping = inode->i_mapping; 741da177e4SLinus Torvalds unsigned long limit; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds if (inode->i_size < offset) 771da177e4SLinus Torvalds goto do_expand; 781da177e4SLinus Torvalds i_size_write(inode, offset); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds truncate_inode_pages(mapping, offset); 811da177e4SLinus Torvalds goto out_truncate; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds do_expand: 841da177e4SLinus Torvalds limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; 851da177e4SLinus Torvalds if (limit != RLIM_INFINITY && offset > limit) 861da177e4SLinus Torvalds goto out_sig; 871da177e4SLinus Torvalds if (offset > inode->i_sb->s_maxbytes) 881da177e4SLinus Torvalds goto out; 891da177e4SLinus Torvalds i_size_write(inode, offset); 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds out_truncate: 921da177e4SLinus Torvalds if (inode->i_op && inode->i_op->truncate) 931da177e4SLinus Torvalds inode->i_op->truncate(inode); 941da177e4SLinus Torvalds return 0; 951da177e4SLinus Torvalds out_sig: 961da177e4SLinus Torvalds send_sig(SIGXFSZ, current, 0); 971da177e4SLinus Torvalds out: 981da177e4SLinus Torvalds return -EFBIG; 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds EXPORT_SYMBOL(vmtruncate); 1021da177e4SLinus Torvalds 1031da177e4SLinus Torvalds /* 1041da177e4SLinus Torvalds * Return the total memory allocated for this pointer, not 1051da177e4SLinus Torvalds * just what the caller asked for. 1061da177e4SLinus Torvalds * 1071da177e4SLinus Torvalds * Doesn't have to be accurate, i.e. may have races. 1081da177e4SLinus Torvalds */ 1091da177e4SLinus Torvalds unsigned int kobjsize(const void *objp) 1101da177e4SLinus Torvalds { 1111da177e4SLinus Torvalds struct page *page; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds if (!objp || !((page = virt_to_page(objp)))) 1141da177e4SLinus Torvalds return 0; 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds if (PageSlab(page)) 1171da177e4SLinus Torvalds return ksize(objp); 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds BUG_ON(page->index < 0); 1201da177e4SLinus Torvalds BUG_ON(page->index >= MAX_ORDER); 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds return (PAGE_SIZE << page->index); 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* 1267b4d5b8bSDavid Howells * get a list of pages in an address range belonging to the specified process 1277b4d5b8bSDavid Howells * and indicate the VMA that covers each page 1287b4d5b8bSDavid Howells * - this is potentially dodgy as we may end incrementing the page count of a 1297b4d5b8bSDavid Howells * slab page or a secondary page from a compound page 1307b4d5b8bSDavid Howells * - don't permit access to VMAs that don't support it, such as I/O mappings 1311da177e4SLinus Torvalds */ 1321da177e4SLinus Torvalds int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, 1331da177e4SLinus Torvalds unsigned long start, int len, int write, int force, 1341da177e4SLinus Torvalds struct page **pages, struct vm_area_struct **vmas) 1351da177e4SLinus Torvalds { 136910e46daSSonic Zhang struct vm_area_struct *vma; 1377b4d5b8bSDavid Howells unsigned long vm_flags; 1387b4d5b8bSDavid Howells int i; 1397b4d5b8bSDavid Howells 1407b4d5b8bSDavid Howells /* calculate required read or write permissions. 1417b4d5b8bSDavid Howells * - if 'force' is set, we only require the "MAY" flags. 1427b4d5b8bSDavid Howells */ 1437b4d5b8bSDavid Howells vm_flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD); 1447b4d5b8bSDavid Howells vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds for (i = 0; i < len; i++) { 147910e46daSSonic Zhang vma = find_vma(mm, start); 148910e46daSSonic Zhang if (!vma) 1497b4d5b8bSDavid Howells goto finish_or_fault; 1507b4d5b8bSDavid Howells 1517b4d5b8bSDavid Howells /* protect what we can, including chardevs */ 1527b4d5b8bSDavid Howells if (vma->vm_flags & (VM_IO | VM_PFNMAP) || 1537b4d5b8bSDavid Howells !(vm_flags & vma->vm_flags)) 1547b4d5b8bSDavid Howells goto finish_or_fault; 155910e46daSSonic Zhang 1561da177e4SLinus Torvalds if (pages) { 1571da177e4SLinus Torvalds pages[i] = virt_to_page(start); 1581da177e4SLinus Torvalds if (pages[i]) 1591da177e4SLinus Torvalds page_cache_get(pages[i]); 1601da177e4SLinus Torvalds } 1611da177e4SLinus Torvalds if (vmas) 162910e46daSSonic Zhang vmas[i] = vma; 1631da177e4SLinus Torvalds start += PAGE_SIZE; 1641da177e4SLinus Torvalds } 1657b4d5b8bSDavid Howells 1667b4d5b8bSDavid Howells return i; 1677b4d5b8bSDavid Howells 1687b4d5b8bSDavid Howells finish_or_fault: 1697b4d5b8bSDavid Howells return i ? : -EFAULT; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 17266aa2b4bSGreg Ungerer EXPORT_SYMBOL(get_user_pages); 17366aa2b4bSGreg Ungerer 1741da177e4SLinus Torvalds DEFINE_RWLOCK(vmlist_lock); 1751da177e4SLinus Torvalds struct vm_struct *vmlist; 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds void vfree(void *addr) 1781da177e4SLinus Torvalds { 1791da177e4SLinus Torvalds kfree(addr); 1801da177e4SLinus Torvalds } 1811da177e4SLinus Torvalds 182dd0fc66fSAl Viro void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds /* 1851da177e4SLinus Torvalds * kmalloc doesn't like __GFP_HIGHMEM for some reason 1861da177e4SLinus Torvalds */ 18784097518SNick Piggin return kmalloc(size, (gfp_mask | __GFP_COMP) & ~__GFP_HIGHMEM); 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds struct page * vmalloc_to_page(void *addr) 1911da177e4SLinus Torvalds { 1921da177e4SLinus Torvalds return virt_to_page(addr); 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds unsigned long vmalloc_to_pfn(void *addr) 1961da177e4SLinus Torvalds { 1971da177e4SLinus Torvalds return page_to_pfn(virt_to_page(addr)); 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds long vread(char *buf, char *addr, unsigned long count) 2021da177e4SLinus Torvalds { 2031da177e4SLinus Torvalds memcpy(buf, addr, count); 2041da177e4SLinus Torvalds return count; 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds long vwrite(char *buf, char *addr, unsigned long count) 2081da177e4SLinus Torvalds { 2091da177e4SLinus Torvalds /* Don't allow overflow */ 2101da177e4SLinus Torvalds if ((unsigned long) addr + count < count) 2111da177e4SLinus Torvalds count = -(unsigned long) addr; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds memcpy(addr, buf, count); 2141da177e4SLinus Torvalds return(count); 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds /* 2181da177e4SLinus Torvalds * vmalloc - allocate virtually continguos memory 2191da177e4SLinus Torvalds * 2201da177e4SLinus Torvalds * @size: allocation size 2211da177e4SLinus Torvalds * 2221da177e4SLinus Torvalds * Allocate enough pages to cover @size from the page level 2231da177e4SLinus Torvalds * allocator and map them into continguos kernel virtual space. 2241da177e4SLinus Torvalds * 225c1c8897fSMichael Opdenacker * For tight control over page level allocator and protection flags 2261da177e4SLinus Torvalds * use __vmalloc() instead. 2271da177e4SLinus Torvalds */ 2281da177e4SLinus Torvalds void *vmalloc(unsigned long size) 2291da177e4SLinus Torvalds { 2301da177e4SLinus Torvalds return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); 2311da177e4SLinus Torvalds } 232f6138882SAndrew Morton EXPORT_SYMBOL(vmalloc); 233f6138882SAndrew Morton 234f6138882SAndrew Morton void *vmalloc_node(unsigned long size, int node) 235f6138882SAndrew Morton { 236f6138882SAndrew Morton return vmalloc(size); 237f6138882SAndrew Morton } 238f6138882SAndrew Morton EXPORT_SYMBOL(vmalloc_node); 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* 2411da177e4SLinus Torvalds * vmalloc_32 - allocate virtually continguos memory (32bit addressable) 2421da177e4SLinus Torvalds * 2431da177e4SLinus Torvalds * @size: allocation size 2441da177e4SLinus Torvalds * 2451da177e4SLinus Torvalds * Allocate enough 32bit PA addressable pages to cover @size from the 2461da177e4SLinus Torvalds * page level allocator and map them into continguos kernel virtual space. 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds void *vmalloc_32(unsigned long size) 2491da177e4SLinus Torvalds { 2501da177e4SLinus Torvalds return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds 2531da177e4SLinus Torvalds void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot) 2541da177e4SLinus Torvalds { 2551da177e4SLinus Torvalds BUG(); 2561da177e4SLinus Torvalds return NULL; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds void vunmap(void *addr) 2601da177e4SLinus Torvalds { 2611da177e4SLinus Torvalds BUG(); 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds /* 265*1eeb66a1SChristoph Hellwig * Implement a stub for vmalloc_sync_all() if the architecture chose not to 266*1eeb66a1SChristoph Hellwig * have one. 267*1eeb66a1SChristoph Hellwig */ 268*1eeb66a1SChristoph Hellwig void __attribute__((weak)) vmalloc_sync_all(void) 269*1eeb66a1SChristoph Hellwig { 270*1eeb66a1SChristoph Hellwig } 271*1eeb66a1SChristoph Hellwig 272*1eeb66a1SChristoph Hellwig /* 2731da177e4SLinus Torvalds * sys_brk() for the most part doesn't need the global kernel 2741da177e4SLinus Torvalds * lock, except when an application is doing something nasty 2751da177e4SLinus Torvalds * like trying to un-brk an area that has already been mapped 2761da177e4SLinus Torvalds * to a regular file. in this case, the unmapping will need 2771da177e4SLinus Torvalds * to invoke file system routines that need the global lock. 2781da177e4SLinus Torvalds */ 2791da177e4SLinus Torvalds asmlinkage unsigned long sys_brk(unsigned long brk) 2801da177e4SLinus Torvalds { 2811da177e4SLinus Torvalds struct mm_struct *mm = current->mm; 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds if (brk < mm->start_brk || brk > mm->context.end_brk) 2841da177e4SLinus Torvalds return mm->brk; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds if (mm->brk == brk) 2871da177e4SLinus Torvalds return mm->brk; 2881da177e4SLinus Torvalds 2891da177e4SLinus Torvalds /* 2901da177e4SLinus Torvalds * Always allow shrinking brk 2911da177e4SLinus Torvalds */ 2921da177e4SLinus Torvalds if (brk <= mm->brk) { 2931da177e4SLinus Torvalds mm->brk = brk; 2941da177e4SLinus Torvalds return brk; 2951da177e4SLinus Torvalds } 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds /* 2981da177e4SLinus Torvalds * Ok, looks good - let it rip. 2991da177e4SLinus Torvalds */ 3001da177e4SLinus Torvalds return mm->brk = brk; 3011da177e4SLinus Torvalds } 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds #ifdef DEBUG 3041da177e4SLinus Torvalds static void show_process_blocks(void) 3051da177e4SLinus Torvalds { 3061da177e4SLinus Torvalds struct vm_list_struct *vml; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds printk("Process blocks %d:", current->pid); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds for (vml = ¤t->mm->context.vmlist; vml; vml = vml->next) { 3111da177e4SLinus Torvalds printk(" %p: %p", vml, vml->vma); 3121da177e4SLinus Torvalds if (vml->vma) 3131da177e4SLinus Torvalds printk(" (%d @%lx #%d)", 3141da177e4SLinus Torvalds kobjsize((void *) vml->vma->vm_start), 3151da177e4SLinus Torvalds vml->vma->vm_start, 3161da177e4SLinus Torvalds atomic_read(&vml->vma->vm_usage)); 3171da177e4SLinus Torvalds printk(vml->next ? " ->" : ".\n"); 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds } 3201da177e4SLinus Torvalds #endif /* DEBUG */ 3211da177e4SLinus Torvalds 3223034097aSDavid Howells /* 3233034097aSDavid Howells * add a VMA into a process's mm_struct in the appropriate place in the list 3243034097aSDavid Howells * - should be called with mm->mmap_sem held writelocked 3253034097aSDavid Howells */ 3263034097aSDavid Howells static void add_vma_to_mm(struct mm_struct *mm, struct vm_list_struct *vml) 3273034097aSDavid Howells { 3283034097aSDavid Howells struct vm_list_struct **ppv; 3293034097aSDavid Howells 3303034097aSDavid Howells for (ppv = ¤t->mm->context.vmlist; *ppv; ppv = &(*ppv)->next) 3313034097aSDavid Howells if ((*ppv)->vma->vm_start > vml->vma->vm_start) 3323034097aSDavid Howells break; 3333034097aSDavid Howells 3343034097aSDavid Howells vml->next = *ppv; 3353034097aSDavid Howells *ppv = vml; 3363034097aSDavid Howells } 3373034097aSDavid Howells 3383034097aSDavid Howells /* 3393034097aSDavid Howells * look up the first VMA in which addr resides, NULL if none 3403034097aSDavid Howells * - should be called with mm->mmap_sem at least held readlocked 3413034097aSDavid Howells */ 3423034097aSDavid Howells struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) 3433034097aSDavid Howells { 3443034097aSDavid Howells struct vm_list_struct *loop, *vml; 3453034097aSDavid Howells 3463034097aSDavid Howells /* search the vm_start ordered list */ 3473034097aSDavid Howells vml = NULL; 3483034097aSDavid Howells for (loop = mm->context.vmlist; loop; loop = loop->next) { 3493034097aSDavid Howells if (loop->vma->vm_start > addr) 3503034097aSDavid Howells break; 3513034097aSDavid Howells vml = loop; 3523034097aSDavid Howells } 3533034097aSDavid Howells 3543034097aSDavid Howells if (vml && vml->vma->vm_end > addr) 3553034097aSDavid Howells return vml->vma; 3563034097aSDavid Howells 3573034097aSDavid Howells return NULL; 3583034097aSDavid Howells } 3593034097aSDavid Howells EXPORT_SYMBOL(find_vma); 3603034097aSDavid Howells 3613034097aSDavid Howells /* 362930e652aSDavid Howells * find a VMA 363930e652aSDavid Howells * - we don't extend stack VMAs under NOMMU conditions 364930e652aSDavid Howells */ 365930e652aSDavid Howells struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) 366930e652aSDavid Howells { 367930e652aSDavid Howells return find_vma(mm, addr); 368930e652aSDavid Howells } 369930e652aSDavid Howells 370930e652aSDavid Howells /* 3716fa5f80bSDavid Howells * look up the first VMA exactly that exactly matches addr 3726fa5f80bSDavid Howells * - should be called with mm->mmap_sem at least held readlocked 3736fa5f80bSDavid Howells */ 3746fa5f80bSDavid Howells static inline struct vm_area_struct *find_vma_exact(struct mm_struct *mm, 3756fa5f80bSDavid Howells unsigned long addr) 3766fa5f80bSDavid Howells { 3776fa5f80bSDavid Howells struct vm_list_struct *vml; 3786fa5f80bSDavid Howells 3796fa5f80bSDavid Howells /* search the vm_start ordered list */ 3806fa5f80bSDavid Howells for (vml = mm->context.vmlist; vml; vml = vml->next) { 3816fa5f80bSDavid Howells if (vml->vma->vm_start == addr) 3826fa5f80bSDavid Howells return vml->vma; 3836fa5f80bSDavid Howells if (vml->vma->vm_start > addr) 3846fa5f80bSDavid Howells break; 3856fa5f80bSDavid Howells } 3866fa5f80bSDavid Howells 3876fa5f80bSDavid Howells return NULL; 3886fa5f80bSDavid Howells } 3896fa5f80bSDavid Howells 3906fa5f80bSDavid Howells /* 3913034097aSDavid Howells * find a VMA in the global tree 3923034097aSDavid Howells */ 3931da177e4SLinus Torvalds static inline struct vm_area_struct *find_nommu_vma(unsigned long start) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds struct vm_area_struct *vma; 3961da177e4SLinus Torvalds struct rb_node *n = nommu_vma_tree.rb_node; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds while (n) { 3991da177e4SLinus Torvalds vma = rb_entry(n, struct vm_area_struct, vm_rb); 4001da177e4SLinus Torvalds 4011da177e4SLinus Torvalds if (start < vma->vm_start) 4021da177e4SLinus Torvalds n = n->rb_left; 4031da177e4SLinus Torvalds else if (start > vma->vm_start) 4041da177e4SLinus Torvalds n = n->rb_right; 4051da177e4SLinus Torvalds else 4061da177e4SLinus Torvalds return vma; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds return NULL; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds 4123034097aSDavid Howells /* 4133034097aSDavid Howells * add a VMA in the global tree 4143034097aSDavid Howells */ 4151da177e4SLinus Torvalds static void add_nommu_vma(struct vm_area_struct *vma) 4161da177e4SLinus Torvalds { 4171da177e4SLinus Torvalds struct vm_area_struct *pvma; 4181da177e4SLinus Torvalds struct address_space *mapping; 4191da177e4SLinus Torvalds struct rb_node **p = &nommu_vma_tree.rb_node; 4201da177e4SLinus Torvalds struct rb_node *parent = NULL; 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds /* add the VMA to the mapping */ 4231da177e4SLinus Torvalds if (vma->vm_file) { 4241da177e4SLinus Torvalds mapping = vma->vm_file->f_mapping; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds flush_dcache_mmap_lock(mapping); 4271da177e4SLinus Torvalds vma_prio_tree_insert(vma, &mapping->i_mmap); 4281da177e4SLinus Torvalds flush_dcache_mmap_unlock(mapping); 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds /* add the VMA to the master list */ 4321da177e4SLinus Torvalds while (*p) { 4331da177e4SLinus Torvalds parent = *p; 4341da177e4SLinus Torvalds pvma = rb_entry(parent, struct vm_area_struct, vm_rb); 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds if (vma->vm_start < pvma->vm_start) { 4371da177e4SLinus Torvalds p = &(*p)->rb_left; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds else if (vma->vm_start > pvma->vm_start) { 4401da177e4SLinus Torvalds p = &(*p)->rb_right; 4411da177e4SLinus Torvalds } 4421da177e4SLinus Torvalds else { 4431da177e4SLinus Torvalds /* mappings are at the same address - this can only 4441da177e4SLinus Torvalds * happen for shared-mem chardevs and shared file 4451da177e4SLinus Torvalds * mappings backed by ramfs/tmpfs */ 4461da177e4SLinus Torvalds BUG_ON(!(pvma->vm_flags & VM_SHARED)); 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds if (vma < pvma) 4491da177e4SLinus Torvalds p = &(*p)->rb_left; 4501da177e4SLinus Torvalds else if (vma > pvma) 4511da177e4SLinus Torvalds p = &(*p)->rb_right; 4521da177e4SLinus Torvalds else 4531da177e4SLinus Torvalds BUG(); 4541da177e4SLinus Torvalds } 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds rb_link_node(&vma->vm_rb, parent, p); 4581da177e4SLinus Torvalds rb_insert_color(&vma->vm_rb, &nommu_vma_tree); 4591da177e4SLinus Torvalds } 4601da177e4SLinus Torvalds 4613034097aSDavid Howells /* 4623034097aSDavid Howells * delete a VMA from the global list 4633034097aSDavid Howells */ 4641da177e4SLinus Torvalds static void delete_nommu_vma(struct vm_area_struct *vma) 4651da177e4SLinus Torvalds { 4661da177e4SLinus Torvalds struct address_space *mapping; 4671da177e4SLinus Torvalds 4681da177e4SLinus Torvalds /* remove the VMA from the mapping */ 4691da177e4SLinus Torvalds if (vma->vm_file) { 4701da177e4SLinus Torvalds mapping = vma->vm_file->f_mapping; 4711da177e4SLinus Torvalds 4721da177e4SLinus Torvalds flush_dcache_mmap_lock(mapping); 4731da177e4SLinus Torvalds vma_prio_tree_remove(vma, &mapping->i_mmap); 4741da177e4SLinus Torvalds flush_dcache_mmap_unlock(mapping); 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds /* remove from the master list */ 4781da177e4SLinus Torvalds rb_erase(&vma->vm_rb, &nommu_vma_tree); 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 4811da177e4SLinus Torvalds /* 4821da177e4SLinus Torvalds * determine whether a mapping should be permitted and, if so, what sort of 4831da177e4SLinus Torvalds * mapping we're capable of supporting 4841da177e4SLinus Torvalds */ 4851da177e4SLinus Torvalds static int validate_mmap_request(struct file *file, 4861da177e4SLinus Torvalds unsigned long addr, 4871da177e4SLinus Torvalds unsigned long len, 4881da177e4SLinus Torvalds unsigned long prot, 4891da177e4SLinus Torvalds unsigned long flags, 4901da177e4SLinus Torvalds unsigned long pgoff, 4911da177e4SLinus Torvalds unsigned long *_capabilities) 4921da177e4SLinus Torvalds { 4931da177e4SLinus Torvalds unsigned long capabilities; 4941da177e4SLinus Torvalds unsigned long reqprot = prot; 4951da177e4SLinus Torvalds int ret; 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds /* do the simple checks first */ 4981da177e4SLinus Torvalds if (flags & MAP_FIXED || addr) { 4991da177e4SLinus Torvalds printk(KERN_DEBUG 5001da177e4SLinus Torvalds "%d: Can't do fixed-address/overlay mmap of RAM\n", 5011da177e4SLinus Torvalds current->pid); 5021da177e4SLinus Torvalds return -EINVAL; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds if ((flags & MAP_TYPE) != MAP_PRIVATE && 5061da177e4SLinus Torvalds (flags & MAP_TYPE) != MAP_SHARED) 5071da177e4SLinus Torvalds return -EINVAL; 5081da177e4SLinus Torvalds 509f81cff0dSMike Frysinger if (!len) 5101da177e4SLinus Torvalds return -EINVAL; 5111da177e4SLinus Torvalds 512f81cff0dSMike Frysinger /* Careful about overflows.. */ 513f81cff0dSMike Frysinger len = PAGE_ALIGN(len); 514f81cff0dSMike Frysinger if (!len || len > TASK_SIZE) 515f81cff0dSMike Frysinger return -ENOMEM; 516f81cff0dSMike Frysinger 5171da177e4SLinus Torvalds /* offset overflow? */ 5181da177e4SLinus Torvalds if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) 519f81cff0dSMike Frysinger return -EOVERFLOW; 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds if (file) { 5221da177e4SLinus Torvalds /* validate file mapping requests */ 5231da177e4SLinus Torvalds struct address_space *mapping; 5241da177e4SLinus Torvalds 5251da177e4SLinus Torvalds /* files must support mmap */ 5261da177e4SLinus Torvalds if (!file->f_op || !file->f_op->mmap) 5271da177e4SLinus Torvalds return -ENODEV; 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds /* work out if what we've got could possibly be shared 5301da177e4SLinus Torvalds * - we support chardevs that provide their own "memory" 5311da177e4SLinus Torvalds * - we support files/blockdevs that are memory backed 5321da177e4SLinus Torvalds */ 5331da177e4SLinus Torvalds mapping = file->f_mapping; 5341da177e4SLinus Torvalds if (!mapping) 535e9536ae7SJosef Sipek mapping = file->f_path.dentry->d_inode->i_mapping; 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds capabilities = 0; 5381da177e4SLinus Torvalds if (mapping && mapping->backing_dev_info) 5391da177e4SLinus Torvalds capabilities = mapping->backing_dev_info->capabilities; 5401da177e4SLinus Torvalds 5411da177e4SLinus Torvalds if (!capabilities) { 5421da177e4SLinus Torvalds /* no explicit capabilities set, so assume some 5431da177e4SLinus Torvalds * defaults */ 544e9536ae7SJosef Sipek switch (file->f_path.dentry->d_inode->i_mode & S_IFMT) { 5451da177e4SLinus Torvalds case S_IFREG: 5461da177e4SLinus Torvalds case S_IFBLK: 5471da177e4SLinus Torvalds capabilities = BDI_CAP_MAP_COPY; 5481da177e4SLinus Torvalds break; 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds case S_IFCHR: 5511da177e4SLinus Torvalds capabilities = 5521da177e4SLinus Torvalds BDI_CAP_MAP_DIRECT | 5531da177e4SLinus Torvalds BDI_CAP_READ_MAP | 5541da177e4SLinus Torvalds BDI_CAP_WRITE_MAP; 5551da177e4SLinus Torvalds break; 5561da177e4SLinus Torvalds 5571da177e4SLinus Torvalds default: 5581da177e4SLinus Torvalds return -EINVAL; 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds } 5611da177e4SLinus Torvalds 5621da177e4SLinus Torvalds /* eliminate any capabilities that we can't support on this 5631da177e4SLinus Torvalds * device */ 5641da177e4SLinus Torvalds if (!file->f_op->get_unmapped_area) 5651da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 5661da177e4SLinus Torvalds if (!file->f_op->read) 5671da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_COPY; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds if (flags & MAP_SHARED) { 5701da177e4SLinus Torvalds /* do checks for writing, appending and locking */ 5711da177e4SLinus Torvalds if ((prot & PROT_WRITE) && 5721da177e4SLinus Torvalds !(file->f_mode & FMODE_WRITE)) 5731da177e4SLinus Torvalds return -EACCES; 5741da177e4SLinus Torvalds 575e9536ae7SJosef Sipek if (IS_APPEND(file->f_path.dentry->d_inode) && 5761da177e4SLinus Torvalds (file->f_mode & FMODE_WRITE)) 5771da177e4SLinus Torvalds return -EACCES; 5781da177e4SLinus Torvalds 579e9536ae7SJosef Sipek if (locks_verify_locked(file->f_path.dentry->d_inode)) 5801da177e4SLinus Torvalds return -EAGAIN; 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_DIRECT)) 5831da177e4SLinus Torvalds return -ENODEV; 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds if (((prot & PROT_READ) && !(capabilities & BDI_CAP_READ_MAP)) || 5861da177e4SLinus Torvalds ((prot & PROT_WRITE) && !(capabilities & BDI_CAP_WRITE_MAP)) || 5871da177e4SLinus Torvalds ((prot & PROT_EXEC) && !(capabilities & BDI_CAP_EXEC_MAP)) 5881da177e4SLinus Torvalds ) { 5891da177e4SLinus Torvalds printk("MAP_SHARED not completely supported on !MMU\n"); 5901da177e4SLinus Torvalds return -EINVAL; 5911da177e4SLinus Torvalds } 5921da177e4SLinus Torvalds 5931da177e4SLinus Torvalds /* we mustn't privatise shared mappings */ 5941da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_COPY; 5951da177e4SLinus Torvalds } 5961da177e4SLinus Torvalds else { 5971da177e4SLinus Torvalds /* we're going to read the file into private memory we 5981da177e4SLinus Torvalds * allocate */ 5991da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_COPY)) 6001da177e4SLinus Torvalds return -ENODEV; 6011da177e4SLinus Torvalds 6021da177e4SLinus Torvalds /* we don't permit a private writable mapping to be 6031da177e4SLinus Torvalds * shared with the backing device */ 6041da177e4SLinus Torvalds if (prot & PROT_WRITE) 6051da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds /* handle executable mappings and implied executable 6091da177e4SLinus Torvalds * mappings */ 610e9536ae7SJosef Sipek if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) { 6111da177e4SLinus Torvalds if (prot & PROT_EXEC) 6121da177e4SLinus Torvalds return -EPERM; 6131da177e4SLinus Torvalds } 6141da177e4SLinus Torvalds else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) { 6151da177e4SLinus Torvalds /* handle implication of PROT_EXEC by PROT_READ */ 6161da177e4SLinus Torvalds if (current->personality & READ_IMPLIES_EXEC) { 6171da177e4SLinus Torvalds if (capabilities & BDI_CAP_EXEC_MAP) 6181da177e4SLinus Torvalds prot |= PROT_EXEC; 6191da177e4SLinus Torvalds } 6201da177e4SLinus Torvalds } 6211da177e4SLinus Torvalds else if ((prot & PROT_READ) && 6221da177e4SLinus Torvalds (prot & PROT_EXEC) && 6231da177e4SLinus Torvalds !(capabilities & BDI_CAP_EXEC_MAP) 6241da177e4SLinus Torvalds ) { 6251da177e4SLinus Torvalds /* backing file is not executable, try to copy */ 6261da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds } 6291da177e4SLinus Torvalds else { 6301da177e4SLinus Torvalds /* anonymous mappings are always memory backed and can be 6311da177e4SLinus Torvalds * privately mapped 6321da177e4SLinus Torvalds */ 6331da177e4SLinus Torvalds capabilities = BDI_CAP_MAP_COPY; 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds /* handle PROT_EXEC implication by PROT_READ */ 6361da177e4SLinus Torvalds if ((prot & PROT_READ) && 6371da177e4SLinus Torvalds (current->personality & READ_IMPLIES_EXEC)) 6381da177e4SLinus Torvalds prot |= PROT_EXEC; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds 6411da177e4SLinus Torvalds /* allow the security API to have its say */ 6421da177e4SLinus Torvalds ret = security_file_mmap(file, reqprot, prot, flags); 6431da177e4SLinus Torvalds if (ret < 0) 6441da177e4SLinus Torvalds return ret; 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds /* looks okay */ 6471da177e4SLinus Torvalds *_capabilities = capabilities; 6481da177e4SLinus Torvalds return 0; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds /* 6521da177e4SLinus Torvalds * we've determined that we can make the mapping, now translate what we 6531da177e4SLinus Torvalds * now know into VMA flags 6541da177e4SLinus Torvalds */ 6551da177e4SLinus Torvalds static unsigned long determine_vm_flags(struct file *file, 6561da177e4SLinus Torvalds unsigned long prot, 6571da177e4SLinus Torvalds unsigned long flags, 6581da177e4SLinus Torvalds unsigned long capabilities) 6591da177e4SLinus Torvalds { 6601da177e4SLinus Torvalds unsigned long vm_flags; 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags); 6631da177e4SLinus Torvalds vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; 6641da177e4SLinus Torvalds /* vm_flags |= mm->def_flags; */ 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_DIRECT)) { 6671da177e4SLinus Torvalds /* attempt to share read-only copies of mapped file chunks */ 6681da177e4SLinus Torvalds if (file && !(prot & PROT_WRITE)) 6691da177e4SLinus Torvalds vm_flags |= VM_MAYSHARE; 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds else { 6721da177e4SLinus Torvalds /* overlay a shareable mapping on the backing device or inode 6731da177e4SLinus Torvalds * if possible - used for chardevs, ramfs/tmpfs/shmfs and 6741da177e4SLinus Torvalds * romfs/cramfs */ 6751da177e4SLinus Torvalds if (flags & MAP_SHARED) 6761da177e4SLinus Torvalds vm_flags |= VM_MAYSHARE | VM_SHARED; 6771da177e4SLinus Torvalds else if ((((vm_flags & capabilities) ^ vm_flags) & BDI_CAP_VMFLAGS) == 0) 6781da177e4SLinus Torvalds vm_flags |= VM_MAYSHARE; 6791da177e4SLinus Torvalds } 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds /* refuse to let anyone share private mappings with this process if 6821da177e4SLinus Torvalds * it's being traced - otherwise breakpoints set in it may interfere 6831da177e4SLinus Torvalds * with another untraced process 6841da177e4SLinus Torvalds */ 6851da177e4SLinus Torvalds if ((flags & MAP_PRIVATE) && (current->ptrace & PT_PTRACED)) 6861da177e4SLinus Torvalds vm_flags &= ~VM_MAYSHARE; 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds return vm_flags; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds /* 6921da177e4SLinus Torvalds * set up a shared mapping on a file 6931da177e4SLinus Torvalds */ 6941da177e4SLinus Torvalds static int do_mmap_shared_file(struct vm_area_struct *vma, unsigned long len) 6951da177e4SLinus Torvalds { 6961da177e4SLinus Torvalds int ret; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); 6991da177e4SLinus Torvalds if (ret != -ENOSYS) 7001da177e4SLinus Torvalds return ret; 7011da177e4SLinus Torvalds 7021da177e4SLinus Torvalds /* getting an ENOSYS error indicates that direct mmap isn't 7031da177e4SLinus Torvalds * possible (as opposed to tried but failed) so we'll fall 7041da177e4SLinus Torvalds * through to making a private copy of the data and mapping 7051da177e4SLinus Torvalds * that if we can */ 7061da177e4SLinus Torvalds return -ENODEV; 7071da177e4SLinus Torvalds } 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds /* 7101da177e4SLinus Torvalds * set up a private mapping or an anonymous shared mapping 7111da177e4SLinus Torvalds */ 7121da177e4SLinus Torvalds static int do_mmap_private(struct vm_area_struct *vma, unsigned long len) 7131da177e4SLinus Torvalds { 7141da177e4SLinus Torvalds void *base; 7151da177e4SLinus Torvalds int ret; 7161da177e4SLinus Torvalds 7171da177e4SLinus Torvalds /* invoke the file's mapping function so that it can keep track of 7181da177e4SLinus Torvalds * shared mappings on devices or memory 7191da177e4SLinus Torvalds * - VM_MAYSHARE will be set if it may attempt to share 7201da177e4SLinus Torvalds */ 7211da177e4SLinus Torvalds if (vma->vm_file) { 7221da177e4SLinus Torvalds ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); 7231da177e4SLinus Torvalds if (ret != -ENOSYS) { 7241da177e4SLinus Torvalds /* shouldn't return success if we're not sharing */ 7251da177e4SLinus Torvalds BUG_ON(ret == 0 && !(vma->vm_flags & VM_MAYSHARE)); 7261da177e4SLinus Torvalds return ret; /* success or a real error */ 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds 7291da177e4SLinus Torvalds /* getting an ENOSYS error indicates that direct mmap isn't 7301da177e4SLinus Torvalds * possible (as opposed to tried but failed) so we'll try to 7311da177e4SLinus Torvalds * make a private copy of the data and map that instead */ 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds /* allocate some memory to hold the mapping 7351da177e4SLinus Torvalds * - note that this may not return a page-aligned address if the object 7361da177e4SLinus Torvalds * we're allocating is smaller than a page 7371da177e4SLinus Torvalds */ 73884097518SNick Piggin base = kmalloc(len, GFP_KERNEL|__GFP_COMP); 7391da177e4SLinus Torvalds if (!base) 7401da177e4SLinus Torvalds goto enomem; 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds vma->vm_start = (unsigned long) base; 7431da177e4SLinus Torvalds vma->vm_end = vma->vm_start + len; 7441da177e4SLinus Torvalds vma->vm_flags |= VM_MAPPED_COPY; 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds #ifdef WARN_ON_SLACK 7471da177e4SLinus Torvalds if (len + WARN_ON_SLACK <= kobjsize(result)) 7481da177e4SLinus Torvalds printk("Allocation of %lu bytes from process %d has %lu bytes of slack\n", 7491da177e4SLinus Torvalds len, current->pid, kobjsize(result) - len); 7501da177e4SLinus Torvalds #endif 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds if (vma->vm_file) { 7531da177e4SLinus Torvalds /* read the contents of a file into the copy */ 7541da177e4SLinus Torvalds mm_segment_t old_fs; 7551da177e4SLinus Torvalds loff_t fpos; 7561da177e4SLinus Torvalds 7571da177e4SLinus Torvalds fpos = vma->vm_pgoff; 7581da177e4SLinus Torvalds fpos <<= PAGE_SHIFT; 7591da177e4SLinus Torvalds 7601da177e4SLinus Torvalds old_fs = get_fs(); 7611da177e4SLinus Torvalds set_fs(KERNEL_DS); 7621da177e4SLinus Torvalds ret = vma->vm_file->f_op->read(vma->vm_file, base, len, &fpos); 7631da177e4SLinus Torvalds set_fs(old_fs); 7641da177e4SLinus Torvalds 7651da177e4SLinus Torvalds if (ret < 0) 7661da177e4SLinus Torvalds goto error_free; 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds /* clear the last little bit */ 7691da177e4SLinus Torvalds if (ret < len) 7701da177e4SLinus Torvalds memset(base + ret, 0, len - ret); 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds } else { 7731da177e4SLinus Torvalds /* if it's an anonymous mapping, then just clear it */ 7741da177e4SLinus Torvalds memset(base, 0, len); 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds return 0; 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds error_free: 7801da177e4SLinus Torvalds kfree(base); 7811da177e4SLinus Torvalds vma->vm_start = 0; 7821da177e4SLinus Torvalds return ret; 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds enomem: 7851da177e4SLinus Torvalds printk("Allocation of length %lu from process %d failed\n", 7861da177e4SLinus Torvalds len, current->pid); 7871da177e4SLinus Torvalds show_free_areas(); 7881da177e4SLinus Torvalds return -ENOMEM; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds /* 7921da177e4SLinus Torvalds * handle mapping creation for uClinux 7931da177e4SLinus Torvalds */ 7941da177e4SLinus Torvalds unsigned long do_mmap_pgoff(struct file *file, 7951da177e4SLinus Torvalds unsigned long addr, 7961da177e4SLinus Torvalds unsigned long len, 7971da177e4SLinus Torvalds unsigned long prot, 7981da177e4SLinus Torvalds unsigned long flags, 7991da177e4SLinus Torvalds unsigned long pgoff) 8001da177e4SLinus Torvalds { 8011da177e4SLinus Torvalds struct vm_list_struct *vml = NULL; 8021da177e4SLinus Torvalds struct vm_area_struct *vma = NULL; 8031da177e4SLinus Torvalds struct rb_node *rb; 8041da177e4SLinus Torvalds unsigned long capabilities, vm_flags; 8051da177e4SLinus Torvalds void *result; 8061da177e4SLinus Torvalds int ret; 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds /* decide whether we should attempt the mapping, and if so what sort of 8091da177e4SLinus Torvalds * mapping */ 8101da177e4SLinus Torvalds ret = validate_mmap_request(file, addr, len, prot, flags, pgoff, 8111da177e4SLinus Torvalds &capabilities); 8121da177e4SLinus Torvalds if (ret < 0) 8131da177e4SLinus Torvalds return ret; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds /* we've determined that we can make the mapping, now translate what we 8161da177e4SLinus Torvalds * now know into VMA flags */ 8171da177e4SLinus Torvalds vm_flags = determine_vm_flags(file, prot, flags, capabilities); 8181da177e4SLinus Torvalds 8191da177e4SLinus Torvalds /* we're going to need to record the mapping if it works */ 8204668edc3SBurman Yan vml = kzalloc(sizeof(struct vm_list_struct), GFP_KERNEL); 8211da177e4SLinus Torvalds if (!vml) 8221da177e4SLinus Torvalds goto error_getting_vml; 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds down_write(&nommu_vma_sem); 8251da177e4SLinus Torvalds 8261da177e4SLinus Torvalds /* if we want to share, we need to check for VMAs created by other 8271da177e4SLinus Torvalds * mmap() calls that overlap with our proposed mapping 8281da177e4SLinus Torvalds * - we can only share with an exact match on most regular files 8291da177e4SLinus Torvalds * - shared mappings on character devices and memory backed files are 8301da177e4SLinus Torvalds * permitted to overlap inexactly as far as we are concerned for in 8311da177e4SLinus Torvalds * these cases, sharing is handled in the driver or filesystem rather 8321da177e4SLinus Torvalds * than here 8331da177e4SLinus Torvalds */ 8341da177e4SLinus Torvalds if (vm_flags & VM_MAYSHARE) { 8351da177e4SLinus Torvalds unsigned long pglen = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 8361da177e4SLinus Torvalds unsigned long vmpglen; 8371da177e4SLinus Torvalds 838165b2392SDavid Howells /* suppress VMA sharing for shared regions */ 839165b2392SDavid Howells if (vm_flags & VM_SHARED && 840165b2392SDavid Howells capabilities & BDI_CAP_MAP_DIRECT) 841165b2392SDavid Howells goto dont_share_VMAs; 842165b2392SDavid Howells 8431da177e4SLinus Torvalds for (rb = rb_first(&nommu_vma_tree); rb; rb = rb_next(rb)) { 8441da177e4SLinus Torvalds vma = rb_entry(rb, struct vm_area_struct, vm_rb); 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds if (!(vma->vm_flags & VM_MAYSHARE)) 8471da177e4SLinus Torvalds continue; 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds /* search for overlapping mappings on the same file */ 850e9536ae7SJosef Sipek if (vma->vm_file->f_path.dentry->d_inode != file->f_path.dentry->d_inode) 8511da177e4SLinus Torvalds continue; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds if (vma->vm_pgoff >= pgoff + pglen) 8541da177e4SLinus Torvalds continue; 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds vmpglen = vma->vm_end - vma->vm_start + PAGE_SIZE - 1; 8571da177e4SLinus Torvalds vmpglen >>= PAGE_SHIFT; 8581da177e4SLinus Torvalds if (pgoff >= vma->vm_pgoff + vmpglen) 8591da177e4SLinus Torvalds continue; 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds /* handle inexactly overlapping matches between mappings */ 8621da177e4SLinus Torvalds if (vma->vm_pgoff != pgoff || vmpglen != pglen) { 8631da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_DIRECT)) 8641da177e4SLinus Torvalds goto sharing_violation; 8651da177e4SLinus Torvalds continue; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds /* we've found a VMA we can share */ 8691da177e4SLinus Torvalds atomic_inc(&vma->vm_usage); 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds vml->vma = vma; 8721da177e4SLinus Torvalds result = (void *) vma->vm_start; 8731da177e4SLinus Torvalds goto shared; 8741da177e4SLinus Torvalds } 8751da177e4SLinus Torvalds 876165b2392SDavid Howells dont_share_VMAs: 8771da177e4SLinus Torvalds vma = NULL; 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds /* obtain the address at which to make a shared mapping 8801da177e4SLinus Torvalds * - this is the hook for quasi-memory character devices to 8811da177e4SLinus Torvalds * tell us the location of a shared mapping 8821da177e4SLinus Torvalds */ 8831da177e4SLinus Torvalds if (file && file->f_op->get_unmapped_area) { 8841da177e4SLinus Torvalds addr = file->f_op->get_unmapped_area(file, addr, len, 8851da177e4SLinus Torvalds pgoff, flags); 8861da177e4SLinus Torvalds if (IS_ERR((void *) addr)) { 8871da177e4SLinus Torvalds ret = addr; 8881da177e4SLinus Torvalds if (ret != (unsigned long) -ENOSYS) 8891da177e4SLinus Torvalds goto error; 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds /* the driver refused to tell us where to site 8921da177e4SLinus Torvalds * the mapping so we'll have to attempt to copy 8931da177e4SLinus Torvalds * it */ 8941da177e4SLinus Torvalds ret = (unsigned long) -ENODEV; 8951da177e4SLinus Torvalds if (!(capabilities & BDI_CAP_MAP_COPY)) 8961da177e4SLinus Torvalds goto error; 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds capabilities &= ~BDI_CAP_MAP_DIRECT; 8991da177e4SLinus Torvalds } 9001da177e4SLinus Torvalds } 9011da177e4SLinus Torvalds } 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds /* we're going to need a VMA struct as well */ 9044668edc3SBurman Yan vma = kzalloc(sizeof(struct vm_area_struct), GFP_KERNEL); 9051da177e4SLinus Torvalds if (!vma) 9061da177e4SLinus Torvalds goto error_getting_vma; 9071da177e4SLinus Torvalds 9081da177e4SLinus Torvalds INIT_LIST_HEAD(&vma->anon_vma_node); 9091da177e4SLinus Torvalds atomic_set(&vma->vm_usage, 1); 9101da177e4SLinus Torvalds if (file) 9111da177e4SLinus Torvalds get_file(file); 9121da177e4SLinus Torvalds vma->vm_file = file; 9131da177e4SLinus Torvalds vma->vm_flags = vm_flags; 9141da177e4SLinus Torvalds vma->vm_start = addr; 9151da177e4SLinus Torvalds vma->vm_end = addr + len; 9161da177e4SLinus Torvalds vma->vm_pgoff = pgoff; 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds vml->vma = vma; 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds /* set up the mapping */ 9211da177e4SLinus Torvalds if (file && vma->vm_flags & VM_SHARED) 9221da177e4SLinus Torvalds ret = do_mmap_shared_file(vma, len); 9231da177e4SLinus Torvalds else 9241da177e4SLinus Torvalds ret = do_mmap_private(vma, len); 9251da177e4SLinus Torvalds if (ret < 0) 9261da177e4SLinus Torvalds goto error; 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds /* okay... we have a mapping; now we have to register it */ 9291da177e4SLinus Torvalds result = (void *) vma->vm_start; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds if (vma->vm_flags & VM_MAPPED_COPY) { 9321da177e4SLinus Torvalds realalloc += kobjsize(result); 9331da177e4SLinus Torvalds askedalloc += len; 9341da177e4SLinus Torvalds } 9351da177e4SLinus Torvalds 9361da177e4SLinus Torvalds realalloc += kobjsize(vma); 9371da177e4SLinus Torvalds askedalloc += sizeof(*vma); 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds current->mm->total_vm += len >> PAGE_SHIFT; 9401da177e4SLinus Torvalds 9411da177e4SLinus Torvalds add_nommu_vma(vma); 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds shared: 9441da177e4SLinus Torvalds realalloc += kobjsize(vml); 9451da177e4SLinus Torvalds askedalloc += sizeof(*vml); 9461da177e4SLinus Torvalds 9473034097aSDavid Howells add_vma_to_mm(current->mm, vml); 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds up_write(&nommu_vma_sem); 9501da177e4SLinus Torvalds 9511da177e4SLinus Torvalds if (prot & PROT_EXEC) 9521da177e4SLinus Torvalds flush_icache_range((unsigned long) result, 9531da177e4SLinus Torvalds (unsigned long) result + len); 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds #ifdef DEBUG 9561da177e4SLinus Torvalds printk("do_mmap:\n"); 9571da177e4SLinus Torvalds show_process_blocks(); 9581da177e4SLinus Torvalds #endif 9591da177e4SLinus Torvalds 9601da177e4SLinus Torvalds return (unsigned long) result; 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds error: 9631da177e4SLinus Torvalds up_write(&nommu_vma_sem); 9641da177e4SLinus Torvalds kfree(vml); 9651da177e4SLinus Torvalds if (vma) { 9663fcd03e0SGavin Lambert if (vma->vm_file) 9671da177e4SLinus Torvalds fput(vma->vm_file); 9681da177e4SLinus Torvalds kfree(vma); 9691da177e4SLinus Torvalds } 9701da177e4SLinus Torvalds return ret; 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds sharing_violation: 9731da177e4SLinus Torvalds up_write(&nommu_vma_sem); 9741da177e4SLinus Torvalds printk("Attempt to share mismatched mappings\n"); 9751da177e4SLinus Torvalds kfree(vml); 9761da177e4SLinus Torvalds return -EINVAL; 9771da177e4SLinus Torvalds 9781da177e4SLinus Torvalds error_getting_vma: 9791da177e4SLinus Torvalds up_write(&nommu_vma_sem); 9801da177e4SLinus Torvalds kfree(vml); 98166aa2b4bSGreg Ungerer printk("Allocation of vma for %lu byte allocation from process %d failed\n", 9821da177e4SLinus Torvalds len, current->pid); 9831da177e4SLinus Torvalds show_free_areas(); 9841da177e4SLinus Torvalds return -ENOMEM; 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds error_getting_vml: 9871da177e4SLinus Torvalds printk("Allocation of vml for %lu byte allocation from process %d failed\n", 9881da177e4SLinus Torvalds len, current->pid); 9891da177e4SLinus Torvalds show_free_areas(); 9901da177e4SLinus Torvalds return -ENOMEM; 9911da177e4SLinus Torvalds } 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds /* 9941da177e4SLinus Torvalds * handle mapping disposal for uClinux 9951da177e4SLinus Torvalds */ 9961da177e4SLinus Torvalds static void put_vma(struct vm_area_struct *vma) 9971da177e4SLinus Torvalds { 9981da177e4SLinus Torvalds if (vma) { 9991da177e4SLinus Torvalds down_write(&nommu_vma_sem); 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds if (atomic_dec_and_test(&vma->vm_usage)) { 10021da177e4SLinus Torvalds delete_nommu_vma(vma); 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds if (vma->vm_ops && vma->vm_ops->close) 10051da177e4SLinus Torvalds vma->vm_ops->close(vma); 10061da177e4SLinus Torvalds 10071da177e4SLinus Torvalds /* IO memory and memory shared directly out of the pagecache from 10081da177e4SLinus Torvalds * ramfs/tmpfs mustn't be released here */ 10091da177e4SLinus Torvalds if (vma->vm_flags & VM_MAPPED_COPY) { 10101da177e4SLinus Torvalds realalloc -= kobjsize((void *) vma->vm_start); 10111da177e4SLinus Torvalds askedalloc -= vma->vm_end - vma->vm_start; 10121da177e4SLinus Torvalds kfree((void *) vma->vm_start); 10131da177e4SLinus Torvalds } 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds realalloc -= kobjsize(vma); 10161da177e4SLinus Torvalds askedalloc -= sizeof(*vma); 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds if (vma->vm_file) 10191da177e4SLinus Torvalds fput(vma->vm_file); 10201da177e4SLinus Torvalds kfree(vma); 10211da177e4SLinus Torvalds } 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds up_write(&nommu_vma_sem); 10241da177e4SLinus Torvalds } 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 10273034097aSDavid Howells /* 10283034097aSDavid Howells * release a mapping 10293034097aSDavid Howells * - under NOMMU conditions the parameters must match exactly to the mapping to 10303034097aSDavid Howells * be removed 10313034097aSDavid Howells */ 10321da177e4SLinus Torvalds int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) 10331da177e4SLinus Torvalds { 10341da177e4SLinus Torvalds struct vm_list_struct *vml, **parent; 10351da177e4SLinus Torvalds unsigned long end = addr + len; 10361da177e4SLinus Torvalds 10371da177e4SLinus Torvalds #ifdef DEBUG 10381da177e4SLinus Torvalds printk("do_munmap:\n"); 10391da177e4SLinus Torvalds #endif 10401da177e4SLinus Torvalds 10413034097aSDavid Howells for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) { 10423034097aSDavid Howells if ((*parent)->vma->vm_start > addr) 10433034097aSDavid Howells break; 10441da177e4SLinus Torvalds if ((*parent)->vma->vm_start == addr && 104566aa2b4bSGreg Ungerer ((len == 0) || ((*parent)->vma->vm_end == end))) 10461da177e4SLinus Torvalds goto found; 10473034097aSDavid Howells } 10481da177e4SLinus Torvalds 10491da177e4SLinus Torvalds printk("munmap of non-mmaped memory by process %d (%s): %p\n", 10501da177e4SLinus Torvalds current->pid, current->comm, (void *) addr); 10511da177e4SLinus Torvalds return -EINVAL; 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds found: 10541da177e4SLinus Torvalds vml = *parent; 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds put_vma(vml->vma); 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds *parent = vml->next; 10591da177e4SLinus Torvalds realalloc -= kobjsize(vml); 10601da177e4SLinus Torvalds askedalloc -= sizeof(*vml); 10611da177e4SLinus Torvalds kfree(vml); 1062365e9c87SHugh Dickins 1063365e9c87SHugh Dickins update_hiwater_vm(mm); 10641da177e4SLinus Torvalds mm->total_vm -= len >> PAGE_SHIFT; 10651da177e4SLinus Torvalds 10661da177e4SLinus Torvalds #ifdef DEBUG 10671da177e4SLinus Torvalds show_process_blocks(); 10681da177e4SLinus Torvalds #endif 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds return 0; 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds 10733034097aSDavid Howells asmlinkage long sys_munmap(unsigned long addr, size_t len) 10743034097aSDavid Howells { 10753034097aSDavid Howells int ret; 10763034097aSDavid Howells struct mm_struct *mm = current->mm; 10773034097aSDavid Howells 10783034097aSDavid Howells down_write(&mm->mmap_sem); 10793034097aSDavid Howells ret = do_munmap(mm, addr, len); 10803034097aSDavid Howells up_write(&mm->mmap_sem); 10813034097aSDavid Howells return ret; 10823034097aSDavid Howells } 10833034097aSDavid Howells 10843034097aSDavid Howells /* 10853034097aSDavid Howells * Release all mappings 10863034097aSDavid Howells */ 10871da177e4SLinus Torvalds void exit_mmap(struct mm_struct * mm) 10881da177e4SLinus Torvalds { 10891da177e4SLinus Torvalds struct vm_list_struct *tmp; 10901da177e4SLinus Torvalds 10911da177e4SLinus Torvalds if (mm) { 10921da177e4SLinus Torvalds #ifdef DEBUG 10931da177e4SLinus Torvalds printk("Exit_mmap:\n"); 10941da177e4SLinus Torvalds #endif 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds mm->total_vm = 0; 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds while ((tmp = mm->context.vmlist)) { 10991da177e4SLinus Torvalds mm->context.vmlist = tmp->next; 11001da177e4SLinus Torvalds put_vma(tmp->vma); 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds realalloc -= kobjsize(tmp); 11031da177e4SLinus Torvalds askedalloc -= sizeof(*tmp); 11041da177e4SLinus Torvalds kfree(tmp); 11051da177e4SLinus Torvalds } 11061da177e4SLinus Torvalds 11071da177e4SLinus Torvalds #ifdef DEBUG 11081da177e4SLinus Torvalds show_process_blocks(); 11091da177e4SLinus Torvalds #endif 11101da177e4SLinus Torvalds } 11111da177e4SLinus Torvalds } 11121da177e4SLinus Torvalds 11131da177e4SLinus Torvalds unsigned long do_brk(unsigned long addr, unsigned long len) 11141da177e4SLinus Torvalds { 11151da177e4SLinus Torvalds return -ENOMEM; 11161da177e4SLinus Torvalds } 11171da177e4SLinus Torvalds 11181da177e4SLinus Torvalds /* 11196fa5f80bSDavid Howells * expand (or shrink) an existing mapping, potentially moving it at the same 11206fa5f80bSDavid Howells * time (controlled by the MREMAP_MAYMOVE flag and available VM space) 11211da177e4SLinus Torvalds * 11226fa5f80bSDavid Howells * under NOMMU conditions, we only permit changing a mapping's size, and only 11236fa5f80bSDavid Howells * as long as it stays within the hole allocated by the kmalloc() call in 11246fa5f80bSDavid Howells * do_mmap_pgoff() and the block is not shareable 11251da177e4SLinus Torvalds * 11266fa5f80bSDavid Howells * MREMAP_FIXED is not supported under NOMMU conditions 11271da177e4SLinus Torvalds */ 11281da177e4SLinus Torvalds unsigned long do_mremap(unsigned long addr, 11291da177e4SLinus Torvalds unsigned long old_len, unsigned long new_len, 11301da177e4SLinus Torvalds unsigned long flags, unsigned long new_addr) 11311da177e4SLinus Torvalds { 11326fa5f80bSDavid Howells struct vm_area_struct *vma; 11331da177e4SLinus Torvalds 11341da177e4SLinus Torvalds /* insanity checks first */ 11351da177e4SLinus Torvalds if (new_len == 0) 11361da177e4SLinus Torvalds return (unsigned long) -EINVAL; 11371da177e4SLinus Torvalds 11381da177e4SLinus Torvalds if (flags & MREMAP_FIXED && new_addr != addr) 11391da177e4SLinus Torvalds return (unsigned long) -EINVAL; 11401da177e4SLinus Torvalds 11416fa5f80bSDavid Howells vma = find_vma_exact(current->mm, addr); 11426fa5f80bSDavid Howells if (!vma) 11431da177e4SLinus Torvalds return (unsigned long) -EINVAL; 11441da177e4SLinus Torvalds 11456fa5f80bSDavid Howells if (vma->vm_end != vma->vm_start + old_len) 11461da177e4SLinus Torvalds return (unsigned long) -EFAULT; 11471da177e4SLinus Torvalds 11486fa5f80bSDavid Howells if (vma->vm_flags & VM_MAYSHARE) 11491da177e4SLinus Torvalds return (unsigned long) -EPERM; 11501da177e4SLinus Torvalds 11511da177e4SLinus Torvalds if (new_len > kobjsize((void *) addr)) 11521da177e4SLinus Torvalds return (unsigned long) -ENOMEM; 11531da177e4SLinus Torvalds 11541da177e4SLinus Torvalds /* all checks complete - do it */ 11556fa5f80bSDavid Howells vma->vm_end = vma->vm_start + new_len; 11561da177e4SLinus Torvalds 11571da177e4SLinus Torvalds askedalloc -= old_len; 11581da177e4SLinus Torvalds askedalloc += new_len; 11591da177e4SLinus Torvalds 11606fa5f80bSDavid Howells return vma->vm_start; 11616fa5f80bSDavid Howells } 11626fa5f80bSDavid Howells 11636fa5f80bSDavid Howells asmlinkage unsigned long sys_mremap(unsigned long addr, 11646fa5f80bSDavid Howells unsigned long old_len, unsigned long new_len, 11656fa5f80bSDavid Howells unsigned long flags, unsigned long new_addr) 11666fa5f80bSDavid Howells { 11676fa5f80bSDavid Howells unsigned long ret; 11686fa5f80bSDavid Howells 11696fa5f80bSDavid Howells down_write(¤t->mm->mmap_sem); 11706fa5f80bSDavid Howells ret = do_mremap(addr, old_len, new_len, flags, new_addr); 11716fa5f80bSDavid Howells up_write(¤t->mm->mmap_sem); 11726fa5f80bSDavid Howells return ret; 11731da177e4SLinus Torvalds } 11741da177e4SLinus Torvalds 11756aab341eSLinus Torvalds struct page *follow_page(struct vm_area_struct *vma, unsigned long address, 1176deceb6cdSHugh Dickins unsigned int foll_flags) 11771da177e4SLinus Torvalds { 11781da177e4SLinus Torvalds return NULL; 11791da177e4SLinus Torvalds } 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, 11821da177e4SLinus Torvalds unsigned long to, unsigned long size, pgprot_t prot) 11831da177e4SLinus Torvalds { 118466aa2b4bSGreg Ungerer vma->vm_start = vma->vm_pgoff << PAGE_SHIFT; 118566aa2b4bSGreg Ungerer return 0; 11861da177e4SLinus Torvalds } 118722c4af40SLuke Yang EXPORT_SYMBOL(remap_pfn_range); 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page) 11901da177e4SLinus Torvalds { 11911da177e4SLinus Torvalds } 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds unsigned long arch_get_unmapped_area(struct file *file, unsigned long addr, 11941da177e4SLinus Torvalds unsigned long len, unsigned long pgoff, unsigned long flags) 11951da177e4SLinus Torvalds { 11961da177e4SLinus Torvalds return -ENOMEM; 11971da177e4SLinus Torvalds } 11981da177e4SLinus Torvalds 11991363c3cdSWolfgang Wander void arch_unmap_area(struct mm_struct *mm, unsigned long addr) 12001da177e4SLinus Torvalds { 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds void unmap_mapping_range(struct address_space *mapping, 12041da177e4SLinus Torvalds loff_t const holebegin, loff_t const holelen, 12051da177e4SLinus Torvalds int even_cows) 12061da177e4SLinus Torvalds { 12071da177e4SLinus Torvalds } 120822c4af40SLuke Yang EXPORT_SYMBOL(unmap_mapping_range); 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds /* 1211d56e03cdSDavid Howells * ask for an unmapped area at which to create a mapping on a file 1212d56e03cdSDavid Howells */ 1213d56e03cdSDavid Howells unsigned long get_unmapped_area(struct file *file, unsigned long addr, 1214d56e03cdSDavid Howells unsigned long len, unsigned long pgoff, 1215d56e03cdSDavid Howells unsigned long flags) 1216d56e03cdSDavid Howells { 1217d56e03cdSDavid Howells unsigned long (*get_area)(struct file *, unsigned long, unsigned long, 1218d56e03cdSDavid Howells unsigned long, unsigned long); 1219d56e03cdSDavid Howells 1220d56e03cdSDavid Howells get_area = current->mm->get_unmapped_area; 1221d56e03cdSDavid Howells if (file && file->f_op && file->f_op->get_unmapped_area) 1222d56e03cdSDavid Howells get_area = file->f_op->get_unmapped_area; 1223d56e03cdSDavid Howells 1224d56e03cdSDavid Howells if (!get_area) 1225d56e03cdSDavid Howells return -ENOSYS; 1226d56e03cdSDavid Howells 1227d56e03cdSDavid Howells return get_area(file, addr, len, pgoff, flags); 1228d56e03cdSDavid Howells } 1229d56e03cdSDavid Howells 1230d56e03cdSDavid Howells EXPORT_SYMBOL(get_unmapped_area); 1231d56e03cdSDavid Howells 1232d56e03cdSDavid Howells /* 12331da177e4SLinus Torvalds * Check that a process has enough memory to allocate a new virtual 12341da177e4SLinus Torvalds * mapping. 0 means there is enough memory for the allocation to 12351da177e4SLinus Torvalds * succeed and -ENOMEM implies there is not. 12361da177e4SLinus Torvalds * 12371da177e4SLinus Torvalds * We currently support three overcommit policies, which are set via the 12381da177e4SLinus Torvalds * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting 12391da177e4SLinus Torvalds * 12401da177e4SLinus Torvalds * Strict overcommit modes added 2002 Feb 26 by Alan Cox. 12411da177e4SLinus Torvalds * Additional code 2002 Jul 20 by Robert Love. 12421da177e4SLinus Torvalds * 12431da177e4SLinus Torvalds * cap_sys_admin is 1 if the process has admin privileges, 0 otherwise. 12441da177e4SLinus Torvalds * 12451da177e4SLinus Torvalds * Note this is a helper function intended to be used by LSMs which 12461da177e4SLinus Torvalds * wish to use this logic. 12471da177e4SLinus Torvalds */ 12481da177e4SLinus Torvalds int __vm_enough_memory(long pages, int cap_sys_admin) 12491da177e4SLinus Torvalds { 12501da177e4SLinus Torvalds unsigned long free, allowed; 12511da177e4SLinus Torvalds 12521da177e4SLinus Torvalds vm_acct_memory(pages); 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds /* 12551da177e4SLinus Torvalds * Sometimes we want to use more memory than we have 12561da177e4SLinus Torvalds */ 12571da177e4SLinus Torvalds if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) 12581da177e4SLinus Torvalds return 0; 12591da177e4SLinus Torvalds 12601da177e4SLinus Torvalds if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { 12611da177e4SLinus Torvalds unsigned long n; 12621da177e4SLinus Torvalds 1263347ce434SChristoph Lameter free = global_page_state(NR_FILE_PAGES); 12641da177e4SLinus Torvalds free += nr_swap_pages; 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds /* 12671da177e4SLinus Torvalds * Any slabs which are created with the 12681da177e4SLinus Torvalds * SLAB_RECLAIM_ACCOUNT flag claim to have contents 12691da177e4SLinus Torvalds * which are reclaimable, under pressure. The dentry 12701da177e4SLinus Torvalds * cache and most inode caches should fall into this 12711da177e4SLinus Torvalds */ 1272972d1a7bSChristoph Lameter free += global_page_state(NR_SLAB_RECLAIMABLE); 12731da177e4SLinus Torvalds 12741da177e4SLinus Torvalds /* 12751da177e4SLinus Torvalds * Leave the last 3% for root 12761da177e4SLinus Torvalds */ 12771da177e4SLinus Torvalds if (!cap_sys_admin) 12781da177e4SLinus Torvalds free -= free / 32; 12791da177e4SLinus Torvalds 12801da177e4SLinus Torvalds if (free > pages) 12811da177e4SLinus Torvalds return 0; 12821da177e4SLinus Torvalds 12831da177e4SLinus Torvalds /* 12841da177e4SLinus Torvalds * nr_free_pages() is very expensive on large systems, 12851da177e4SLinus Torvalds * only call if we're about to fail. 12861da177e4SLinus Torvalds */ 12871da177e4SLinus Torvalds n = nr_free_pages(); 1288d5ddc79bSHideo AOKI 1289d5ddc79bSHideo AOKI /* 1290d5ddc79bSHideo AOKI * Leave reserved pages. The pages are not for anonymous pages. 1291d5ddc79bSHideo AOKI */ 1292d5ddc79bSHideo AOKI if (n <= totalreserve_pages) 1293d5ddc79bSHideo AOKI goto error; 1294d5ddc79bSHideo AOKI else 1295d5ddc79bSHideo AOKI n -= totalreserve_pages; 1296d5ddc79bSHideo AOKI 1297d5ddc79bSHideo AOKI /* 1298d5ddc79bSHideo AOKI * Leave the last 3% for root 1299d5ddc79bSHideo AOKI */ 13001da177e4SLinus Torvalds if (!cap_sys_admin) 13011da177e4SLinus Torvalds n -= n / 32; 13021da177e4SLinus Torvalds free += n; 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds if (free > pages) 13051da177e4SLinus Torvalds return 0; 1306d5ddc79bSHideo AOKI 1307d5ddc79bSHideo AOKI goto error; 13081da177e4SLinus Torvalds } 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds allowed = totalram_pages * sysctl_overcommit_ratio / 100; 13111da177e4SLinus Torvalds /* 13121da177e4SLinus Torvalds * Leave the last 3% for root 13131da177e4SLinus Torvalds */ 13141da177e4SLinus Torvalds if (!cap_sys_admin) 13151da177e4SLinus Torvalds allowed -= allowed / 32; 13161da177e4SLinus Torvalds allowed += total_swap_pages; 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds /* Don't let a single process grow too big: 13191da177e4SLinus Torvalds leave 3% of the size of this process for other processes */ 13201da177e4SLinus Torvalds allowed -= current->mm->total_vm / 32; 13211da177e4SLinus Torvalds 13222f60f8d3SSimon Derr /* 13232f60f8d3SSimon Derr * cast `allowed' as a signed long because vm_committed_space 13242f60f8d3SSimon Derr * sometimes has a negative value 13252f60f8d3SSimon Derr */ 13262f60f8d3SSimon Derr if (atomic_read(&vm_committed_space) < (long)allowed) 13271da177e4SLinus Torvalds return 0; 1328d5ddc79bSHideo AOKI error: 13291da177e4SLinus Torvalds vm_unacct_memory(pages); 13301da177e4SLinus Torvalds 13311da177e4SLinus Torvalds return -ENOMEM; 13321da177e4SLinus Torvalds } 13331da177e4SLinus Torvalds 13341da177e4SLinus Torvalds int in_gate_area_no_task(unsigned long addr) 13351da177e4SLinus Torvalds { 13361da177e4SLinus Torvalds return 0; 13371da177e4SLinus Torvalds } 1338b0e15190SDavid Howells 1339b0e15190SDavid Howells struct page *filemap_nopage(struct vm_area_struct *area, 1340b0e15190SDavid Howells unsigned long address, int *type) 1341b0e15190SDavid Howells { 1342b0e15190SDavid Howells BUG(); 1343b0e15190SDavid Howells return NULL; 1344b0e15190SDavid Howells } 13450ec76a11SDavid Howells 13460ec76a11SDavid Howells /* 13470ec76a11SDavid Howells * Access another process' address space. 13480ec76a11SDavid Howells * - source/target buffer must be kernel space 13490ec76a11SDavid Howells */ 13500ec76a11SDavid Howells int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write) 13510ec76a11SDavid Howells { 13520ec76a11SDavid Howells struct vm_area_struct *vma; 13530ec76a11SDavid Howells struct mm_struct *mm; 13540ec76a11SDavid Howells 13550ec76a11SDavid Howells if (addr + len < addr) 13560ec76a11SDavid Howells return 0; 13570ec76a11SDavid Howells 13580ec76a11SDavid Howells mm = get_task_mm(tsk); 13590ec76a11SDavid Howells if (!mm) 13600ec76a11SDavid Howells return 0; 13610ec76a11SDavid Howells 13620ec76a11SDavid Howells down_read(&mm->mmap_sem); 13630ec76a11SDavid Howells 13640ec76a11SDavid Howells /* the access must start within one of the target process's mappings */ 13650159b141SDavid Howells vma = find_vma(mm, addr); 13660159b141SDavid Howells if (vma) { 13670ec76a11SDavid Howells /* don't overrun this mapping */ 13680ec76a11SDavid Howells if (addr + len >= vma->vm_end) 13690ec76a11SDavid Howells len = vma->vm_end - addr; 13700ec76a11SDavid Howells 13710ec76a11SDavid Howells /* only read or write mappings where it is permitted */ 1372d00c7b99SDavid Howells if (write && vma->vm_flags & VM_MAYWRITE) 13730ec76a11SDavid Howells len -= copy_to_user((void *) addr, buf, len); 1374d00c7b99SDavid Howells else if (!write && vma->vm_flags & VM_MAYREAD) 13750ec76a11SDavid Howells len -= copy_from_user(buf, (void *) addr, len); 13760ec76a11SDavid Howells else 13770ec76a11SDavid Howells len = 0; 13780ec76a11SDavid Howells } else { 13790ec76a11SDavid Howells len = 0; 13800ec76a11SDavid Howells } 13810ec76a11SDavid Howells 13820ec76a11SDavid Howells up_read(&mm->mmap_sem); 13830ec76a11SDavid Howells mmput(mm); 13840ec76a11SDavid Howells return len; 13850ec76a11SDavid Howells } 1386