Back to home page

LXR

 
 

    


0001 /*
0002  *  linux/mm/msync.c
0003  *
0004  * Copyright (C) 1994-1999  Linus Torvalds
0005  */
0006 
0007 /*
0008  * The msync() system call.
0009  */
0010 #include <linux/fs.h>
0011 #include <linux/mm.h>
0012 #include <linux/mman.h>
0013 #include <linux/file.h>
0014 #include <linux/syscalls.h>
0015 #include <linux/sched.h>
0016 
0017 /*
0018  * MS_SYNC syncs the entire file - including mappings.
0019  *
0020  * MS_ASYNC does not start I/O (it used to, up to 2.5.67).
0021  * Nor does it marks the relevant pages dirty (it used to up to 2.6.17).
0022  * Now it doesn't do anything, since dirty pages are properly tracked.
0023  *
0024  * The application may now run fsync() to
0025  * write out the dirty pages and wait on the writeout and check the result.
0026  * Or the application may run fadvise(FADV_DONTNEED) against the fd to start
0027  * async writeout immediately.
0028  * So by _not_ starting I/O in MS_ASYNC we provide complete flexibility to
0029  * applications.
0030  */
0031 SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
0032 {
0033     unsigned long end;
0034     struct mm_struct *mm = current->mm;
0035     struct vm_area_struct *vma;
0036     int unmapped_error = 0;
0037     int error = -EINVAL;
0038 
0039     if (flags & ~(MS_ASYNC | MS_INVALIDATE | MS_SYNC))
0040         goto out;
0041     if (offset_in_page(start))
0042         goto out;
0043     if ((flags & MS_ASYNC) && (flags & MS_SYNC))
0044         goto out;
0045     error = -ENOMEM;
0046     len = (len + ~PAGE_MASK) & PAGE_MASK;
0047     end = start + len;
0048     if (end < start)
0049         goto out;
0050     error = 0;
0051     if (end == start)
0052         goto out;
0053     /*
0054      * If the interval [start,end) covers some unmapped address ranges,
0055      * just ignore them, but return -ENOMEM at the end.
0056      */
0057     down_read(&mm->mmap_sem);
0058     vma = find_vma(mm, start);
0059     for (;;) {
0060         struct file *file;
0061         loff_t fstart, fend;
0062 
0063         /* Still start < end. */
0064         error = -ENOMEM;
0065         if (!vma)
0066             goto out_unlock;
0067         /* Here start < vma->vm_end. */
0068         if (start < vma->vm_start) {
0069             start = vma->vm_start;
0070             if (start >= end)
0071                 goto out_unlock;
0072             unmapped_error = -ENOMEM;
0073         }
0074         /* Here vma->vm_start <= start < vma->vm_end. */
0075         if ((flags & MS_INVALIDATE) &&
0076                 (vma->vm_flags & VM_LOCKED)) {
0077             error = -EBUSY;
0078             goto out_unlock;
0079         }
0080         file = vma->vm_file;
0081         fstart = (start - vma->vm_start) +
0082              ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
0083         fend = fstart + (min(end, vma->vm_end) - start) - 1;
0084         start = vma->vm_end;
0085         if ((flags & MS_SYNC) && file &&
0086                 (vma->vm_flags & VM_SHARED)) {
0087             get_file(file);
0088             up_read(&mm->mmap_sem);
0089             error = vfs_fsync_range(file, fstart, fend, 1);
0090             fput(file);
0091             if (error || start >= end)
0092                 goto out;
0093             down_read(&mm->mmap_sem);
0094             vma = find_vma(mm, start);
0095         } else {
0096             if (start >= end) {
0097                 error = 0;
0098                 goto out_unlock;
0099             }
0100             vma = vma->vm_next;
0101         }
0102     }
0103 out_unlock:
0104     up_read(&mm->mmap_sem);
0105 out:
0106     return error ? : unmapped_error;
0107 }