mlock.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /*
  2. * linux/mm/mlock.c
  3. *
  4. * (C) Copyright 1995 Linus Torvalds
  5. * (C) Copyright 2002 Christoph Hellwig
  6. */
  7. #include <linux/capability.h>
  8. #include <linux/mman.h>
  9. #include <linux/mm.h>
  10. #include <linux/mempolicy.h>
  11. #include <linux/syscalls.h>
  12. #include <linux/sched.h>
  13. #include <linux/module.h>
  14. int can_do_mlock(void)
  15. {
  16. if (capable(CAP_IPC_LOCK))
  17. return 1;
  18. if (current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur != 0)
  19. return 1;
  20. return 0;
  21. }
  22. EXPORT_SYMBOL(can_do_mlock);
  23. static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
  24. unsigned long start, unsigned long end, unsigned int newflags)
  25. {
  26. struct mm_struct * mm = vma->vm_mm;
  27. pgoff_t pgoff;
  28. int pages;
  29. int ret = 0;
  30. if (newflags == vma->vm_flags) {
  31. *prev = vma;
  32. goto out;
  33. }
  34. pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
  35. *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
  36. vma->vm_file, pgoff, vma_policy(vma));
  37. if (*prev) {
  38. vma = *prev;
  39. goto success;
  40. }
  41. *prev = vma;
  42. if (start != vma->vm_start) {
  43. ret = split_vma(mm, vma, start, 1);
  44. if (ret)
  45. goto out;
  46. }
  47. if (end != vma->vm_end) {
  48. ret = split_vma(mm, vma, end, 0);
  49. if (ret)
  50. goto out;
  51. }
  52. success:
  53. /*
  54. * vm_flags is protected by the mmap_sem held in write mode.
  55. * It's okay if try_to_unmap_one unmaps a page just after we
  56. * set VM_LOCKED, make_pages_present below will bring it back.
  57. */
  58. vma->vm_flags = newflags;
  59. /*
  60. * Keep track of amount of locked VM.
  61. */
  62. pages = (end - start) >> PAGE_SHIFT;
  63. if (newflags & VM_LOCKED) {
  64. pages = -pages;
  65. if (!(newflags & VM_IO))
  66. ret = make_pages_present(start, end);
  67. }
  68. mm->locked_vm -= pages;
  69. out:
  70. if (ret == -ENOMEM)
  71. ret = -EAGAIN;
  72. return ret;
  73. }
  74. static int do_mlock(unsigned long start, size_t len, int on)
  75. {
  76. unsigned long nstart, end, tmp;
  77. struct vm_area_struct * vma, * prev;
  78. int error;
  79. len = PAGE_ALIGN(len);
  80. end = start + len;
  81. if (end < start)
  82. return -EINVAL;
  83. if (end == start)
  84. return 0;
  85. vma = find_vma_prev(current->mm, start, &prev);
  86. if (!vma || vma->vm_start > start)
  87. return -ENOMEM;
  88. if (start > vma->vm_start)
  89. prev = vma;
  90. for (nstart = start ; ; ) {
  91. unsigned int newflags;
  92. /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
  93. newflags = vma->vm_flags | VM_LOCKED;
  94. if (!on)
  95. newflags &= ~VM_LOCKED;
  96. tmp = vma->vm_end;
  97. if (tmp > end)
  98. tmp = end;
  99. error = mlock_fixup(vma, &prev, nstart, tmp, newflags);
  100. if (error)
  101. break;
  102. nstart = tmp;
  103. if (nstart < prev->vm_end)
  104. nstart = prev->vm_end;
  105. if (nstart >= end)
  106. break;
  107. vma = prev->vm_next;
  108. if (!vma || vma->vm_start != nstart) {
  109. error = -ENOMEM;
  110. break;
  111. }
  112. }
  113. return error;
  114. }
  115. asmlinkage long sys_mlock(unsigned long start, size_t len)
  116. {
  117. unsigned long locked;
  118. unsigned long lock_limit;
  119. int error = -ENOMEM;
  120. if (!can_do_mlock())
  121. return -EPERM;
  122. down_write(&current->mm->mmap_sem);
  123. len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
  124. start &= PAGE_MASK;
  125. locked = len >> PAGE_SHIFT;
  126. locked += current->mm->locked_vm;
  127. lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
  128. lock_limit >>= PAGE_SHIFT;
  129. /* check against resource limits */
  130. if ((locked <= lock_limit) || capable(CAP_IPC_LOCK))
  131. error = do_mlock(start, len, 1);
  132. up_write(&current->mm->mmap_sem);
  133. return error;
  134. }
  135. asmlinkage long sys_munlock(unsigned long start, size_t len)
  136. {
  137. int ret;
  138. down_write(&current->mm->mmap_sem);
  139. len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
  140. start &= PAGE_MASK;
  141. ret = do_mlock(start, len, 0);
  142. up_write(&current->mm->mmap_sem);
  143. return ret;
  144. }
  145. static int do_mlockall(int flags)
  146. {
  147. struct vm_area_struct * vma, * prev = NULL;
  148. unsigned int def_flags = 0;
  149. if (flags & MCL_FUTURE)
  150. def_flags = VM_LOCKED;
  151. current->mm->def_flags = def_flags;
  152. if (flags == MCL_FUTURE)
  153. goto out;
  154. for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
  155. unsigned int newflags;
  156. newflags = vma->vm_flags | VM_LOCKED;
  157. if (!(flags & MCL_CURRENT))
  158. newflags &= ~VM_LOCKED;
  159. /* Ignore errors */
  160. mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
  161. }
  162. out:
  163. return 0;
  164. }
  165. asmlinkage long sys_mlockall(int flags)
  166. {
  167. unsigned long lock_limit;
  168. int ret = -EINVAL;
  169. if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
  170. goto out;
  171. ret = -EPERM;
  172. if (!can_do_mlock())
  173. goto out;
  174. down_write(&current->mm->mmap_sem);
  175. lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
  176. lock_limit >>= PAGE_SHIFT;
  177. ret = -ENOMEM;
  178. if (!(flags & MCL_CURRENT) || (current->mm->total_vm <= lock_limit) ||
  179. capable(CAP_IPC_LOCK))
  180. ret = do_mlockall(flags);
  181. up_write(&current->mm->mmap_sem);
  182. out:
  183. return ret;
  184. }
  185. asmlinkage long sys_munlockall(void)
  186. {
  187. int ret;
  188. down_write(&current->mm->mmap_sem);
  189. ret = do_mlockall(0);
  190. up_write(&current->mm->mmap_sem);
  191. return ret;
  192. }
  193. /*
  194. * Objects with different lifetime than processes (SHM_LOCK and SHM_HUGETLB
  195. * shm segments) get accounted against the user_struct instead.
  196. */
  197. static DEFINE_SPINLOCK(shmlock_user_lock);
  198. int user_shm_lock(size_t size, struct user_struct *user)
  199. {
  200. unsigned long lock_limit, locked;
  201. int allowed = 0;
  202. locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
  203. lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
  204. if (lock_limit == RLIM_INFINITY)
  205. allowed = 1;
  206. lock_limit >>= PAGE_SHIFT;
  207. spin_lock(&shmlock_user_lock);
  208. if (!allowed &&
  209. locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
  210. goto out;
  211. get_uid(user);
  212. user->locked_shm += locked;
  213. allowed = 1;
  214. out:
  215. spin_unlock(&shmlock_user_lock);
  216. return allowed;
  217. }
  218. void user_shm_unlock(size_t size, struct user_struct *user)
  219. {
  220. spin_lock(&shmlock_user_lock);
  221. user->locked_shm -= (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
  222. spin_unlock(&shmlock_user_lock);
  223. free_uid(user);
  224. }