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 ) ;
2005-04-17 02:20:36 +04:00
static int nfs_fsync ( struct file * , struct dentry * dentry , int datasync ) ;
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 ,
. fsync = nfs_fsync ,
. 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 ;
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 ) ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
2006-08-23 04:06:11 +04:00
res = NFS_PROTO ( inode ) - > file_open ( inode , filp ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return res ;
}
static int
nfs_file_release ( struct inode * inode , struct file * filp )
{
/* Ensure that dirty pages are flushed out with the right creds */
if ( filp - > f_mode & FMODE_WRITE )
filemap_fdatawrite ( filp - > f_mapping ) ;
2006-03-20 21:44:14 +03:00
nfs_inc_stats ( inode , NFSIOS_VFSRELEASE ) ;
2005-04-17 02:20:36 +04:00
return NFS_PROTO ( inode ) - > file_release ( inode , filp ) ;
}
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 )
{
/* 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 ;
int retval = nfs_revalidate_file_size ( inode , filp ) ;
if ( retval < 0 )
return ( loff_t ) retval ;
}
return remote_llseek ( filp , offset , origin ) ;
}
2007-07-25 22:09:54 +04:00
/*
* Helper for nfs_file_flush ( ) and nfs_fsync ( )
*
* 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 ) ;
2006-12-08 13:36:40 +03:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
int status ;
dfprintk ( VFS , " nfs: flush(%s/%ld) \n " , inode - > i_sb - > s_id , inode - > i_ino ) ;
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
# ifdef CONFIG_NFS_DIRECTIO
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
# endif
dfprintk ( VFS , " nfs: read(%s/%s, %lu@%lu) \n " ,
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 ;
2007-06-01 13:51:43 +04:00
dfprintk ( VFS , " 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 ;
dfprintk ( VFS , " nfs: mmap(%s/%s) \n " ,
dentry - > d_parent - > d_name . name , dentry - > d_name . name ) ;
2006-05-25 09:40:59 +04:00
status = nfs_revalidate_mapping ( inode , file - > f_mapping ) ;
2007-07-23 01:09:05 +04:00
if ( ! status ) {
vma - > vm_ops = & nfs_file_vm_ops ;
vma - > vm_flags | = VM_CAN_NONLINEAR ;
file_accessed ( file ) ;
}
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
nfs_fsync ( struct file * file , struct dentry * dentry , int datasync )
{
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 ;
dfprintk ( VFS , " nfs: fsync(%s/%ld) \n " , inode - > i_sb - > s_id , inode - > i_ino ) ;
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
}
/*
* This does the " real " work of the write . The generic routine has
* allocated the page , locked it , done all the page alignment stuff
* calculations etc . Now we should just copy the data from user
* space and write it back to the real medium . .
*
* If the writer ends up delaying the write , the writer needs to
* increment the page use counts until he is done with the page .
*/
static int nfs_prepare_write ( struct file * file , struct page * page , unsigned offset , unsigned to )
{
return nfs_flush_incompatible ( file , page ) ;
}
static int nfs_commit_write ( struct file * file , struct page * page , unsigned offset , unsigned to )
{
long status ;
lock_kernel ( ) ;
status = nfs_updatepage ( file , page , offset , to - offset ) ;
unlock_kernel ( ) ;
return status ;
}
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
{
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 )
{
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 )
{
return nfs_wb_page ( page - > mapping - > host , 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 ,
. prepare_write = nfs_prepare_write ,
. commit_write = nfs_commit_write ,
2006-03-20 21:44:04 +03:00
. invalidatepage = nfs_invalidate_page ,
. releasepage = nfs_release_page ,
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_NFS_DIRECTIO
. direct_IO = nfs_direct_IO ,
# endif
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 ;
unsigned pagelen ;
int ret = - EINVAL ;
lock_page ( page ) ;
if ( page - > mapping ! = vma - > vm_file - > f_path . dentry - > d_inode - > i_mapping )
goto out_unlock ;
pagelen = nfs_page_length ( page ) ;
if ( pagelen = = 0 )
goto out_unlock ;
ret = nfs_prepare_write ( filp , page , 0 , pagelen ) ;
if ( ! ret )
ret = nfs_commit_write ( filp , page , 0 , pagelen ) ;
out_unlock :
unlock_page ( page ) ;
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
# ifdef CONFIG_NFS_DIRECTIO
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
# endif
2006-10-01 10:28:46 +04:00
dfprintk ( VFS , " nfs: write(%s/%s(%ld), %lu@%Ld) \n " ,
2005-04-17 02:20:36 +04:00
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
2006-10-01 10:28:46 +04:00
inode - > i_ino , ( 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 " ,
__FUNCTION__ , 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" */
if ( ! ( NFS_SERVER ( inode ) - > flags & NFS_MOUNT_NONLM ) ) {
status = NFS_PROTO ( inode ) - > lock ( filp , cmd , fl ) ;
/* If we were signalled we still need to ensure that
* we clean up any state on the server . We therefore
* record the lock call as having succeeded in order to
* ensure that locks_remove_posix ( ) cleans it out when
* the process exits .
*/
if ( status = = - EINTR | | status = = - ERESTARTSYS )
do_vfs_lock ( filp , fl ) ;
} else
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 ) ;
2005-04-17 02:20:36 +04:00
nfs_zap_caches ( inode ) ;
out :
return status ;
}
/*
* Lock a ( portion of ) a file
*/
static int nfs_lock ( struct file * filp , int cmd , struct file_lock * fl )
{
struct inode * inode = filp - > f_mapping - > host ;
dprintk ( " NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld) \n " ,
inode - > i_sb - > s_id , inode - > i_ino ,
fl - > fl_type , fl - > fl_flags ,
( long long ) fl - > fl_start , ( long long ) fl - > fl_end ) ;
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 */
2005-12-22 07:24:54 +03:00
if ( ( inode - > i_mode & ( S_ISGID | S_IXGRP ) ) = = S_ISGID & &
fl - > fl_type ! = F_UNLCK )
2005-04-17 02:20:36 +04:00
return - ENOLCK ;
if ( IS_GETLK ( cmd ) )
return do_getlk ( filp , cmd , fl ) ;
if ( fl - > fl_type = = F_UNLCK )
return do_unlk ( filp , cmd , fl ) ;
return do_setlk ( filp , cmd , fl ) ;
}
/*
* Lock a ( portion of ) a file
*/
static int nfs_flock ( struct file * filp , int cmd , struct file_lock * fl )
{
dprintk ( " NFS: nfs_flock(f=%s/%ld, t=%x, fl=%x) \n " ,
2006-12-08 13:36:40 +03:00
filp - > f_path . dentry - > d_inode - > i_sb - > s_id ,
filp - > f_path . dentry - > d_inode - > i_ino ,
2005-04-17 02:20:36 +04:00
fl - > fl_type , fl - > fl_flags ) ;
/*
* No BSD flocks over NFS allowed .
* Note : we could try to fake a POSIX lock request here by
* using ( ( u32 ) filp | 0x80000000 ) or some such as the pid .
* Not sure whether that would be unique , though , or whether
* that would break in other places .
*/
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
static int nfs_setlease ( struct file * file , long arg , struct file_lock * * fl )
{
/*
* There is no protocol support for leases , so we have no way
* to implement them correctly in the face of opens by other
* clients .
*/
return - EINVAL ;
}