xref: /linux/mm/msync.c (revision 2d8ad8719591fa803b0d589ed057fa46f49b7155)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	linux/mm/msync.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (C) 1994-1999  Linus Torvalds
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds /*
81da177e4SLinus Torvalds  * The msync() system call.
91da177e4SLinus Torvalds  */
108f2e9f15SAndrew Morton #include <linux/fs.h>
111da177e4SLinus Torvalds #include <linux/mm.h>
121da177e4SLinus Torvalds #include <linux/mman.h>
139c50823eSAndrew Morton #include <linux/file.h>
141da177e4SLinus Torvalds #include <linux/syscalls.h>
15e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds /*
181da177e4SLinus Torvalds  * MS_SYNC syncs the entire file - including mappings.
191da177e4SLinus Torvalds  *
20204ec841SPeter Zijlstra  * MS_ASYNC does not start I/O (it used to, up to 2.5.67).
21204ec841SPeter Zijlstra  * Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
22204ec841SPeter Zijlstra  * Now it doesn't do anything, since dirty pages are properly tracked.
23204ec841SPeter Zijlstra  *
24204ec841SPeter Zijlstra  * The application may now run fsync() to
251da177e4SLinus Torvalds  * write out the dirty pages and wait on the writeout and check the result.
261da177e4SLinus Torvalds  * Or the application may run fadvise(FADV_DONTNEED) against the fd to start
271da177e4SLinus Torvalds  * async writeout immediately.
2816538c40SAmos Waterland  * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to
291da177e4SLinus Torvalds  * applications.
301da177e4SLinus Torvalds  */
316a6160a7SHeiko Carstens SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
321da177e4SLinus Torvalds {
331da177e4SLinus Torvalds 	unsigned long end;
34204ec841SPeter Zijlstra 	struct mm_struct *mm = current->mm;
351da177e4SLinus Torvalds 	struct vm_area_struct *vma;
36676758bdSAndrew Morton 	int unmapped_error = 0;
37676758bdSAndrew Morton 	int error = -EINVAL;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds 	if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
401da177e4SLinus Torvalds 		goto out;
411da177e4SLinus Torvalds 	if (start & ~PAGE_MASK)
421da177e4SLinus Torvalds 		goto out;
431da177e4SLinus Torvalds 	if ((flags & MS_ASYNC) && (flags & MS_SYNC))
441da177e4SLinus Torvalds 		goto out;
451da177e4SLinus Torvalds 	error = -ENOMEM;
461da177e4SLinus Torvalds 	len = (len + ~PAGE_MASK) & PAGE_MASK;
471da177e4SLinus Torvalds 	end = start + len;
481da177e4SLinus Torvalds 	if (end < start)
491da177e4SLinus Torvalds 		goto out;
501da177e4SLinus Torvalds 	error = 0;
511da177e4SLinus Torvalds 	if (end == start)
521da177e4SLinus Torvalds 		goto out;
531da177e4SLinus Torvalds 	/*
541da177e4SLinus Torvalds 	 * If the interval [start,end) covers some unmapped address ranges,
551da177e4SLinus Torvalds 	 * just ignore them, but return -ENOMEM at the end.
561da177e4SLinus Torvalds 	 */
57204ec841SPeter Zijlstra 	down_read(&mm->mmap_sem);
58204ec841SPeter Zijlstra 	vma = find_vma(mm, start);
59204ec841SPeter Zijlstra 	for (;;) {
609c50823eSAndrew Morton 		struct file *file;
619c50823eSAndrew Morton 
62204ec841SPeter Zijlstra 		/* Still start < end. */
63204ec841SPeter Zijlstra 		error = -ENOMEM;
64204ec841SPeter Zijlstra 		if (!vma)
65204ec841SPeter Zijlstra 			goto out_unlock;
661da177e4SLinus Torvalds 		/* Here start < vma->vm_end. */
671da177e4SLinus Torvalds 		if (start < vma->vm_start) {
681da177e4SLinus Torvalds 			start = vma->vm_start;
69204ec841SPeter Zijlstra 			if (start >= end)
70204ec841SPeter Zijlstra 				goto out_unlock;
71204ec841SPeter Zijlstra 			unmapped_error = -ENOMEM;
721da177e4SLinus Torvalds 		}
731da177e4SLinus Torvalds 		/* Here vma->vm_start <= start < vma->vm_end. */
74204ec841SPeter Zijlstra 		if ((flags & MS_INVALIDATE) &&
75204ec841SPeter Zijlstra 				(vma->vm_flags & VM_LOCKED)) {
76204ec841SPeter Zijlstra 			error = -EBUSY;
779c50823eSAndrew Morton 			goto out_unlock;
789c50823eSAndrew Morton 		}
799c50823eSAndrew Morton 		file = vma->vm_file;
801da177e4SLinus Torvalds 		start = vma->vm_end;
81204ec841SPeter Zijlstra 		if ((flags & MS_SYNC) && file &&
82707c21c8SAndrew Morton 				(vma->vm_flags & VM_SHARED)) {
83707c21c8SAndrew Morton 			get_file(file);
84204ec841SPeter Zijlstra 			up_read(&mm->mmap_sem);
85*8018ab05SChristoph Hellwig 			error = vfs_fsync(file, 0);
86707c21c8SAndrew Morton 			fput(file);
87204ec841SPeter Zijlstra 			if (error || start >= end)
88204ec841SPeter Zijlstra 				goto out;
89204ec841SPeter Zijlstra 			down_read(&mm->mmap_sem);
90204ec841SPeter Zijlstra 			vma = find_vma(mm, start);
919c50823eSAndrew Morton 		} else {
92204ec841SPeter Zijlstra 			if (start >= end) {
93204ec841SPeter Zijlstra 				error = 0;
94204ec841SPeter Zijlstra 				goto out_unlock;
95204ec841SPeter Zijlstra 			}
961da177e4SLinus Torvalds 			vma = vma->vm_next;
971da177e4SLinus Torvalds 		}
98204ec841SPeter Zijlstra 	}
999c50823eSAndrew Morton out_unlock:
100204ec841SPeter Zijlstra 	up_read(&mm->mmap_sem);
1019c50823eSAndrew Morton out:
102204ec841SPeter Zijlstra 	return error ? : unmapped_error;
1031da177e4SLinus Torvalds }
104