Back to home page

OSCL-LXR

 
 

    


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