msync.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /*
  2. * linux/mm/msync.c
  3. *
  4. * Copyright (C) 1994-1999 Linus Torvalds
  5. */
  6. /*
  7. * The msync() system call.
  8. */
  9. #include <linux/fs.h>
  10. #include <linux/mm.h>
  11. #include <linux/mman.h>
  12. #include <linux/file.h>
  13. #include <linux/syscalls.h>
  14. /*
  15. * MS_SYNC syncs the entire file - including mappings.
  16. *
  17. * MS_ASYNC does not start I/O (it used to, up to 2.5.67).
  18. * Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
  19. * Now it doesn't do anything, since dirty pages are properly tracked.
  20. *
  21. * The application may now run fsync() to
  22. * write out the dirty pages and wait on the writeout and check the result.
  23. * Or the application may run fadvise(FADV_DONTNEED) against the fd to start
  24. * async writeout immediately.
  25. * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to
  26. * applications.
  27. */
  28. asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
  29. {
  30. unsigned long end;
  31. struct mm_struct *mm = current->mm;
  32. struct vm_area_struct *vma;
  33. int unmapped_error = 0;
  34. int error = -EINVAL;
  35. if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
  36. goto out;
  37. if (start & ~PAGE_MASK)
  38. goto out;
  39. if ((flags & MS_ASYNC) && (flags & MS_SYNC))
  40. goto out;
  41. error = -ENOMEM;
  42. len = (len + ~PAGE_MASK) & PAGE_MASK;
  43. end = start + len;
  44. if (end < start)
  45. goto out;
  46. error = 0;
  47. if (end == start)
  48. goto out;
  49. /*
  50. * If the interval [start,end) covers some unmapped address ranges,
  51. * just ignore them, but return -ENOMEM at the end.
  52. */
  53. down_read(&mm->mmap_sem);
  54. vma = find_vma(mm, start);
  55. for (;;) {
  56. struct file *file;
  57. /* Still start < end. */
  58. error = -ENOMEM;
  59. if (!vma)
  60. goto out_unlock;
  61. /* Here start < vma->vm_end. */
  62. if (start < vma->vm_start) {
  63. start = vma->vm_start;
  64. if (start >= end)
  65. goto out_unlock;
  66. unmapped_error = -ENOMEM;
  67. }
  68. /* Here vma->vm_start <= start < vma->vm_end. */
  69. if ((flags & MS_INVALIDATE) &&
  70. (vma->vm_flags & VM_LOCKED)) {
  71. error = -EBUSY;
  72. goto out_unlock;
  73. }
  74. file = vma->vm_file;
  75. start = vma->vm_end;
  76. if ((flags & MS_SYNC) && file &&
  77. (vma->vm_flags & VM_SHARED)) {
  78. get_file(file);
  79. up_read(&mm->mmap_sem);
  80. error = do_fsync(file, 0);
  81. fput(file);
  82. if (error || start >= end)
  83. goto out;
  84. down_read(&mm->mmap_sem);
  85. vma = find_vma(mm, start);
  86. } else {
  87. if (start >= end) {
  88. error = 0;
  89. goto out_unlock;
  90. }
  91. vma = vma->vm_next;
  92. }
  93. }
  94. out_unlock:
  95. up_read(&mm->mmap_sem);
  96. out:
  97. return error ? : unmapped_error;
  98. }