2012-07-17 00:39:15 +04:00
/*
* linux / fs / nfs / file . c
*
* Copyright ( C ) 1992 Rick Sladkey
*/
# 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"
# 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
if ( ( openflags & O_ACCMODE ) = = 3 )
openflags - - ;
/* We can't create new files here */
openflags & = ~ ( O_CREAT | O_EXCL ) ;
parent = dget_parent ( dentry ) ;
dir = parent - > d_inode ;
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 ;
nfs_wb_all ( inode ) ;
}
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 ;
}
}
if ( inode ! = dentry - > d_inode )
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
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 )
2012-09-12 00:01:22 +04:00
ret = pnfs_layoutcommit_inode ( inode , true ) ;
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 ) ;
2012-07-17 00:39:15 +04:00
return ret ;
}
const struct file_operations nfs4_file_operations = {
. llseek = nfs_file_llseek ,
2014-04-03 04:14:12 +04:00
. read = new_sync_read ,
2014-04-03 22:07:25 +04:00
. write = new_sync_write ,
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 ,
2012-07-17 00:39:15 +04:00
. check_flags = nfs_check_flags ,
. setlease = nfs_setlease ,
} ;