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