2005-04-17 02:20:36 +04:00
/*
* linux / fs / nfs / file . c
*
* Copyright ( C ) 1992 Rick Sladkey
*
* Changes Copyright ( C ) 1994 by Florian La Roche
* - Do not copy data too often around in the kernel .
* - In nfs_file_read the return value of kmalloc wasn ' t checked .
* - Put in a better version of read look - ahead buffering . Original idea
* and implementation by Wai S Kok elekokws @ ee . nus . sg .
*
* Expire cache on write to a file by Wai S Kok ( Oct 1994 ) .
*
* Total rewrite of read side for new NFS buffer cache . . Linus .
*
* nfs regular file handling functions
*/
# include <linux/time.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/fcntl.h>
# include <linux/stat.h>
# include <linux/nfs_fs.h>
# include <linux/nfs_mount.h>
# include <linux/mm.h>
# include <linux/slab.h>
# include <linux/pagemap.h>
# include <linux/smp_lock.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/aio.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include <asm/system.h>
# include "delegation.h"
2007-07-23 01:09:05 +04:00
# include "internal.h"
2006-03-20 21:44:14 +03:00
# include "iostat.h"
2005-04-17 02:20:36 +04:00
# define NFSDBG_FACILITY NFSDBG_FILE
static int nfs_file_open ( struct inode * , struct file * ) ;
static int nfs_file_release ( struct inode * , struct file * ) ;
2005-06-13 19:14:01 +04:00
static loff_t nfs_file_llseek ( struct file * file , loff_t offset , int origin ) ;
2005-04-17 02:20:36 +04:00
static int nfs_file_mmap ( struct file * , struct vm_area_struct * ) ;
2007-06-01 13:51:43 +04:00
static ssize_t nfs_file_splice_read ( struct file * filp , loff_t * ppos ,
struct pipe_inode_info * pipe ,
size_t count , unsigned int flags ) ;
2006-10-01 10:28:46 +04:00
static ssize_t nfs_file_read ( struct kiocb * , const struct iovec * iov ,
unsigned long nr_segs , loff_t pos ) ;
static ssize_t nfs_file_write ( struct kiocb * , const struct iovec * iov ,
unsigned long nr_segs , loff_t pos ) ;
2006-06-23 13:05:12 +04:00
static int nfs_file_flush ( struct file * , fl_owner_t id ) ;
2008-05-28 00:29:07 +04:00
static int nfs_file_fsync ( struct file * , struct dentry * dentry , int datasync ) ;
2005-04-17 02:20:36 +04:00
static int nfs_check_flags ( int flags ) ;
static int nfs_lock ( struct file * filp , int cmd , struct file_lock * fl ) ;
static int nfs_flock ( struct file * filp , int cmd , struct file_lock * fl ) ;
2007-06-08 23:23:34 +04:00
static int nfs_setlease ( struct file * file , long arg , struct file_lock * * fl ) ;
2005-04-17 02:20:36 +04:00
2007-07-23 01:09:05 +04:00
static struct vm_operations_struct nfs_file_vm_ops ;
2006-03-28 13:56:42 +04:00
const struct file_operations nfs_file_operations = {
2005-06-13 19:14:01 +04:00
. llseek = nfs_file_llseek ,
2005-04-17 02:20:36 +04:00
. read = do_sync_read ,
. write = do_sync_write ,
2006-10-01 10:28:46 +04:00
. aio_read = nfs_file_read ,
. aio_write = nfs_file_write ,
2005-04-17 02:20:36 +04:00
. mmap = nfs_file_mmap ,
. open = nfs_file_open ,
. flush = nfs_file_flush ,
. release = nfs_file_release ,
2008-05-28 00:29:07 +04:00
. fsync = nfs_file_fsync ,
2005-04-17 02:20:36 +04:00
. lock = nfs_lock ,
. flock = nfs_flock ,
2007-06-01 13:51:43 +04:00
. splice_read = nfs_file_splice_read ,
2005-04-17 02:20:36 +04:00
. check_flags = nfs_check_flags ,
2007-06-08 23:23:34 +04:00
. setlease = nfs_setlease ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-12 11:55:39 +03:00
const struct inode_operations nfs_file_inode_operations = {
2005-04-17 02:20:36 +04:00
. permission = nfs_permission ,
. getattr = nfs_getattr ,
. setattr = nfs_setattr ,
} ;
2005-06-22 21:16:27 +04:00
# ifdef CONFIG_NFS_V3
2007-02-12 11:55:39 +03:00
const struct inode_operations nfs3_file_inode_operations = {
2005-06-22 21:16:27 +04:00
. permission = nfs_permission ,
. getattr = nfs_getattr ,
. setattr = nfs_setattr ,
. listxattr = nfs3_listxattr ,
. getxattr = nfs3_getxattr ,
. setxattr = nfs3_setxattr ,
. removexattr = nfs3_removexattr ,
} ;
# endif /* CONFIG_NFS_v3 */
2005-04-17 02:20:36 +04:00
/* Hack for future NFS swap support */
# ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
# endif
static int nfs_check_flags ( int flags )
{
if ( ( flags & ( O_APPEND | O_DIRECT ) ) = = ( O_APPEND | O_DIRECT ) )
return - EINVAL ;
return 0 ;
}
/*
* Open file
*/
static int
nfs_file_open ( struct inode * inode , struct file * filp )
{
int res ;
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: open file(%s/%s) \n " ,
2008-06-12 01:55:42 +04:00
filp - > f_path . dentry - > d_parent - > d_name . name ,
filp - > f_path . dentry - > d_name . name ) ;
2005-04-17 02:20:36 +04:00
res = nfs_check_flags ( filp - > f_flags ) ;
if ( res )
return res ;
2006-03-20 21:44:14 +03:00
nfs_inc_stats ( inode , NFSIOS_VFSOPEN ) ;
2008-06-12 00:32:46 +04:00
res = nfs_open ( inode , filp ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static int
nfs_file_release ( struct inode * inode , struct file * filp )
{
2008-06-12 01:55:58 +04:00
struct dentry * dentry = filp - > f_path . dentry ;
dprintk ( " NFS: release(%s/%s) \n " ,
dentry - > d_parent - > d_name . name ,
dentry - > d_name . name ) ;
2005-04-17 02:20:36 +04:00
/* Ensure that dirty pages are flushed out with the right creds */
if ( filp - > f_mode & FMODE_WRITE )
2008-06-12 01:55:58 +04:00
nfs_wb_all ( dentry - > d_inode ) ;
2006-03-20 21:44:14 +03:00
nfs_inc_stats ( inode , NFSIOS_VFSRELEASE ) ;
2008-06-12 00:32:46 +04:00
return nfs_release ( inode , filp ) ;
2005-04-17 02:20:36 +04:00
}
2005-06-13 19:14:01 +04:00
/**
* nfs_revalidate_size - Revalidate the file size
* @ inode - pointer to inode struct
* @ file - pointer to struct file
*
* Revalidates the file length . This is basically a wrapper around
* nfs_revalidate_inode ( ) that takes into account the fact that we may
* have cached writes ( in which case we don ' t care about the server ' s
* idea of what the file length is ) , or O_DIRECT ( in which case we
* shouldn ' t trust the cache ) .
*/
static int nfs_revalidate_file_size ( struct inode * inode , struct file * filp )
{
struct nfs_server * server = NFS_SERVER ( inode ) ;
struct nfs_inode * nfsi = NFS_I ( inode ) ;
if ( server - > flags & NFS_MOUNT_NOAC )
goto force_reval ;
if ( filp - > f_flags & O_DIRECT )
goto force_reval ;
if ( nfsi - > npages ! = 0 )
return 0 ;
2005-08-18 22:24:09 +04:00
if ( ! ( nfsi - > cache_validity & NFS_INO_REVAL_PAGECACHE ) & & ! nfs_attribute_timeout ( inode ) )
2005-06-22 21:16:30 +04:00
return 0 ;
2005-06-13 19:14:01 +04:00
force_reval :
return __nfs_revalidate_inode ( server , inode ) ;
}
static loff_t nfs_file_llseek ( struct file * filp , loff_t offset , int origin )
{
2008-06-27 13:05:24 +04:00
loff_t loff ;
2008-07-16 02:34:16 +04:00
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: llseek file(%s/%s, %lld, %d) \n " ,
2008-06-12 01:55:34 +04:00
filp - > f_path . dentry - > d_parent - > d_name . name ,
filp - > f_path . dentry - > d_name . name ,
offset , origin ) ;
2005-06-13 19:14:01 +04:00
/* origin == SEEK_END => we must revalidate the cached file length */
2006-09-17 05:09:32 +04:00
if ( origin = = SEEK_END ) {
2005-06-13 19:14:01 +04:00
struct inode * inode = filp - > f_mapping - > host ;
2008-09-24 01:28:35 +04:00
2005-06-13 19:14:01 +04:00
int retval = nfs_revalidate_file_size ( inode , filp ) ;
if ( retval < 0 )
return ( loff_t ) retval ;
2008-09-24 01:28:35 +04:00
spin_lock ( & inode - > i_lock ) ;
loff = generic_file_llseek_unlocked ( filp , offset , origin ) ;
spin_unlock ( & inode - > i_lock ) ;
} else
loff = generic_file_llseek_unlocked ( filp , offset , origin ) ;
2008-06-27 13:05:24 +04:00
return loff ;
2005-06-13 19:14:01 +04:00
}
2007-07-25 22:09:54 +04:00
/*
2008-05-28 00:29:07 +04:00
* Helper for nfs_file_flush ( ) and nfs_file_fsync ( )
2007-07-25 22:09:54 +04:00
*
* Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to
* disk , but it retrieves and clears ctx - > error after synching , despite
* the two being set at the same time in nfs_context_set_write_error ( ) .
* This is because the former is used to notify the _next_ call to
* nfs_file_write ( ) that a write error occured , and hence cause it to
* fall back to doing a synchronous write .
*/
static int nfs_do_fsync ( struct nfs_open_context * ctx , struct inode * inode )
{
int have_error , status ;
int ret = 0 ;
have_error = test_and_clear_bit ( NFS_CONTEXT_ERROR_WRITE , & ctx - > flags ) ;
status = nfs_wb_all ( inode ) ;
have_error | = test_bit ( NFS_CONTEXT_ERROR_WRITE , & ctx - > flags ) ;
if ( have_error )
ret = xchg ( & ctx - > error , 0 ) ;
if ( ! ret )
ret = status ;
return ret ;
}
2005-04-17 02:20:36 +04:00
/*
* Flush all dirty pages , and check for write errors .
*/
static int
2006-06-23 13:05:12 +04:00
nfs_file_flush ( struct file * file , fl_owner_t id )
2005-04-17 02:20:36 +04:00
{
2007-08-11 01:44:32 +04:00
struct nfs_open_context * ctx = nfs_file_open_context ( file ) ;
2008-06-12 01:55:58 +04:00
struct dentry * dentry = file - > f_path . dentry ;
struct inode * inode = dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
int status ;
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: flush(%s/%s) \n " ,
dentry - > d_parent - > d_name . name ,
dentry - > d_name . name ) ;
2005-04-17 02:20:36 +04:00
if ( ( file - > f_mode & FMODE_WRITE ) = = 0 )
return 0 ;
2006-03-20 21:44:14 +03:00
nfs_inc_stats ( inode , NFSIOS_VFSFLUSH ) ;
2007-07-25 22:09:54 +04:00
2005-04-17 02:20:36 +04:00
/* Ensure that data+attribute caches are up to date after close() */
2007-07-25 22:09:54 +04:00
status = nfs_do_fsync ( ctx , inode ) ;
if ( ! status )
nfs_revalidate_inode ( NFS_SERVER ( inode ) , inode ) ;
2005-04-17 02:20:36 +04:00
return status ;
}
static ssize_t
2006-10-01 10:28:46 +04:00
nfs_file_read ( struct kiocb * iocb , const struct iovec * iov ,
unsigned long nr_segs , loff_t pos )
2005-04-17 02:20:36 +04:00
{
2006-12-08 13:36:40 +03:00
struct dentry * dentry = iocb - > ki_filp - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
ssize_t result ;
2006-10-01 10:28:46 +04:00
size_t count = iov_length ( iov , nr_segs ) ;
2005-04-17 02:20:36 +04:00
if ( iocb - > ki_filp - > f_flags & O_DIRECT )
2006-10-01 10:28:46 +04:00
return nfs_file_direct_read ( iocb , iov , nr_segs , pos ) ;
2005-04-17 02:20:36 +04:00
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: read(%s/%s, %lu@%lu) \n " ,
2005-04-17 02:20:36 +04:00
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
( unsigned long ) count , ( unsigned long ) pos ) ;
2006-05-25 09:40:59 +04:00
result = nfs_revalidate_mapping ( inode , iocb - > ki_filp - > f_mapping ) ;
2006-03-20 21:44:14 +03:00
nfs_add_stats ( inode , NFSIOS_NORMALREADBYTES , count ) ;
2005-04-17 02:20:36 +04:00
if ( ! result )
2006-10-01 10:28:46 +04:00
result = generic_file_aio_read ( iocb , iov , nr_segs , pos ) ;
2005-04-17 02:20:36 +04:00
return result ;
}
static ssize_t
2007-06-01 13:51:43 +04:00
nfs_file_splice_read ( struct file * filp , loff_t * ppos ,
struct pipe_inode_info * pipe , size_t count ,
unsigned int flags )
2005-04-17 02:20:36 +04:00
{
2006-12-08 13:36:40 +03:00
struct dentry * dentry = filp - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
ssize_t res ;
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: splice_read(%s/%s, %lu@%Lu) \n " ,
2005-04-17 02:20:36 +04:00
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
( unsigned long ) count , ( unsigned long long ) * ppos ) ;
2006-05-25 09:40:59 +04:00
res = nfs_revalidate_mapping ( inode , filp - > f_mapping ) ;
2005-04-17 02:20:36 +04:00
if ( ! res )
2007-06-01 13:51:43 +04:00
res = generic_file_splice_read ( filp , ppos , pipe , count , flags ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static int
nfs_file_mmap ( struct file * file , struct vm_area_struct * vma )
{
2006-12-08 13:36:40 +03:00
struct dentry * dentry = file - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
int status ;
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: mmap(%s/%s) \n " ,
2005-04-17 02:20:36 +04:00
dentry - > d_parent - > d_name . name , dentry - > d_name . name ) ;
2009-03-11 21:37:54 +03:00
/* Note: generic_file_mmap() returns ENOSYS on nommu systems
* so we call that before revalidating the mapping
*/
status = generic_file_mmap ( file , vma ) ;
2007-07-23 01:09:05 +04:00
if ( ! status ) {
vma - > vm_ops = & nfs_file_vm_ops ;
2009-03-11 21:37:54 +03:00
status = nfs_revalidate_mapping ( inode , file - > f_mapping ) ;
2007-07-23 01:09:05 +04:00
}
2005-04-17 02:20:36 +04:00
return status ;
}
/*
* Flush any dirty pages for this process , and check for write errors .
* The return status from this call provides a reliable indication of
* whether any write errors occurred for this process .
*/
static int
2008-05-28 00:29:07 +04:00
nfs_file_fsync ( struct file * file , struct dentry * dentry , int datasync )
2005-04-17 02:20:36 +04:00
{
2007-08-11 01:44:32 +04:00
struct nfs_open_context * ctx = nfs_file_open_context ( file ) ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: fsync file(%s/%s) datasync %d \n " ,
2008-05-28 00:29:07 +04:00
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
datasync ) ;
2005-04-17 02:20:36 +04:00
2006-03-20 21:44:14 +03:00
nfs_inc_stats ( inode , NFSIOS_VFSFSYNC ) ;
2007-07-25 22:09:54 +04:00
return nfs_do_fsync ( ctx , inode ) ;
2005-04-17 02:20:36 +04:00
}
/*
2007-10-16 12:25:16 +04:00
* This does the " real " work of the write . We must allocate and lock the
* page to be sent back to the generic routine , which then copies the
* data from user space .
2005-04-17 02:20:36 +04:00
*
* If the writer ends up delaying the write , the writer needs to
* increment the page use counts until he is done with the page .
*/
2007-10-16 12:25:16 +04:00
static int nfs_write_begin ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:25:16 +04:00
int ret ;
pgoff_t index ;
struct page * page ;
index = pos > > PAGE_CACHE_SHIFT ;
2008-06-12 01:55:50 +04:00
dfprintk ( PAGECACHE , " NFS: write_begin(%s/%s(%ld), %u@%lld) \n " ,
file - > f_path . dentry - > d_parent - > d_name . name ,
file - > f_path . dentry - > d_name . name ,
mapping - > host - > i_ino , len , ( long long ) pos ) ;
2009-03-11 21:10:30 +03:00
/*
* Prevent starvation issues if someone is doing a consistency
* sync - to - disk
*/
ret = wait_on_bit ( & NFS_I ( mapping - > host ) - > flags , NFS_INO_FLUSHING ,
nfs_wait_bit_killable , TASK_KILLABLE ) ;
if ( ret )
return ret ;
fs: symlink write_begin allocation context fix
With the write_begin/write_end aops, page_symlink was broken because it
could no longer pass a GFP_NOFS type mask into the point where the
allocations happened. They are done in write_begin, which would always
assume that the filesystem can be entered from reclaim. This bug could
cause filesystem deadlocks.
The funny thing with having a gfp_t mask there is that it doesn't really
allow the caller to arbitrarily tinker with the context in which it can be
called. It couldn't ever be GFP_ATOMIC, for example, because it needs to
take the page lock. The only thing any callers care about is __GFP_FS
anyway, so turn that into a single flag.
Add a new flag for write_begin, AOP_FLAG_NOFS. Filesystems can now act on
this flag in their write_begin function. Change __grab_cache_page to
accept a nofs argument as well, to honour that flag (while we're there,
change the name to grab_cache_page_write_begin which is more instructive
and does away with random leading underscores).
This is really a more flexible way to go in the end anyway -- if a
filesystem happens to want any extra allocations aside from the pagecache
ones in ints write_begin function, it may now use GFP_KERNEL (rather than
GFP_NOFS) for common case allocations (eg. ocfs2_alloc_write_ctxt, for a
random example).
[kosaki.motohiro@jp.fujitsu.com: fix ubifs]
[kosaki.motohiro@jp.fujitsu.com: fix fuse]
Signed-off-by: Nick Piggin <npiggin@suse.de>
Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: <stable@kernel.org> [2.6.28.x]
Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
[ Cleaned up the calling convention: just pass in the AOP flags
untouched to the grab_cache_page_write_begin() function. That
just simplifies everybody, and may even allow future expansion of the
logic. - Linus ]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2009-01-04 23:00:53 +03:00
page = grab_cache_page_write_begin ( mapping , index , flags ) ;
2007-10-16 12:25:16 +04:00
if ( ! page )
return - ENOMEM ;
* pagep = page ;
ret = nfs_flush_incompatible ( file , page ) ;
if ( ret ) {
unlock_page ( page ) ;
page_cache_release ( page ) ;
}
return ret ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:25:16 +04:00
static int nfs_write_end ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * page , void * fsdata )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:25:16 +04:00
unsigned offset = pos & ( PAGE_CACHE_SIZE - 1 ) ;
int status ;
2005-04-17 02:20:36 +04:00
2008-06-12 01:55:50 +04:00
dfprintk ( PAGECACHE , " NFS: write_end(%s/%s(%ld), %u@%lld) \n " ,
file - > f_path . dentry - > d_parent - > d_name . name ,
file - > f_path . dentry - > d_name . name ,
mapping - > host - > i_ino , len , ( long long ) pos ) ;
2008-06-11 02:31:00 +04:00
/*
* Zero any uninitialised parts of the page , and then mark the page
* as up to date if it turns out that we ' re extending the file .
*/
if ( ! PageUptodate ( page ) ) {
unsigned pglen = nfs_page_length ( page ) ;
unsigned end = offset + len ;
if ( pglen = = 0 ) {
zero_user_segments ( page , 0 , offset ,
end , PAGE_CACHE_SIZE ) ;
SetPageUptodate ( page ) ;
} else if ( end > = pglen ) {
zero_user_segment ( page , end , PAGE_CACHE_SIZE ) ;
if ( offset = = 0 )
SetPageUptodate ( page ) ;
} else
zero_user_segment ( page , pglen , PAGE_CACHE_SIZE ) ;
}
2007-10-16 12:25:16 +04:00
status = nfs_updatepage ( file , page , offset , copied ) ;
unlock_page ( page ) ;
page_cache_release ( page ) ;
2007-12-20 22:55:04 +03:00
if ( status < 0 )
return status ;
return copied ;
2005-04-17 02:20:36 +04:00
}
2006-03-26 13:37:18 +04:00
static void nfs_invalidate_page ( struct page * page , unsigned long offset )
2006-03-20 21:44:04 +03:00
{
2008-06-12 01:55:50 +04:00
dfprintk ( PAGECACHE , " NFS: invalidate_page(%p, %lu) \n " , page , offset ) ;
2006-10-10 00:18:38 +04:00
if ( offset ! = 0 )
return ;
2006-05-31 09:13:38 +04:00
/* Cancel any unstarted writes on this page */
2007-08-28 18:29:36 +04:00
nfs_wb_page_cancel ( page - > mapping - > host , page ) ;
2006-03-20 21:44:04 +03:00
}
static int nfs_release_page ( struct page * page , gfp_t gfp )
{
2008-06-12 01:55:50 +04:00
dfprintk ( PAGECACHE , " NFS: release_page(%p) \n " , page ) ;
2007-01-11 10:15:39 +03:00
/* If PagePrivate() is set, then the page is not freeable */
return 0 ;
}
static int nfs_launder_page ( struct page * page )
{
2008-06-12 01:55:50 +04:00
struct inode * inode = page - > mapping - > host ;
dfprintk ( PAGECACHE , " NFS: launder_page(%ld, %llu) \n " ,
inode - > i_ino , ( long long ) page_offset ( page ) ) ;
return nfs_wb_page ( inode , page ) ;
2006-03-20 21:44:04 +03:00
}
2006-06-28 15:26:44 +04:00
const struct address_space_operations nfs_file_aops = {
2005-04-17 02:20:36 +04:00
. readpage = nfs_readpage ,
. readpages = nfs_readpages ,
2007-07-23 01:09:05 +04:00
. set_page_dirty = __set_page_dirty_nobuffers ,
2005-04-17 02:20:36 +04:00
. writepage = nfs_writepage ,
. writepages = nfs_writepages ,
2007-10-16 12:25:16 +04:00
. write_begin = nfs_write_begin ,
. write_end = nfs_write_end ,
2006-03-20 21:44:04 +03:00
. invalidatepage = nfs_invalidate_page ,
. releasepage = nfs_release_page ,
2005-04-17 02:20:36 +04:00
. direct_IO = nfs_direct_IO ,
2007-01-11 10:15:39 +03:00
. launder_page = nfs_launder_page ,
2005-04-17 02:20:36 +04:00
} ;
2007-07-23 01:09:05 +04:00
static int nfs_vm_page_mkwrite ( struct vm_area_struct * vma , struct page * page )
{
struct file * filp = vma - > vm_file ;
2008-06-12 01:55:50 +04:00
struct dentry * dentry = filp - > f_path . dentry ;
2007-07-23 01:09:05 +04:00
unsigned pagelen ;
int ret = - EINVAL ;
2007-10-16 12:25:16 +04:00
struct address_space * mapping ;
2007-07-23 01:09:05 +04:00
2008-06-12 01:55:50 +04:00
dfprintk ( PAGECACHE , " NFS: vm_page_mkwrite(%s/%s(%ld), offset %lld) \n " ,
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
filp - > f_mapping - > host - > i_ino ,
( long long ) page_offset ( page ) ) ;
2007-07-23 01:09:05 +04:00
lock_page ( page ) ;
2007-10-16 12:25:16 +04:00
mapping = page - > mapping ;
2008-06-12 01:55:50 +04:00
if ( mapping ! = dentry - > d_inode - > i_mapping )
2008-01-23 01:13:06 +03:00
goto out_unlock ;
ret = 0 ;
2007-07-23 01:09:05 +04:00
pagelen = nfs_page_length ( page ) ;
2008-01-23 01:13:06 +03:00
if ( pagelen = = 0 )
goto out_unlock ;
2007-10-16 12:25:16 +04:00
2008-01-23 01:13:06 +03:00
ret = nfs_flush_incompatible ( filp , page ) ;
if ( ret ! = 0 )
goto out_unlock ;
ret = nfs_updatepage ( filp , page , 0 , pagelen ) ;
if ( ret = = 0 )
ret = pagelen ;
out_unlock :
unlock_page ( page ) ;
2007-07-23 01:09:05 +04:00
return ret ;
}
static struct vm_operations_struct nfs_file_vm_ops = {
. fault = filemap_fault ,
. page_mkwrite = nfs_vm_page_mkwrite ,
} ;
2007-07-25 22:09:54 +04:00
static int nfs_need_sync_write ( struct file * filp , struct inode * inode )
{
struct nfs_open_context * ctx ;
if ( IS_SYNC ( inode ) | | ( filp - > f_flags & O_SYNC ) )
return 1 ;
2007-08-11 01:44:32 +04:00
ctx = nfs_file_open_context ( filp ) ;
2007-07-25 22:09:54 +04:00
if ( test_bit ( NFS_CONTEXT_ERROR_WRITE , & ctx - > flags ) )
return 1 ;
return 0 ;
}
2006-10-01 10:28:46 +04:00
static ssize_t nfs_file_write ( struct kiocb * iocb , const struct iovec * iov ,
unsigned long nr_segs , loff_t pos )
2005-04-17 02:20:36 +04:00
{
2006-12-08 13:36:40 +03:00
struct dentry * dentry = iocb - > ki_filp - > f_path . dentry ;
2005-04-17 02:20:36 +04:00
struct inode * inode = dentry - > d_inode ;
ssize_t result ;
2006-10-01 10:28:46 +04:00
size_t count = iov_length ( iov , nr_segs ) ;
2005-04-17 02:20:36 +04:00
if ( iocb - > ki_filp - > f_flags & O_DIRECT )
2006-10-01 10:28:46 +04:00
return nfs_file_direct_write ( iocb , iov , nr_segs , pos ) ;
2005-04-17 02:20:36 +04:00
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: write(%s/%s, %lu@%Ld) \n " ,
2005-04-17 02:20:36 +04:00
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
2008-06-12 01:55:58 +04:00
( unsigned long ) count , ( long long ) pos ) ;
2005-04-17 02:20:36 +04:00
result = - EBUSY ;
if ( IS_SWAPFILE ( inode ) )
goto out_swapfile ;
2005-06-22 21:16:30 +04:00
/*
* O_APPEND implies that we must revalidate the file length .
*/
if ( iocb - > ki_filp - > f_flags & O_APPEND ) {
result = nfs_revalidate_file_size ( inode , iocb - > ki_filp ) ;
if ( result )
goto out ;
2005-06-22 21:16:30 +04:00
}
2005-04-17 02:20:36 +04:00
result = count ;
if ( ! count )
goto out ;
2006-03-20 21:44:14 +03:00
nfs_add_stats ( inode , NFSIOS_NORMALWRITTENBYTES , count ) ;
2006-10-01 10:28:46 +04:00
result = generic_file_aio_write ( iocb , iov , nr_segs , pos ) ;
2006-12-05 08:35:40 +03:00
/* Return error values for O_SYNC and IS_SYNC() */
2007-07-25 22:09:54 +04:00
if ( result > = 0 & & nfs_need_sync_write ( iocb - > ki_filp , inode ) ) {
2007-08-11 01:44:32 +04:00
int err = nfs_do_fsync ( nfs_file_open_context ( iocb - > ki_filp ) , inode ) ;
2006-12-05 08:35:40 +03:00
if ( err < 0 )
result = err ;
}
2005-04-17 02:20:36 +04:00
out :
return result ;
out_swapfile :
printk ( KERN_INFO " NFS: attempt to write to active swap file! \n " ) ;
goto out ;
}
static int do_getlk ( struct file * filp , int cmd , struct file_lock * fl )
{
struct inode * inode = filp - > f_mapping - > host ;
int status = 0 ;
lock_kernel ( ) ;
2005-10-19 01:20:16 +04:00
/* Try local locking first */
2007-05-12 00:09:32 +04:00
posix_test_lock ( filp , fl ) ;
if ( fl - > fl_type ! = F_UNLCK ) {
/* found a conflict */
2005-10-19 01:20:16 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2005-10-19 01:20:16 +04:00
if ( nfs_have_delegation ( inode , FMODE_READ ) )
goto out_noconflict ;
if ( NFS_SERVER ( inode ) - > flags & NFS_MOUNT_NONLM )
goto out_noconflict ;
status = NFS_PROTO ( inode ) - > lock ( filp , cmd , fl ) ;
out :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return status ;
2005-10-19 01:20:16 +04:00
out_noconflict :
fl - > fl_type = F_UNLCK ;
goto out ;
2005-04-17 02:20:36 +04:00
}
static int do_vfs_lock ( struct file * file , struct file_lock * fl )
{
int res = 0 ;
switch ( fl - > fl_flags & ( FL_POSIX | FL_FLOCK ) ) {
case FL_POSIX :
res = posix_lock_file_wait ( file , fl ) ;
break ;
case FL_FLOCK :
res = flock_lock_file_wait ( file , fl ) ;
break ;
default :
BUG ( ) ;
}
if ( res < 0 )
2007-01-31 01:36:01 +03:00
dprintk ( KERN_WARNING " %s: VFS is out of sync with lock manager "
" - error %d! \n " ,
2008-05-03 00:42:44 +04:00
__func__ , res ) ;
2005-04-17 02:20:36 +04:00
return res ;
}
static int do_unlk ( struct file * filp , int cmd , struct file_lock * fl )
{
struct inode * inode = filp - > f_mapping - > host ;
int status ;
/*
* Flush all pending writes before doing anything
* with locks . .
*/
2005-12-14 00:13:54 +03:00
nfs_sync_mapping ( filp - > f_mapping ) ;
2005-04-17 02:20:36 +04:00
/* NOTE: special case
* If we ' re signalled while cleaning up locks on process exit , we
* still need to complete the unlock .
*/
lock_kernel ( ) ;
/* Use local locking if mounted with "-onolock" */
if ( ! ( NFS_SERVER ( inode ) - > flags & NFS_MOUNT_NONLM ) )
status = NFS_PROTO ( inode ) - > lock ( filp , cmd , fl ) ;
else
status = do_vfs_lock ( filp , fl ) ;
unlock_kernel ( ) ;
return status ;
}
static int do_setlk ( struct file * filp , int cmd , struct file_lock * fl )
{
struct inode * inode = filp - > f_mapping - > host ;
int status ;
/*
* Flush all pending writes before doing anything
* with locks . .
*/
2005-12-14 00:13:54 +03:00
status = nfs_sync_mapping ( filp - > f_mapping ) ;
if ( status ! = 0 )
2005-04-17 02:20:36 +04:00
goto out ;
lock_kernel ( ) ;
/* Use local locking if mounted with "-onolock" */
2008-04-02 04:26:52 +04:00
if ( ! ( NFS_SERVER ( inode ) - > flags & NFS_MOUNT_NONLM ) )
2005-04-17 02:20:36 +04:00
status = NFS_PROTO ( inode ) - > lock ( filp , cmd , fl ) ;
2008-04-02 04:26:52 +04:00
else
2005-04-17 02:20:36 +04:00
status = do_vfs_lock ( filp , fl ) ;
unlock_kernel ( ) ;
if ( status < 0 )
goto out ;
/*
* Make sure we clear the cache whenever we try to get the lock .
* This makes locking act as a cache coherency point .
*/
2005-12-14 00:13:54 +03:00
nfs_sync_mapping ( filp - > f_mapping ) ;
2008-06-11 02:31:02 +04:00
if ( ! nfs_have_delegation ( inode , FMODE_READ ) )
nfs_zap_caches ( inode ) ;
2005-04-17 02:20:36 +04:00
out :
return status ;
}
/*
* Lock a ( portion of ) a file
*/
static int nfs_lock ( struct file * filp , int cmd , struct file_lock * fl )
{
2008-06-12 01:55:58 +04:00
struct inode * inode = filp - > f_mapping - > host ;
2008-05-21 03:34:39 +04:00
int ret = - ENOLCK ;
2005-04-17 02:20:36 +04:00
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: lock(%s/%s, t=%x, fl=%x, r=%lld:%lld) \n " ,
filp - > f_path . dentry - > d_parent - > d_name . name ,
filp - > f_path . dentry - > d_name . name ,
2005-04-17 02:20:36 +04:00
fl - > fl_type , fl - > fl_flags ,
( long long ) fl - > fl_start , ( long long ) fl - > fl_end ) ;
2008-06-12 01:55:58 +04:00
2006-03-20 21:44:14 +03:00
nfs_inc_stats ( inode , NFSIOS_VFSLOCK ) ;
2005-04-17 02:20:36 +04:00
/* No mandatory locks over NFS */
2007-10-02 01:41:15 +04:00
if ( __mandatory_lock ( inode ) & & fl - > fl_type ! = F_UNLCK )
2008-05-21 03:34:39 +04:00
goto out_err ;
if ( NFS_PROTO ( inode ) - > lock_check_bounds ! = NULL ) {
ret = NFS_PROTO ( inode ) - > lock_check_bounds ( fl ) ;
if ( ret < 0 )
goto out_err ;
}
2005-04-17 02:20:36 +04:00
if ( IS_GETLK ( cmd ) )
2008-05-21 03:34:39 +04:00
ret = do_getlk ( filp , cmd , fl ) ;
else if ( fl - > fl_type = = F_UNLCK )
ret = do_unlk ( filp , cmd , fl ) ;
else
ret = do_setlk ( filp , cmd , fl ) ;
out_err :
return ret ;
2005-04-17 02:20:36 +04:00
}
/*
* Lock a ( portion of ) a file
*/
static int nfs_flock ( struct file * filp , int cmd , struct file_lock * fl )
{
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: flock(%s/%s, t=%x, fl=%x) \n " ,
filp - > f_path . dentry - > d_parent - > d_name . name ,
filp - > f_path . dentry - > d_name . name ,
2005-04-17 02:20:36 +04:00
fl - > fl_type , fl - > fl_flags ) ;
if ( ! ( fl - > fl_flags & FL_FLOCK ) )
return - ENOLCK ;
/* We're simulating flock() locks using posix locks on the server */
fl - > fl_owner = ( fl_owner_t ) filp ;
fl - > fl_start = 0 ;
fl - > fl_end = OFFSET_MAX ;
if ( fl - > fl_type = = F_UNLCK )
return do_unlk ( filp , cmd , fl ) ;
return do_setlk ( filp , cmd , fl ) ;
}
2007-06-08 23:23:34 +04:00
2008-06-12 01:55:58 +04:00
/*
* There is no protocol support for leases , so we have no way to implement
* them correctly in the face of opens by other clients .
*/
2007-06-08 23:23:34 +04:00
static int nfs_setlease ( struct file * file , long arg , struct file_lock * * fl )
{
2008-06-12 01:55:58 +04:00
dprintk ( " NFS: setlease(%s/%s, arg=%ld) \n " ,
file - > f_path . dentry - > d_parent - > d_name . name ,
file - > f_path . dentry - > d_name . name , arg ) ;
2007-06-08 23:23:34 +04:00
return - EINVAL ;
}