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