2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
* mm/fadvise.c
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002, Linus Torvalds
|
|
|
|
*
|
2008-10-16 12:01:59 +07:00
|
|
|
* 11Jan2003 Andrew Morton
|
2005-04-17 05:20:36 +07:00
|
|
|
* Initial version.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/file.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/pagemap.h>
|
|
|
|
#include <linux/backing-dev.h>
|
|
|
|
#include <linux/pagevec.h>
|
|
|
|
#include <linux/fadvise.h>
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 18:18:04 +07:00
|
|
|
#include <linux/writeback.h>
|
2005-04-17 05:20:36 +07:00
|
|
|
#include <linux/syscalls.h>
|
|
|
|
|
|
|
|
#include <asm/unistd.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* POSIX_FADV_WILLNEED could set PG_Referenced, and POSIX_FADV_NOREUSE could
|
|
|
|
* deactivate the pages and clear PG_Referenced.
|
|
|
|
*/
|
2009-01-14 20:14:02 +07:00
|
|
|
SYSCALL_DEFINE(fadvise64_64)(int fd, loff_t offset, loff_t len, int advice)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
struct file *file = fget(fd);
|
|
|
|
struct address_space *mapping;
|
|
|
|
struct backing_dev_info *bdi;
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 18:18:04 +07:00
|
|
|
loff_t endbyte; /* inclusive */
|
2005-04-17 05:20:36 +07:00
|
|
|
pgoff_t start_index;
|
|
|
|
pgoff_t end_index;
|
|
|
|
unsigned long nrpages;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (!file)
|
|
|
|
return -EBADF;
|
|
|
|
|
2006-12-08 17:36:44 +07:00
|
|
|
if (S_ISFIFO(file->f_path.dentry->d_inode->i_mode)) {
|
2006-01-08 16:03:44 +07:00
|
|
|
ret = -ESPIPE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
mapping = file->f_mapping;
|
|
|
|
if (!mapping || len < 0) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2008-04-28 16:13:02 +07:00
|
|
|
if (mapping->a_ops->get_xip_mem) {
|
2008-02-05 13:29:31 +07:00
|
|
|
switch (advice) {
|
|
|
|
case POSIX_FADV_NORMAL:
|
|
|
|
case POSIX_FADV_RANDOM:
|
|
|
|
case POSIX_FADV_SEQUENTIAL:
|
|
|
|
case POSIX_FADV_WILLNEED:
|
|
|
|
case POSIX_FADV_NOREUSE:
|
|
|
|
case POSIX_FADV_DONTNEED:
|
|
|
|
/* no bad return value, but ignore advice */
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
2005-06-24 12:05:29 +07:00
|
|
|
goto out;
|
2008-02-05 13:29:31 +07:00
|
|
|
}
|
2005-06-24 12:05:29 +07:00
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
/* Careful about overflows. Len == 0 means "as much as possible" */
|
|
|
|
endbyte = offset + len;
|
|
|
|
if (!len || endbyte < len)
|
|
|
|
endbyte = -1;
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 18:18:04 +07:00
|
|
|
else
|
|
|
|
endbyte--; /* inclusive */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
bdi = mapping->backing_dev_info;
|
|
|
|
|
|
|
|
switch (advice) {
|
|
|
|
case POSIX_FADV_NORMAL:
|
|
|
|
file->f_ra.ra_pages = bdi->ra_pages;
|
2010-03-06 04:42:03 +07:00
|
|
|
spin_lock(&file->f_lock);
|
|
|
|
file->f_mode &= ~FMODE_RANDOM;
|
|
|
|
spin_unlock(&file->f_lock);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case POSIX_FADV_RANDOM:
|
2010-03-06 04:42:03 +07:00
|
|
|
spin_lock(&file->f_lock);
|
|
|
|
file->f_mode |= FMODE_RANDOM;
|
|
|
|
spin_unlock(&file->f_lock);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case POSIX_FADV_SEQUENTIAL:
|
|
|
|
file->f_ra.ra_pages = bdi->ra_pages * 2;
|
2010-03-06 04:42:03 +07:00
|
|
|
spin_lock(&file->f_lock);
|
|
|
|
file->f_mode &= ~FMODE_RANDOM;
|
|
|
|
spin_unlock(&file->f_lock);
|
2005-04-17 05:20:36 +07:00
|
|
|
break;
|
|
|
|
case POSIX_FADV_WILLNEED:
|
|
|
|
if (!mapping->a_ops->readpage) {
|
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* First and last PARTIAL page! */
|
|
|
|
start_index = offset >> PAGE_CACHE_SHIFT;
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 18:18:04 +07:00
|
|
|
end_index = endbyte >> PAGE_CACHE_SHIFT;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* Careful about overflow on the "+1" */
|
|
|
|
nrpages = end_index - start_index + 1;
|
|
|
|
if (!nrpages)
|
|
|
|
nrpages = ~0UL;
|
|
|
|
|
|
|
|
ret = force_page_cache_readahead(mapping, file,
|
|
|
|
start_index,
|
2009-06-17 05:31:20 +07:00
|
|
|
nrpages);
|
2005-04-17 05:20:36 +07:00
|
|
|
if (ret > 0)
|
|
|
|
ret = 0;
|
|
|
|
break;
|
2006-08-06 02:14:25 +07:00
|
|
|
case POSIX_FADV_NOREUSE:
|
|
|
|
break;
|
2005-04-17 05:20:36 +07:00
|
|
|
case POSIX_FADV_DONTNEED:
|
|
|
|
if (!bdi_write_congested(mapping->backing_dev_info))
|
|
|
|
filemap_flush(mapping);
|
|
|
|
|
|
|
|
/* First and last FULL page! */
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 18:18:04 +07:00
|
|
|
start_index = (offset+(PAGE_CACHE_SIZE-1)) >> PAGE_CACHE_SHIFT;
|
2005-04-17 05:20:36 +07:00
|
|
|
end_index = (endbyte >> PAGE_CACHE_SHIFT);
|
|
|
|
|
[PATCH] fadvise(): write commands
Add two new linux-specific fadvise extensions():
LINUX_FADV_ASYNC_WRITE: start async writeout of any dirty pages between file
offsets `offset' and `offset+len'. Any pages which are currently under
writeout are skipped, whether or not they are dirty.
LINUX_FADV_WRITE_WAIT: wait upon writeout of any dirty pages between file
offsets `offset' and `offset+len'.
By combining these two operations the application may do several things:
LINUX_FADV_ASYNC_WRITE: push some or all of the dirty pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE: push all of the currently dirty
pages at the disk.
LINUX_FADV_WRITE_WAIT, LINUX_FADV_ASYNC_WRITE, LINUX_FADV_WRITE_WAIT: push all
of the currently dirty pages at the disk, wait until they have been written.
It should be noted that none of these operations write out the file's
metadata. So unless the application is strictly performing overwrites of
already-instantiated disk blocks, there are no guarantees here that the data
will be available after a crash.
To complete this suite of operations I guess we should have a "sync file
metadata only" operation. This gives applications access to all the building
blocks needed for all sorts of sync operations. But sync-metadata doesn't fit
well with the fadvise() interface. Probably it should be a new syscall:
sys_fmetadatasync().
The patch also diddles with the meaning of `endbyte' in sys_fadvise64_64().
It is made to represent that last affected byte in the file (ie: it is
inclusive). Generally, all these byterange and pagerange functions are
inclusive so we can easily represent EOF with -1.
As Ulrich notes, these two functions are somewhat abusive of the fadvise()
concept, which appears to be "set the future policy for this fd".
But these commands are a perfect fit with the fadvise() impementation, and
several of the existing fadvise() commands are synchronous and don't affect
future policy either. I think we can live with the slight incongruity.
Cc: Michael Kerrisk <mtk-manpages@gmx.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2006-03-24 18:18:04 +07:00
|
|
|
if (end_index >= start_index)
|
|
|
|
invalidate_mapping_pages(mapping, start_index,
|
|
|
|
end_index);
|
|
|
|
break;
|
2005-04-17 05:20:36 +07:00
|
|
|
default:
|
|
|
|
ret = -EINVAL;
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
fput(file);
|
|
|
|
return ret;
|
|
|
|
}
|
2009-01-14 20:14:02 +07:00
|
|
|
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
|
|
|
|
asmlinkage long SyS_fadvise64_64(long fd, loff_t offset, loff_t len, long advice)
|
|
|
|
{
|
|
|
|
return SYSC_fadvise64_64((int) fd, offset, len, (int) advice);
|
|
|
|
}
|
|
|
|
SYSCALL_ALIAS(sys_fadvise64_64, SyS_fadvise64_64);
|
|
|
|
#endif
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#ifdef __ARCH_WANT_SYS_FADVISE64
|
|
|
|
|
2009-01-14 20:14:02 +07:00
|
|
|
SYSCALL_DEFINE(fadvise64)(int fd, loff_t offset, size_t len, int advice)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
return sys_fadvise64_64(fd, offset, len, advice);
|
|
|
|
}
|
2009-01-14 20:14:02 +07:00
|
|
|
#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
|
|
|
|
asmlinkage long SyS_fadvise64(long fd, loff_t offset, long len, long advice)
|
|
|
|
{
|
|
|
|
return SYSC_fadvise64((int) fd, offset, (size_t)len, (int)advice);
|
|
|
|
}
|
|
|
|
SYSCALL_ALIAS(sys_fadvise64, SyS_fadvise64);
|
|
|
|
#endif
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#endif
|