/* * linux/mm/msync.c * * Copyright (C) 1994-1999 Linus Torvalds */ #include #include #include #include #include #include SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags) { unsigned long end; struct mm_struct *mm = current->mm; struct vm_area_struct *vma; int unmapped_error = 0; int error = -EINVAL; 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; down_read(&mm->mmap_sem); vma = find_vma(mm, start); for (;;) { struct file *file; error = -ENOMEM; if (!vma) goto out_unlock; if (start < vma->vm_start) { start = vma->vm_start; if (start >= end) goto out_unlock; unmapped_error = -ENOMEM; } if ((flags & MS_INVALIDATE) && (vma->vm_flags & VM_LOCKED)) { error = -EBUSY; goto out_unlock; } file = vma->vm_file; start = vma->vm_end; if ((flags & MS_SYNC) && file && (vma->vm_flags & VM_SHARED)) { get_file(file); up_read(&mm->mmap_sem); error = vfs_fsync(file, 0); fput(file); if (error || start >= end) goto out; down_read(&mm->mmap_sem); vma = find_vma(mm, start); } else { if (start >= end) { error = 0; goto out_unlock; } vma = vma->vm_next; } } out_unlock: up_read(&mm->mmap_sem); out: return error ? : unmapped_error; }