| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | *	linux/mm/msync.c | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 1994-1999  Linus Torvalds | 
|  | 5 | */ | 
|  | 6 |  | 
|  | 7 | /* | 
|  | 8 | * The msync() system call. | 
|  | 9 | */ | 
| Andrew Morton | 8f2e9f1 | 2006-03-24 03:18:15 -0800 | [diff] [blame] | 10 | #include <linux/fs.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 11 | #include <linux/mm.h> | 
|  | 12 | #include <linux/mman.h> | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 13 | #include <linux/file.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 14 | #include <linux/syscalls.h> | 
| Alexey Dobriyan | e8edc6e | 2007-05-21 01:22:52 +0400 | [diff] [blame] | 15 | #include <linux/sched.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 16 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 17 | /* | 
|  | 18 | * MS_SYNC syncs the entire file - including mappings. | 
|  | 19 | * | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 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 | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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. | 
| Amos Waterland | 16538c4 | 2006-03-24 18:30:53 +0100 | [diff] [blame] | 28 | * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | * applications. | 
|  | 30 | */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 31 | asmlinkage long sys_msync(unsigned long start, size_t len, int flags) | 
|  | 32 | { | 
|  | 33 | unsigned long end; | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 34 | struct mm_struct *mm = current->mm; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 35 | struct vm_area_struct *vma; | 
| Andrew Morton | 676758b | 2006-03-24 03:18:14 -0800 | [diff] [blame] | 36 | int unmapped_error = 0; | 
|  | 37 | int error = -EINVAL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 38 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC)) | 
|  | 40 | goto out; | 
|  | 41 | if (start & ~PAGE_MASK) | 
|  | 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 | */ | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 57 | down_read(&mm->mmap_sem); | 
|  | 58 | vma = find_vma(mm, start); | 
|  | 59 | for (;;) { | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 60 | struct file *file; | 
|  | 61 |  | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 62 | /* Still start < end. */ | 
|  | 63 | error = -ENOMEM; | 
|  | 64 | if (!vma) | 
|  | 65 | goto out_unlock; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 66 | /* Here start < vma->vm_end. */ | 
|  | 67 | if (start < vma->vm_start) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 68 | start = vma->vm_start; | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 69 | if (start >= end) | 
|  | 70 | goto out_unlock; | 
|  | 71 | unmapped_error = -ENOMEM; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 | } | 
|  | 73 | /* Here vma->vm_start <= start < vma->vm_end. */ | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 74 | if ((flags & MS_INVALIDATE) && | 
|  | 75 | (vma->vm_flags & VM_LOCKED)) { | 
|  | 76 | error = -EBUSY; | 
|  | 77 | goto out_unlock; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 78 | } | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 79 | file = vma->vm_file; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 80 | start = vma->vm_end; | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 81 | if ((flags & MS_SYNC) && file && | 
| Andrew Morton | 707c21c | 2006-03-24 03:18:13 -0800 | [diff] [blame] | 82 | (vma->vm_flags & VM_SHARED)) { | 
| Andrew Morton | 707c21c | 2006-03-24 03:18:13 -0800 | [diff] [blame] | 83 | get_file(file); | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 84 | up_read(&mm->mmap_sem); | 
| Andrew Morton | 8f2e9f1 | 2006-03-24 03:18:15 -0800 | [diff] [blame] | 85 | error = do_fsync(file, 0); | 
| Andrew Morton | 707c21c | 2006-03-24 03:18:13 -0800 | [diff] [blame] | 86 | fput(file); | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 87 | if (error || start >= end) | 
|  | 88 | goto out; | 
|  | 89 | down_read(&mm->mmap_sem); | 
|  | 90 | vma = find_vma(mm, start); | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 91 | } else { | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 92 | if (start >= end) { | 
|  | 93 | error = 0; | 
|  | 94 | goto out_unlock; | 
|  | 95 | } | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 96 | vma = vma->vm_next; | 
|  | 97 | } | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 98 | } | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 99 | out_unlock: | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 100 | up_read(&mm->mmap_sem); | 
| Andrew Morton | 9c50823e | 2006-03-24 03:18:12 -0800 | [diff] [blame] | 101 | out: | 
| Peter Zijlstra | 204ec84 | 2006-09-25 23:31:01 -0700 | [diff] [blame] | 102 | return error ? : unmapped_error; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 | } |