2012-07-17 00:39:15 +04:00
/*
* linux / fs / nfs / file . c
*
* Copyright ( C ) 1992 Rick Sladkey
*/
2014-11-25 21:18:15 +03:00
# include <linux/fs.h>
# include <linux/falloc.h>
2012-07-17 00:39:15 +04:00
# include <linux/nfs_fs.h>
# include "internal.h"
2012-12-05 20:31:49 +04:00
# include "fscache.h"
2012-07-17 00:39:15 +04:00
# include "pnfs.h"
2015-03-26 02:09:08 +03:00
# include "nfstrace.h"
2014-09-26 21:58:48 +04:00
# ifdef CONFIG_NFS_V4_2
# include "nfs42.h"
# endif
2012-07-17 00:39:15 +04:00
# define NFSDBG_FACILITY NFSDBG_FILE
static int
nfs4_file_open ( struct inode * inode , struct file * filp )
{
struct nfs_open_context * ctx ;
struct dentry * dentry = filp - > f_path . dentry ;
struct dentry * parent = NULL ;
struct inode * dir ;
unsigned openflags = filp - > f_flags ;
struct iattr attr ;
2013-09-24 02:01:28 +04:00
int opened = 0 ;
2012-07-17 00:39:15 +04:00
int err ;
/*
* If no cached dentry exists or if it ' s negative , NFSv4 handled the
* opens in - > lookup ( ) or - > create ( ) .
*
* We only get this far for a cached positive dentry . We skipped
* revalidation , so handle it here by dropping the dentry and returning
* - EOPENSTALE . The VFS will retry the lookup / create / open .
*/
2013-09-16 18:53:17 +04:00
dprintk ( " NFS: open file(%pd2) \n " , dentry ) ;
2012-07-17 00:39:15 +04:00
2015-06-25 16:25:50 +03:00
err = nfs_check_flags ( openflags ) ;
if ( err )
return err ;
2012-07-17 00:39:15 +04:00
if ( ( openflags & O_ACCMODE ) = = 3 )
openflags - - ;
/* We can't create new files here */
openflags & = ~ ( O_CREAT | O_EXCL ) ;
parent = dget_parent ( dentry ) ;
2015-03-18 01:25:59 +03:00
dir = d_inode ( parent ) ;
2012-07-17 00:39:15 +04:00
ctx = alloc_nfs_open_context ( filp - > f_path . dentry , filp - > f_mode ) ;
err = PTR_ERR ( ctx ) ;
if ( IS_ERR ( ctx ) )
goto out ;
attr . ia_valid = ATTR_OPEN ;
if ( openflags & O_TRUNC ) {
attr . ia_valid | = ATTR_SIZE ;
attr . ia_size = 0 ;
2015-03-26 00:23:31 +03:00
nfs_sync_inode ( inode ) ;
2012-07-17 00:39:15 +04:00
}
2013-09-24 02:01:28 +04:00
inode = NFS_PROTO ( dir ) - > open_context ( dir , ctx , openflags , & attr , & opened ) ;
2012-07-17 00:39:15 +04:00
if ( IS_ERR ( inode ) ) {
err = PTR_ERR ( inode ) ;
switch ( err ) {
case - EPERM :
case - EACCES :
case - EDQUOT :
case - ENOSPC :
case - EROFS :
goto out_put_ctx ;
default :
goto out_drop ;
}
}
2015-03-18 01:25:59 +03:00
if ( inode ! = d_inode ( dentry ) )
2012-07-17 00:39:15 +04:00
goto out_drop ;
nfs_set_verifier ( dentry , nfs_save_change_attribute ( dir ) ) ;
nfs_file_set_open_context ( filp , ctx ) ;
2013-09-27 14:20:03 +04:00
nfs_fscache_open_file ( inode , filp ) ;
2012-07-17 00:39:15 +04:00
err = 0 ;
out_put_ctx :
put_nfs_open_context ( ctx ) ;
out :
dput ( parent ) ;
return err ;
out_drop :
d_drop ( dentry ) ;
err = - EOPENSTALE ;
goto out_put_ctx ;
}
static int
nfs4_file_fsync ( struct file * file , loff_t start , loff_t end , int datasync )
{
int ret ;
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( file ) ;
2012-07-17 00:39:15 +04:00
2015-03-26 02:09:08 +03:00
trace_nfs_fsync_enter ( inode ) ;
2015-03-26 01:58:53 +03:00
nfs_inode_dio_wait ( inode ) ;
2012-09-12 00:01:22 +04:00
do {
ret = filemap_write_and_wait_range ( inode - > i_mapping , start , end ) ;
if ( ret ! = 0 )
break ;
mutex_lock ( & inode - > i_mutex ) ;
ret = nfs_file_fsync_commit ( file , start , end , datasync ) ;
2014-04-21 21:29:17 +04:00
if ( ! ret )
2015-03-25 21:14:42 +03:00
ret = pnfs_sync_inode ( inode , ! ! datasync ) ;
2012-09-12 00:01:22 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2012-09-12 00:19:38 +04:00
/*
* If nfs_file_fsync_commit detected a server reboot , then
* resend all dirty pages that might have been covered by
* the NFS_CONTEXT_RESEND_WRITES flag
*/
start = 0 ;
end = LLONG_MAX ;
2012-09-12 00:01:22 +04:00
} while ( ret = = - EAGAIN ) ;
2015-03-26 02:09:08 +03:00
trace_nfs_fsync_exit ( inode , ret ) ;
2012-07-17 00:39:15 +04:00
return ret ;
}
2014-09-26 21:58:48 +04:00
# ifdef CONFIG_NFS_V4_2
static loff_t nfs4_file_llseek ( struct file * filep , loff_t offset , int whence )
{
loff_t ret ;
switch ( whence ) {
case SEEK_HOLE :
case SEEK_DATA :
ret = nfs42_proc_llseek ( filep , offset , whence ) ;
if ( ret ! = - ENOTSUPP )
return ret ;
default :
return nfs_file_llseek ( filep , offset , whence ) ;
}
}
2014-11-25 21:18:15 +03:00
static long nfs42_fallocate ( struct file * filep , int mode , loff_t offset , loff_t len )
{
struct inode * inode = file_inode ( filep ) ;
long ret ;
if ( ! S_ISREG ( inode - > i_mode ) )
return - EOPNOTSUPP ;
2014-11-25 21:18:16 +03:00
if ( ( mode ! = 0 ) & & ( mode ! = ( FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE ) ) )
2014-11-25 21:18:15 +03:00
return - EOPNOTSUPP ;
ret = inode_newsize_ok ( inode , offset + len ) ;
if ( ret < 0 )
return ret ;
2014-11-25 21:18:16 +03:00
if ( mode & FALLOC_FL_PUNCH_HOLE )
2015-03-16 21:06:24 +03:00
return nfs42_proc_deallocate ( filep , offset , len ) ;
return nfs42_proc_allocate ( filep , offset , len ) ;
2014-11-25 21:18:15 +03:00
}
2014-09-26 21:58:48 +04:00
# endif /* CONFIG_NFS_V4_2 */
2012-07-17 00:39:15 +04:00
const struct file_operations nfs4_file_operations = {
2014-09-26 21:58:48 +04:00
# ifdef CONFIG_NFS_V4_2
. llseek = nfs4_file_llseek ,
# else
2012-07-17 00:39:15 +04:00
. llseek = nfs_file_llseek ,
2014-09-26 21:58:48 +04:00
# endif
2014-04-03 04:14:12 +04:00
. read_iter = nfs_file_read ,
2014-04-03 22:07:25 +04:00
. write_iter = nfs_file_write ,
2012-07-17 00:39:15 +04:00
. mmap = nfs_file_mmap ,
. open = nfs4_file_open ,
. flush = nfs_file_flush ,
. release = nfs_file_release ,
. fsync = nfs4_file_fsync ,
. lock = nfs_lock ,
. flock = nfs_flock ,
. splice_read = nfs_file_splice_read ,
2014-04-05 12:37:17 +04:00
. splice_write = iter_file_splice_write ,
2014-11-25 21:18:15 +03:00
# ifdef CONFIG_NFS_V4_2
. fallocate = nfs42_fallocate ,
# endif /* CONFIG_NFS_V4_2 */
2012-07-17 00:39:15 +04:00
. check_flags = nfs_check_flags ,
2014-08-27 14:49:41 +04:00
. setlease = simple_nosetlease ,
2012-07-17 00:39:15 +04:00
} ;