mlock.c 5.3 KB

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