1 /* 2 * linux/mm/mlock.c 3 * 4 * (C) Copyright 1995 Linus Torvalds 5 * (C) Copyright 2002 Christoph Hellwig 6 */ 7 8 #include <linux/mman.h> 9 #include <linux/mm.h> 10 11 12 static int mlock_fixup(struct vm_area_struct * vma, 13 unsigned long start, unsigned long end, unsigned int newflags) 14 { 15 struct mm_struct * mm = vma->vm_mm; 16 int pages; 17 int ret = 0; 18 19 if (newflags == vma->vm_flags) 20 goto out; 21 22 if (start != vma->vm_start) { 23 if (split_vma(mm, vma, start, 1)) { 24 ret = -EAGAIN; 25 goto out; 26 } 27 } 28 29 if (end != vma->vm_end) { 30 if (split_vma(mm, vma, end, 0)) { 31 ret = -EAGAIN; 32 goto out; 33 } 34 } 35 36 /* 37 * vm_flags is protected by the mmap_sem held in write mode. 38 * It's okay if try_to_unmap_one unmaps a page just after we 39 * set VM_LOCKED, make_pages_present below will bring it back. 40 */ 41 vma->vm_flags = newflags; 42 43 /* 44 * Keep track of amount of locked VM. 45 */ 46 pages = (end - start) >> PAGE_SHIFT; 47 if (newflags & VM_LOCKED) { 48 pages = -pages; 49 ret = make_pages_present(start, end); 50 } 51 52 vma->vm_mm->locked_vm -= pages; 53 out: 54 return ret; 55 } 56 57 static int do_mlock(unsigned long start, size_t len, int on) 58 { 59 unsigned long nstart, end, tmp; 60 struct vm_area_struct * vma, * next; 61 int error; 62 63 if (on && !capable(CAP_IPC_LOCK)) 64 return -EPERM; 65 len = PAGE_ALIGN(len); 66 end = start + len; 67 if (end < start) 68 return -EINVAL; 69 if (end == start) 70 return 0; 71 vma = find_vma(current->mm, start); 72 if (!vma || vma->vm_start > start) 73 return -ENOMEM; 74 75 for (nstart = start ; ; ) { 76 unsigned int newflags; 77 78 /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ 79 80 newflags = vma->vm_flags | VM_LOCKED; 81 if (!on) 82 newflags &= ~VM_LOCKED; 83 84 if (vma->vm_end >= end) { 85 error = mlock_fixup(vma, nstart, end, newflags); 86 break; 87 } 88 89 tmp = vma->vm_end; 90 next = vma->vm_next; 91 error = mlock_fixup(vma, nstart, tmp, newflags); 92 if (error) 93 break; 94 nstart = tmp; 95 vma = next; 96 if (!vma || vma->vm_start != nstart) { 97 error = -ENOMEM; 98 break; 99 } 100 } 101 return error; 102 } 103 104 asmlinkage long sys_mlock(unsigned long start, size_t len) 105 { 106 unsigned long locked; 107 unsigned long lock_limit; 108 int error = -ENOMEM; 109 110 down_write(¤t->mm->mmap_sem); 111 len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); 112 start &= PAGE_MASK; 113 114 locked = len >> PAGE_SHIFT; 115 locked += current->mm->locked_vm; 116 117 lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; 118 lock_limit >>= PAGE_SHIFT; 119 120 /* check against resource limits */ 121 if (locked <= lock_limit) 122 error = do_mlock(start, len, 1); 123 up_write(¤t->mm->mmap_sem); 124 return error; 125 } 126 127 asmlinkage long sys_munlock(unsigned long start, size_t len) 128 { 129 int ret; 130 131 down_write(¤t->mm->mmap_sem); 132 len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); 133 start &= PAGE_MASK; 134 ret = do_mlock(start, len, 0); 135 up_write(¤t->mm->mmap_sem); 136 return ret; 137 } 138 139 static int do_mlockall(int flags) 140 { 141 int error; 142 unsigned int def_flags; 143 struct vm_area_struct * vma; 144 145 if (!capable(CAP_IPC_LOCK)) 146 return -EPERM; 147 148 def_flags = 0; 149 if (flags & MCL_FUTURE) 150 def_flags = VM_LOCKED; 151 current->mm->def_flags = def_flags; 152 153 error = 0; 154 for (vma = current->mm->mmap; vma ; vma = vma->vm_next) { 155 unsigned int newflags; 156 157 newflags = vma->vm_flags | VM_LOCKED; 158 if (!(flags & MCL_CURRENT)) 159 newflags &= ~VM_LOCKED; 160 161 /* Ignore errors */ 162 mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags); 163 } 164 return error; 165 } 166 167 asmlinkage long sys_mlockall(int flags) 168 { 169 unsigned long lock_limit; 170 int ret = -EINVAL; 171 172 down_write(¤t->mm->mmap_sem); 173 if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE))) 174 goto out; 175 176 lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; 177 lock_limit >>= PAGE_SHIFT; 178 179 ret = -ENOMEM; 180 if (current->mm->total_vm <= lock_limit) 181 ret = do_mlockall(flags); 182 out: 183 up_write(¤t->mm->mmap_sem); 184 return ret; 185 } 186 187 asmlinkage long sys_munlockall(void) 188 { 189 int ret; 190 191 down_write(¤t->mm->mmap_sem); 192 ret = do_mlockall(0); 193 up_write(¤t->mm->mmap_sem); 194 return ret; 195 } 196
This page was automatically generated by LXR 0.3.1. • Linux is a registered trademark of Linus Torvalds