msync.c 2.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 *	linux/mm/msync.c
 *
 * Copyright (C) 1994-1999  Linus Torvalds
 */

/*
 * The msync() system call.
 */
A
Andrew Morton 已提交
10
#include <linux/fs.h>
L
Linus Torvalds 已提交
11 12
#include <linux/mm.h>
#include <linux/mman.h>
13
#include <linux/file.h>
L
Linus Torvalds 已提交
14
#include <linux/syscalls.h>
A
Alexey Dobriyan 已提交
15
#include <linux/sched.h>
L
Linus Torvalds 已提交
16 17 18 19

/*
 * MS_SYNC syncs the entire file - including mappings.
 *
P
Peter Zijlstra 已提交
20 21 22 23 24
 * 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
L
Linus Torvalds 已提交
25 26 27
 * 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.
28
 * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to
L
Linus Torvalds 已提交
29 30 31 32 33
 * applications.
 */
asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
{
	unsigned long end;
P
Peter Zijlstra 已提交
34
	struct mm_struct *mm = current->mm;
L
Linus Torvalds 已提交
35
	struct vm_area_struct *vma;
A
Andrew Morton 已提交
36 37
	int unmapped_error = 0;
	int error = -EINVAL;
L
Linus Torvalds 已提交
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56

	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
		goto out;
	if (start & ~PAGE_MASK)
		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.
	 */
P
Peter Zijlstra 已提交
57 58 59
	down_read(&mm->mmap_sem);
	vma = find_vma(mm, start);
	for (;;) {
60 61
		struct file *file;

P
Peter Zijlstra 已提交
62 63 64 65
		/* Still start < end. */
		error = -ENOMEM;
		if (!vma)
			goto out_unlock;
L
Linus Torvalds 已提交
66 67 68
		/* Here start < vma->vm_end. */
		if (start < vma->vm_start) {
			start = vma->vm_start;
P
Peter Zijlstra 已提交
69 70 71
			if (start >= end)
				goto out_unlock;
			unmapped_error = -ENOMEM;
L
Linus Torvalds 已提交
72 73
		}
		/* Here vma->vm_start <= start < vma->vm_end. */
P
Peter Zijlstra 已提交
74 75 76 77
		if ((flags & MS_INVALIDATE) &&
				(vma->vm_flags & VM_LOCKED)) {
			error = -EBUSY;
			goto out_unlock;
L
Linus Torvalds 已提交
78
		}
79
		file = vma->vm_file;
L
Linus Torvalds 已提交
80
		start = vma->vm_end;
P
Peter Zijlstra 已提交
81
		if ((flags & MS_SYNC) && file &&
82 83
				(vma->vm_flags & VM_SHARED)) {
			get_file(file);
P
Peter Zijlstra 已提交
84
			up_read(&mm->mmap_sem);
C
Christoph Hellwig 已提交
85
			error = vfs_fsync(file, file->f_path.dentry, 0);
86
			fput(file);
P
Peter Zijlstra 已提交
87 88 89 90
			if (error || start >= end)
				goto out;
			down_read(&mm->mmap_sem);
			vma = find_vma(mm, start);
91
		} else {
P
Peter Zijlstra 已提交
92 93 94 95
			if (start >= end) {
				error = 0;
				goto out_unlock;
			}
96 97
			vma = vma->vm_next;
		}
P
Peter Zijlstra 已提交
98
	}
99
out_unlock:
P
Peter Zijlstra 已提交
100
	up_read(&mm->mmap_sem);
101
out:
P
Peter Zijlstra 已提交
102
	return error ? : unmapped_error;
L
Linus Torvalds 已提交
103
}