mlock.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. return ret;
  71. }
  72. static int do_mlock(unsigned long start, size_t len, int on)
  73. {
  74. unsigned long nstart, end, tmp;
  75. struct vm_area_struct * vma, * prev;
  76. int error;
  77. len = PAGE_ALIGN(len);
  78. end = start + len;
  79. if (end < start)
  80. return -EINVAL;
  81. if (end == start)
  82. return 0;
  83. vma = find_vma_prev(current->mm, start, &prev);
  84. if (!vma || vma->vm_start > start)
  85. return -ENOMEM;
  86. if (start > vma->vm_start)
  87. prev = vma;
  88. for (nstart = start ; ; ) {
  89. unsigned int newflags;
  90. /* Here we know that vma->vm_start <= nstart < vma->vm_end. */
  91. newflags = vma->vm_flags | VM_LOCKED;
  92. if (!on)
  93. newflags &= ~VM_LOCKED;
  94. tmp = vma->vm_end;
  95. if (tmp > end)
  96. tmp = end;
  97. error = mlock_fixup(vma, &prev, nstart, tmp, newflags);
  98. if (error)
  99. break;
  100. nstart = tmp;
  101. if (nstart < prev->vm_end)
  102. nstart = prev->vm_end;
  103. if (nstart >= end)
  104. break;
  105. vma = prev->vm_next;
  106. if (!vma || vma->vm_start != nstart) {
  107. error = -ENOMEM;
  108. break;
  109. }
  110. }
  111. return error;
  112. }
  113. asmlinkage long sys_mlock(unsigned long start, size_t len)
  114. {
  115. unsigned long locked;
  116. unsigned long lock_limit;
  117. int error = -ENOMEM;
  118. if (!can_do_mlock())
  119. return -EPERM;
  120. down_write(&current->mm->mmap_sem);
  121. len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
  122. start &= PAGE_MASK;
  123. locked = len >> PAGE_SHIFT;
  124. locked += current->mm->locked_vm;
  125. lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
  126. lock_limit >>= PAGE_SHIFT;
  127. /* check against resource limits */
  128. if ((locked <= lock_limit) || capable(CAP_IPC_LOCK))
  129. error = do_mlock(start, len, 1);
  130. up_write(&current->mm->mmap_sem);
  131. return error;
  132. }
  133. asmlinkage long sys_munlock(unsigned long start, size_t len)
  134. {
  135. int ret;
  136. down_write(&current->mm->mmap_sem);
  137. len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
  138. start &= PAGE_MASK;
  139. ret = do_mlock(start, len, 0);
  140. up_write(&current->mm->mmap_sem);
  141. return ret;
  142. }
  143. static int do_mlockall(int flags)
  144. {
  145. struct vm_area_struct * vma, * prev = NULL;
  146. unsigned int def_flags = 0;
  147. if (flags & MCL_FUTURE)
  148. def_flags = VM_LOCKED;
  149. current->mm->def_flags = def_flags;
  150. if (flags == MCL_FUTURE)
  151. goto out;
  152. for (vma = current->mm->mmap; vma ; vma = prev->vm_next) {
  153. unsigned int newflags;
  154. newflags = vma->vm_flags | VM_LOCKED;
  155. if (!(flags & MCL_CURRENT))
  156. newflags &= ~VM_LOCKED;
  157. /* Ignore errors */
  158. mlock_fixup(vma, &prev, vma->vm_start, vma->vm_end, newflags);
  159. }
  160. out:
  161. return 0;
  162. }
  163. asmlinkage long sys_mlockall(int flags)
  164. {
  165. unsigned long lock_limit;
  166. int ret = -EINVAL;
  167. if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
  168. goto out;
  169. ret = -EPERM;
  170. if (!can_do_mlock())
  171. goto out;
  172. down_write(&current->mm->mmap_sem);
  173. lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
  174. lock_limit >>= PAGE_SHIFT;
  175. ret = -ENOMEM;
  176. if (!(flags & MCL_CURRENT) || (current->mm->total_vm <= lock_limit) ||
  177. capable(CAP_IPC_LOCK))
  178. ret = do_mlockall(flags);
  179. up_write(&current->mm->mmap_sem);
  180. out:
  181. return ret;
  182. }
  183. asmlinkage long sys_munlockall(void)
  184. {
  185. int ret;
  186. down_write(&current->mm->mmap_sem);
  187. ret = do_mlockall(0);
  188. up_write(&current->mm->mmap_sem);
  189. return ret;
  190. }
  191. /*
  192. * Objects with different lifetime than processes (SHM_LOCK and SHM_HUGETLB
  193. * shm segments) get accounted against the user_struct instead.
  194. */
  195. static DEFINE_SPINLOCK(shmlock_user_lock);
  196. int user_shm_lock(size_t size, struct user_struct *user)
  197. {
  198. unsigned long lock_limit, locked;
  199. int allowed = 0;
  200. locked = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
  201. lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur;
  202. if (lock_limit == RLIM_INFINITY)
  203. allowed = 1;
  204. lock_limit >>= PAGE_SHIFT;
  205. spin_lock(&shmlock_user_lock);
  206. if (!allowed &&
  207. locked + user->locked_shm > lock_limit && !capable(CAP_IPC_LOCK))
  208. goto out;
  209. get_uid(user);
  210. user->locked_shm += locked;
  211. allowed = 1;
  212. out:
  213. spin_unlock(&shmlock_user_lock);
  214. return allowed;
  215. }
  216. void user_shm_unlock(size_t size, struct user_struct *user)
  217. {
  218. spin_lock(&shmlock_user_lock);
  219. user->locked_shm -= (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
  220. spin_unlock(&shmlock_user_lock);
  221. free_uid(user);
  222. }