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>
2015-09-25 21:24:36 +03:00
# include <linux/file.h>
2014-11-25 21:18:15 +03:00
# include <linux/falloc.h>
2012-07-17 00:39:15 +04:00
# include <linux/nfs_fs.h>
2015-11-13 11:38:48 +03:00
# include <uapi/linux/btrfs.h> /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
2015-09-06 02:06:58 +03:00
# include "delegation.h"
2012-07-17 00:39:15 +04:00
# include "internal.h"
2015-09-06 02:06:58 +03:00
# include "iostat.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 ;
2016-03-26 23:14:39 +03:00
struct dentry * dentry = file_dentry ( filp ) ;
2012-07-17 00:39:15 +04:00
struct dentry * parent = NULL ;
struct inode * dir ;
unsigned openflags = filp - > f_flags ;
struct iattr attr ;
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
2016-03-26 23:14:39 +03:00
ctx = alloc_nfs_open_context ( file_dentry ( filp ) , filp - > f_mode ) ;
2012-07-17 00:39:15 +04:00
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
}
2015-08-26 16:11:39 +03:00
inode = NFS_PROTO ( dir ) - > open_context ( dir , ctx , openflags , & attr , NULL ) ;
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 ;
}
2015-09-06 02:06:58 +03:00
/*
* Flush all dirty pages , and check for write errors .
*/
static int
nfs4_file_flush ( struct file * file , fl_owner_t id )
{
struct inode * inode = file_inode ( file ) ;
dprintk ( " NFS: flush(%pD2) \n " , file ) ;
nfs_inc_stats ( inode , NFSIOS_VFSFLUSH ) ;
if ( ( file - > f_mode & FMODE_WRITE ) = = 0 )
return 0 ;
/*
* If we ' re holding a write delegation , then check if we ' re required
* to flush the i / o on close . If not , then just start the i / o now .
*/
if ( ! nfs4_delegation_flush_on_close ( inode ) )
return filemap_fdatawrite ( file - > f_mapping ) ;
/* Flush writes to the server and return any errors */
return vfs_fsync ( file , 0 ) ;
}
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
}
2015-09-25 21:24:36 +03:00
2015-12-03 14:59:50 +03:00
static int nfs42_clone_file_range ( struct file * src_file , loff_t src_off ,
struct file * dst_file , loff_t dst_off , u64 count )
2015-09-25 21:24:36 +03:00
{
struct inode * dst_inode = file_inode ( dst_file ) ;
2015-09-25 21:24:38 +03:00
struct nfs_server * server = NFS_SERVER ( dst_inode ) ;
2015-12-03 14:59:50 +03:00
struct inode * src_inode = file_inode ( src_file ) ;
2015-09-25 21:24:38 +03:00
unsigned int bs = server - > clone_blksize ;
2015-11-13 11:38:47 +03:00
bool same_inode = false ;
2015-09-25 21:24:36 +03:00
int ret ;
2015-09-25 21:24:38 +03:00
/* check alignment w.r.t. clone_blksize */
ret = - EINVAL ;
if ( bs ) {
if ( ! IS_ALIGNED ( src_off , bs ) | | ! IS_ALIGNED ( dst_off , bs ) )
2015-12-03 14:59:50 +03:00
goto out ;
2015-09-25 21:24:38 +03:00
if ( ! IS_ALIGNED ( count , bs ) & & i_size_read ( src_inode ) ! = ( src_off + count ) )
2015-12-03 14:59:50 +03:00
goto out ;
2015-09-25 21:24:38 +03:00
}
2015-12-03 14:59:50 +03:00
if ( src_inode = = dst_inode )
same_inode = true ;
2015-11-13 11:38:47 +03:00
2015-09-25 21:24:36 +03:00
/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
2015-11-13 11:38:47 +03:00
if ( same_inode ) {
2016-01-22 23:40:57 +03:00
inode_lock ( src_inode ) ;
2015-11-13 11:38:47 +03:00
} else if ( dst_inode < src_inode ) {
2016-01-22 23:40:57 +03:00
inode_lock_nested ( dst_inode , I_MUTEX_PARENT ) ;
inode_lock_nested ( src_inode , I_MUTEX_CHILD ) ;
2015-09-25 21:24:36 +03:00
} else {
2016-01-22 23:40:57 +03:00
inode_lock_nested ( src_inode , I_MUTEX_PARENT ) ;
inode_lock_nested ( dst_inode , I_MUTEX_CHILD ) ;
2015-09-25 21:24:36 +03:00
}
/* flush all pending writes on both src and dst so that server
* has the latest data */
ret = nfs_sync_inode ( src_inode ) ;
if ( ret )
goto out_unlock ;
ret = nfs_sync_inode ( dst_inode ) ;
if ( ret )
goto out_unlock ;
2015-12-03 14:59:50 +03:00
ret = nfs42_proc_clone ( src_file , dst_file , src_off , dst_off , count ) ;
2015-09-25 21:24:36 +03:00
/* truncate inode page cache of the dst range so that future reads can fetch
* new data from server */
if ( ! ret )
truncate_inode_pages_range ( & dst_inode - > i_data , dst_off , dst_off + count - 1 ) ;
out_unlock :
2015-11-13 11:38:47 +03:00
if ( same_inode ) {
2016-01-22 23:40:57 +03:00
inode_unlock ( src_inode ) ;
2015-11-13 11:38:47 +03:00
} else if ( dst_inode < src_inode ) {
2016-01-22 23:40:57 +03:00
inode_unlock ( src_inode ) ;
inode_unlock ( dst_inode ) ;
2015-09-25 21:24:36 +03:00
} else {
2016-01-22 23:40:57 +03:00
inode_unlock ( dst_inode ) ;
inode_unlock ( src_inode ) ;
2015-09-25 21:24:36 +03:00
}
2015-12-03 14:59:50 +03:00
out :
2015-09-25 21:24:36 +03:00
return ret ;
}
2015-11-13 11:38:49 +03:00
# endif /* CONFIG_NFS_V4_2 */
2015-09-25 21:24:36 +03:00
2012-07-17 00:39:15 +04:00
const struct file_operations nfs4_file_operations = {
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 ,
2015-09-06 02:06:58 +03:00
. flush = nfs4_file_flush ,
2012-07-17 00:39:15 +04:00
. release = nfs_file_release ,
2016-03-02 19:35:54 +03:00
. fsync = nfs_file_fsync ,
2012-07-17 00:39:15 +04:00
. 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 ,
2014-08-27 14:49:41 +04:00
. setlease = simple_nosetlease ,
2015-11-13 11:38:49 +03:00
# ifdef CONFIG_NFS_V4_2
. llseek = nfs4_file_llseek ,
. fallocate = nfs42_fallocate ,
2015-12-03 14:59:50 +03:00
. clone_file_range = nfs42_clone_file_range ,
2015-11-13 11:38:49 +03:00
# else
. llseek = nfs_file_llseek ,
# endif
2012-07-17 00:39:15 +04:00
} ;