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