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