2005-04-17 02:20:36 +04:00
/*
* linux / mm / msync . c
*
* Copyright ( C ) 1994 - 1999 Linus Torvalds
*/
/*
* The msync ( ) system call .
*/
2006-03-24 14:18:15 +03:00
# include <linux/fs.h>
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/mman.h>
2006-03-24 14:18:12 +03:00
# include <linux/file.h>
2005-04-17 02:20:36 +04:00
# include <linux/syscalls.h>
/*
* MS_SYNC syncs the entire file - including mappings .
*
2006-09-26 10:31:01 +04:00
* MS_ASYNC does not start I / O ( it used to , up to 2.5 .67 ) .
* Nor does it marks the relevant pages dirty ( it used to up to 2.6 .17 ) .
* Now it doesn ' t do anything , since dirty pages are properly tracked .
*
* The application may now run fsync ( ) to
2005-04-17 02:20:36 +04:00
* write out the dirty pages and wait on the writeout and check the result .
* Or the application may run fadvise ( FADV_DONTNEED ) against the fd to start
* async writeout immediately .
2006-03-24 20:30:53 +03:00
* So by _not_ starting I / O in MS_ASYNC we provide complete flexibility to
2005-04-17 02:20:36 +04:00
* applications .
*/
asmlinkage long sys_msync ( unsigned long start , size_t len , int flags )
{
unsigned long end ;
2006-09-26 10:31:01 +04:00
struct mm_struct * mm = current - > mm ;
2005-04-17 02:20:36 +04:00
struct vm_area_struct * vma ;
2006-03-24 14:18:14 +03:00
int unmapped_error = 0 ;
int error = - EINVAL ;
2005-04-17 02:20:36 +04:00
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 ;
/*
* If the interval [ start , end ) covers some unmapped address ranges ,
* just ignore them , but return - ENOMEM at the end .
*/
2006-09-26 10:31:01 +04:00
down_read ( & mm - > mmap_sem ) ;
vma = find_vma ( mm , start ) ;
for ( ; ; ) {
2006-03-24 14:18:12 +03:00
struct file * file ;
2006-09-26 10:31:01 +04:00
/* Still start < end. */
error = - ENOMEM ;
if ( ! vma )
goto out_unlock ;
2005-04-17 02:20:36 +04:00
/* Here start < vma->vm_end. */
if ( start < vma - > vm_start ) {
start = vma - > vm_start ;
2006-09-26 10:31:01 +04:00
if ( start > = end )
goto out_unlock ;
unmapped_error = - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
/* Here vma->vm_start <= start < vma->vm_end. */
2006-09-26 10:31:01 +04:00
if ( ( flags & MS_INVALIDATE ) & &
( vma - > vm_flags & VM_LOCKED ) ) {
error = - EBUSY ;
goto out_unlock ;
2005-04-17 02:20:36 +04:00
}
2006-03-24 14:18:12 +03:00
file = vma - > vm_file ;
2005-04-17 02:20:36 +04:00
start = vma - > vm_end ;
2006-09-26 10:31:01 +04:00
if ( ( flags & MS_SYNC ) & & file & &
2006-03-24 14:18:13 +03:00
( vma - > vm_flags & VM_SHARED ) ) {
get_file ( file ) ;
2006-09-26 10:31:01 +04:00
up_read ( & mm - > mmap_sem ) ;
2006-03-24 14:18:15 +03:00
error = do_fsync ( file , 0 ) ;
2006-03-24 14:18:13 +03:00
fput ( file ) ;
2006-09-26 10:31:01 +04:00
if ( error | | start > = end )
goto out ;
down_read ( & mm - > mmap_sem ) ;
vma = find_vma ( mm , start ) ;
2006-03-24 14:18:12 +03:00
} else {
2006-09-26 10:31:01 +04:00
if ( start > = end ) {
error = 0 ;
goto out_unlock ;
}
2006-03-24 14:18:12 +03:00
vma = vma - > vm_next ;
}
2006-09-26 10:31:01 +04:00
}
2006-03-24 14:18:12 +03:00
out_unlock :
2006-09-26 10:31:01 +04:00
up_read ( & mm - > mmap_sem ) ;
2006-03-24 14:18:12 +03:00
out :
2006-09-26 10:31:01 +04:00
return error ? : unmapped_error ;
2005-04-17 02:20:36 +04:00
}