2015-07-17 17:38:12 +03:00
/*
* ( C ) 2001 Clemson University and The University of Chicago
*
* See COPYING in top - level directory .
*/
/*
* Linux VFS file operations .
*/
# include "protocol.h"
2015-12-04 20:56:14 +03:00
# include "orangefs-kernel.h"
# include "orangefs-bufmap.h"
2015-07-17 17:38:12 +03:00
# include <linux/fs.h>
# include <linux/pagemap.h>
2016-08-02 23:32:15 +03:00
static int flush_racache ( struct inode * inode )
{
struct orangefs_inode_s * orangefs_inode = ORANGEFS_I ( inode ) ;
struct orangefs_kernel_op_s * new_op ;
int ret ;
gossip_debug ( GOSSIP_UTILS_DEBUG ,
" %s: %pU: Handle is %pU | fs_id %d \n " , __func__ ,
get_khandle_from_ino ( inode ) , & orangefs_inode - > refn . khandle ,
orangefs_inode - > refn . fs_id ) ;
new_op = op_alloc ( ORANGEFS_VFS_OP_RA_FLUSH ) ;
if ( ! new_op )
return - ENOMEM ;
new_op - > upcall . req . ra_cache_flush . refn = orangefs_inode - > refn ;
ret = service_operation ( new_op , " orangefs_flush_racache " ,
get_interruptible_flag ( inode ) ) ;
gossip_debug ( GOSSIP_UTILS_DEBUG , " %s: got return value of %d \n " ,
__func__ , ret ) ;
op_release ( new_op ) ;
return ret ;
}
2015-07-17 17:38:12 +03:00
/*
* Copy to client - core ' s address space from the buffers specified
* by the iovec upto total_size bytes .
* NOTE : the iovector can either contain addresses which
* can futher be kernel - space or user - space addresses .
* or it can pointers to struct page ' s
*/
2016-02-17 04:06:19 +03:00
static int precopy_buffers ( int buffer_index ,
2015-10-09 00:54:31 +03:00
struct iov_iter * iter ,
2015-09-04 17:31:16 +03:00
size_t total_size )
2015-07-17 17:38:12 +03:00
{
int ret = 0 ;
/*
* copy data from application / kernel by pulling it out
* of the iovec .
*/
2015-09-04 17:31:16 +03:00
if ( total_size ) {
2016-02-17 04:06:19 +03:00
ret = orangefs_bufmap_copy_from_iovec ( iter ,
2015-11-24 23:12:14 +03:00
buffer_index ,
total_size ) ;
2015-09-04 17:31:16 +03:00
if ( ret < 0 )
gossip_err ( " %s: Failed to copy-in buffers. Please make sure that the pvfs2-client is running. %ld \n " ,
__func__ ,
( long ) ret ) ;
}
2015-07-17 17:38:12 +03:00
if ( ret < 0 )
gossip_err ( " %s: Failed to copy-in buffers. Please make sure that the pvfs2-client is running. %ld \n " ,
__func__ ,
( long ) ret ) ;
return ret ;
}
/*
* Copy from client - core ' s address space to the buffers specified
* by the iovec upto total_size bytes .
* NOTE : the iovector can either contain addresses which
* can futher be kernel - space or user - space addresses .
* or it can pointers to struct page ' s
*/
2016-02-17 04:06:19 +03:00
static int postcopy_buffers ( int buffer_index ,
2015-10-09 00:52:44 +03:00
struct iov_iter * iter ,
2015-09-04 17:31:16 +03:00
size_t total_size )
2015-07-17 17:38:12 +03:00
{
int ret = 0 ;
/*
* copy data to application / kernel by pushing it out to
* the iovec . NOTE ; target buffers can be addresses or
* struct page pointers .
*/
if ( total_size ) {
2016-02-17 04:06:19 +03:00
ret = orangefs_bufmap_copy_to_iovec ( iter ,
2015-11-24 23:12:14 +03:00
buffer_index ,
total_size ) ;
2015-07-17 17:38:12 +03:00
if ( ret < 0 )
2015-09-04 17:31:16 +03:00
gossip_err ( " %s: Failed to copy-out buffers. Please make sure that the pvfs2-client is running (%ld) \n " ,
2015-07-17 17:38:12 +03:00
__func__ ,
( long ) ret ) ;
}
return ret ;
}
/*
* Post and wait for the I / O upcall to finish
*/
2015-11-24 23:12:14 +03:00
static ssize_t wait_for_direct_io ( enum ORANGEFS_io_type type , struct inode * inode ,
2015-10-09 01:00:26 +03:00
loff_t * offset , struct iov_iter * iter ,
2015-09-04 17:31:16 +03:00
size_t total_size , loff_t readahead_size )
2015-07-17 17:38:12 +03:00
{
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * orangefs_inode = ORANGEFS_I ( inode ) ;
struct orangefs_khandle * handle = & orangefs_inode - > refn . khandle ;
struct orangefs_kernel_op_s * new_op = NULL ;
2016-02-07 09:25:06 +03:00
struct iov_iter saved = * iter ;
2015-07-17 17:38:12 +03:00
int buffer_index = - 1 ;
ssize_t ret ;
2015-11-24 23:12:14 +03:00
new_op = op_alloc ( ORANGEFS_VFS_OP_FILE_IO ) ;
2016-01-23 03:47:47 +03:00
if ( ! new_op )
return - ENOMEM ;
2015-07-17 17:38:12 +03:00
/* synchronous I/O */
new_op - > upcall . req . io . readahead_size = readahead_size ;
new_op - > upcall . req . io . io_type = type ;
2015-11-24 23:12:14 +03:00
new_op - > upcall . req . io . refn = orangefs_inode - > refn ;
2015-07-17 17:38:12 +03:00
populate_shared_memory :
/* get a shared buffer index */
2016-02-17 04:10:26 +03:00
buffer_index = orangefs_bufmap_get ( ) ;
if ( buffer_index < 0 ) {
ret = buffer_index ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
2016-02-17 04:10:26 +03:00
" %s: orangefs_bufmap_get failure (%zd) \n " ,
__func__ , ret ) ;
2015-07-17 17:38:12 +03:00
goto out ;
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): GET op %p -> buffer_index %d \n " ,
__func__ ,
handle ,
new_op ,
buffer_index ) ;
new_op - > uses_shared_memory = 1 ;
new_op - > upcall . req . io . buf_index = buffer_index ;
new_op - > upcall . req . io . count = total_size ;
new_op - > upcall . req . io . offset = * offset ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-10-09 01:00:26 +03:00
" %s(%pU): offset: %llu total_size: %zd \n " ,
2015-07-17 17:38:12 +03:00
__func__ ,
handle ,
llu ( * offset ) ,
total_size ) ;
/*
* Stage 1 : copy the buffers into client - core ' s address space
* precopy_buffers only pertains to writes .
*/
2015-11-24 23:12:14 +03:00
if ( type = = ORANGEFS_IO_WRITE ) {
2016-02-17 04:06:19 +03:00
ret = precopy_buffers ( buffer_index ,
2015-10-09 01:00:26 +03:00
iter ,
2015-09-04 17:31:16 +03:00
total_size ) ;
2015-07-17 17:38:12 +03:00
if ( ret < 0 )
goto out ;
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): Calling post_io_request with tag (%llu) \n " ,
__func__ ,
handle ,
llu ( new_op - > tag ) ) ;
/* Stage 2: Service the I/O operation */
ret = service_operation ( new_op ,
2015-11-24 23:12:14 +03:00
type = = ORANGEFS_IO_WRITE ?
2015-07-17 17:38:12 +03:00
" file_write " :
" file_read " ,
get_interruptible_flag ( inode ) ) ;
/*
* If service_operation ( ) returns - EAGAIN # and # the operation was
2015-11-24 23:12:14 +03:00
* purged from orangefs_request_list or htable_ops_in_progress , then
2015-07-17 17:38:12 +03:00
* we know that the client was restarted , causing the shared memory
* area to be wiped clean . To restart a write operation in this
* case , we must re - copy the data from the user ' s iovec to a NEW
* shared memory location . To restart a read operation , we must get
* a new shared memory location .
*/
if ( ret = = - EAGAIN & & op_state_purged ( new_op ) ) {
2016-02-12 05:34:52 +03:00
orangefs_bufmap_put ( buffer_index ) ;
2016-02-06 22:59:38 +03:00
buffer_index = - 1 ;
2016-02-07 09:25:06 +03:00
if ( type = = ORANGEFS_IO_WRITE )
* iter = saved ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s:going to repopulate_shared_memory. \n " ,
__func__ ) ;
goto populate_shared_memory ;
}
if ( ret < 0 ) {
2016-03-09 21:12:37 +03:00
if ( ret = = - EINTR ) {
/*
* We can ' t return EINTR if any data was written ,
* it ' s not POSIX . It is minimally acceptable
* to give a partial write , the way NFS does .
*
* It would be optimal to return all or nothing ,
* but if a userspace write is bigger than
* an IO buffer , and the interrupt occurs
* between buffer writes , that would not be
* possible .
*/
switch ( new_op - > op_state - OP_VFS_STATE_GIVEN_UP ) {
/*
* If the op was waiting when the interrupt
* occurred , then the client - core did not
* trigger the write .
*/
case OP_VFS_STATE_WAITING :
if ( * offset = = 0 )
ret = - EINTR ;
else
ret = 0 ;
break ;
/*
* If the op was in progress when the interrupt
* occurred , then the client - core was able to
* trigger the write .
*/
case OP_VFS_STATE_INPROGR :
ret = total_size ;
break ;
default :
gossip_err ( " %s: unexpected op state :%d:. \n " ,
__func__ ,
new_op - > op_state ) ;
ret = 0 ;
break ;
}
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
2016-03-09 21:12:37 +03:00
" %s: got EINTR, state:%d: %p \n " ,
__func__ ,
new_op - > op_state ,
new_op ) ;
} else {
2015-07-17 17:38:12 +03:00
gossip_err ( " %s: error in %s handle %pU, returning %zd \n " ,
__func__ ,
2015-11-24 23:12:14 +03:00
type = = ORANGEFS_IO_READ ?
2015-07-17 17:38:12 +03:00
" read from " : " write to " ,
handle , ret ) ;
2016-03-09 21:12:37 +03:00
}
2016-02-12 07:07:19 +03:00
if ( orangefs_cancel_op_in_progress ( new_op ) )
return ret ;
2016-02-14 05:06:50 +03:00
goto out ;
2015-07-17 17:38:12 +03:00
}
/*
* Stage 3 : Post copy buffers from client - core ' s address space
* postcopy_buffers only pertains to reads .
*/
2015-11-24 23:12:14 +03:00
if ( type = = ORANGEFS_IO_READ ) {
2016-02-17 04:06:19 +03:00
ret = postcopy_buffers ( buffer_index ,
2015-10-09 01:00:26 +03:00
iter ,
2015-09-04 17:31:16 +03:00
new_op - > downcall . resp . io . amt_complete ) ;
2016-02-12 05:28:52 +03:00
if ( ret < 0 )
2016-02-14 05:06:50 +03:00
goto out ;
2015-07-17 17:38:12 +03:00
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
2016-03-03 21:46:48 +03:00
" %s(%pU): Amount %s, returned by the sys-io call:%d \n " ,
2015-07-17 17:38:12 +03:00
__func__ ,
handle ,
2016-03-03 21:46:48 +03:00
type = = ORANGEFS_IO_READ ? " read " : " written " ,
2015-07-17 17:38:12 +03:00
( int ) new_op - > downcall . resp . io . amt_complete ) ;
ret = new_op - > downcall . resp . io . amt_complete ;
out :
if ( buffer_index > = 0 ) {
2016-02-12 05:34:52 +03:00
orangefs_bufmap_put ( buffer_index ) ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): PUT buffer_index %d \n " ,
__func__ , handle , buffer_index ) ;
buffer_index = - 1 ;
}
2016-01-23 03:47:47 +03:00
op_release ( new_op ) ;
2015-07-17 17:38:12 +03:00
return ret ;
}
/*
* Common entry point for read / write / readv / writev
* This function will dispatch it to either the direct I / O
* or buffered I / O path depending on the mount options and / or
* augmented / extended metadata attached to the file .
* Note : File extended attributes override any mount options .
*/
2015-11-24 23:12:14 +03:00
static ssize_t do_readv_writev ( enum ORANGEFS_io_type type , struct file * file ,
2015-10-09 01:22:08 +03:00
loff_t * offset , struct iov_iter * iter )
2015-07-17 17:38:12 +03:00
{
struct inode * inode = file - > f_mapping - > host ;
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * orangefs_inode = ORANGEFS_I ( inode ) ;
struct orangefs_khandle * handle = & orangefs_inode - > refn . khandle ;
2015-10-09 01:22:08 +03:00
size_t count = iov_iter_count ( iter ) ;
2015-10-09 01:17:26 +03:00
ssize_t total_count = 0 ;
ssize_t ret = - EINVAL ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s-BEGIN(%pU): count(%d) after estimate_max_iovecs. \n " ,
__func__ ,
handle ,
( int ) count ) ;
2015-11-24 23:12:14 +03:00
if ( type = = ORANGEFS_IO_WRITE ) {
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): proceeding with offset : %llu, "
" size %d \n " ,
__func__ ,
handle ,
llu ( * offset ) ,
( int ) count ) ;
}
if ( count = = 0 ) {
ret = 0 ;
goto out ;
}
2015-10-09 01:22:08 +03:00
while ( iov_iter_count ( iter ) ) {
size_t each_count = iov_iter_count ( iter ) ;
2015-07-17 17:38:12 +03:00
size_t amt_complete ;
/* how much to transfer in this loop iteration */
2015-11-24 23:12:14 +03:00
if ( each_count > orangefs_bufmap_size_query ( ) )
each_count = orangefs_bufmap_size_query ( ) ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): size of each_count(%d) \n " ,
__func__ ,
handle ,
( int ) each_count ) ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): BEFORE wait_for_io: offset is %d \n " ,
__func__ ,
handle ,
( int ) * offset ) ;
2015-10-09 01:22:08 +03:00
ret = wait_for_direct_io ( type , inode , offset , iter ,
2015-10-09 01:00:26 +03:00
each_count , 0 ) ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): return from wait_for_io:%d \n " ,
__func__ ,
handle ,
( int ) ret ) ;
if ( ret < 0 )
goto out ;
* offset + = ret ;
total_count + = ret ;
amt_complete = ret ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): AFTER wait_for_io: offset is %d \n " ,
__func__ ,
handle ,
( int ) * offset ) ;
/*
* if we got a short I / O operations ,
* fall out and return what we got so far
*/
if ( amt_complete < each_count )
break ;
} /*end while */
2016-02-17 04:15:43 +03:00
out :
2015-07-17 17:38:12 +03:00
if ( total_count > 0 )
ret = total_count ;
if ( ret > 0 ) {
2015-11-24 23:12:14 +03:00
if ( type = = ORANGEFS_IO_READ ) {
2015-07-17 17:38:12 +03:00
file_accessed ( file ) ;
} else {
2015-11-24 23:12:14 +03:00
SetMtimeFlag ( orangefs_inode ) ;
2016-09-14 17:48:04 +03:00
inode - > i_mtime = current_time ( inode ) ;
2015-07-17 17:38:12 +03:00
mark_inode_dirty_sync ( inode ) ;
}
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): Value(%d) returned. \n " ,
__func__ ,
handle ,
( int ) ret ) ;
return ret ;
}
/*
* Read data from a specified offset in a file ( referenced by inode ) .
* Data may be placed either in a user or kernel buffer .
*/
2015-11-24 23:12:14 +03:00
ssize_t orangefs_inode_read ( struct inode * inode ,
struct iov_iter * iter ,
loff_t * offset ,
loff_t readahead_size )
2015-07-17 17:38:12 +03:00
{
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * orangefs_inode = ORANGEFS_I ( inode ) ;
2015-10-09 01:31:05 +03:00
size_t count = iov_iter_count ( iter ) ;
2015-07-17 17:38:12 +03:00
size_t bufmap_size ;
ssize_t ret = - EINVAL ;
2016-08-15 22:33:42 +03:00
orangefs_stats . reads + + ;
2015-07-17 17:38:12 +03:00
2015-11-24 23:12:14 +03:00
bufmap_size = orangefs_bufmap_size_query ( ) ;
2015-07-17 17:38:12 +03:00
if ( count > bufmap_size ) {
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s: count is too large (%zd/%zd)! \n " ,
__func__ , count , bufmap_size ) ;
return - EINVAL ;
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU) %zd@%llu \n " ,
__func__ ,
2015-11-24 23:12:14 +03:00
& orangefs_inode - > refn . khandle ,
2015-07-17 17:38:12 +03:00
count ,
llu ( * offset ) ) ;
2015-11-24 23:12:14 +03:00
ret = wait_for_direct_io ( ORANGEFS_IO_READ , inode , offset , iter ,
2015-09-04 17:31:16 +03:00
count , readahead_size ) ;
2015-07-17 17:38:12 +03:00
if ( ret > 0 )
* offset + = ret ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): Value(%zd) returned. \n " ,
__func__ ,
2015-11-24 23:12:14 +03:00
& orangefs_inode - > refn . khandle ,
2015-07-17 17:38:12 +03:00
ret ) ;
return ret ;
}
2015-11-24 23:12:14 +03:00
static ssize_t orangefs_file_read_iter ( struct kiocb * iocb , struct iov_iter * iter )
2015-07-17 17:38:12 +03:00
{
struct file * file = iocb - > ki_filp ;
loff_t pos = * ( & iocb - > ki_pos ) ;
ssize_t rc = 0 ;
BUG_ON ( iocb - > private ) ;
2015-11-24 23:12:14 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG , " orangefs_file_read_iter \n " ) ;
2015-07-17 17:38:12 +03:00
2016-08-15 22:33:42 +03:00
orangefs_stats . reads + + ;
2015-07-17 17:38:12 +03:00
2015-11-24 23:12:14 +03:00
rc = do_readv_writev ( ORANGEFS_IO_READ , file , & pos , iter ) ;
2015-07-17 17:38:12 +03:00
iocb - > ki_pos = pos ;
return rc ;
}
2015-11-24 23:12:14 +03:00
static ssize_t orangefs_file_write_iter ( struct kiocb * iocb , struct iov_iter * iter )
2015-07-17 17:38:12 +03:00
{
struct file * file = iocb - > ki_filp ;
2015-11-13 21:05:11 +03:00
loff_t pos ;
2015-07-17 17:38:12 +03:00
ssize_t rc ;
BUG_ON ( iocb - > private ) ;
2015-11-24 23:12:14 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG , " orangefs_file_write_iter \n " ) ;
2015-07-17 17:38:12 +03:00
2016-04-12 07:43:20 +03:00
inode_lock ( file - > f_mapping - > host ) ;
2015-07-17 17:38:12 +03:00
/* Make sure generic_write_checks sees an up to date inode size. */
if ( file - > f_flags & O_APPEND ) {
2016-03-15 19:33:20 +03:00
rc = orangefs_inode_getattr ( file - > f_mapping - > host , 0 , 1 ) ;
if ( rc = = - ESTALE )
rc = - EIO ;
2015-07-17 17:38:12 +03:00
if ( rc ) {
2016-03-15 19:33:20 +03:00
gossip_err ( " %s: orangefs_inode_getattr failed, "
" rc:%zd:. \n " , __func__ , rc ) ;
2015-07-17 17:38:12 +03:00
goto out ;
}
}
if ( file - > f_pos > i_size_read ( file - > f_mapping - > host ) )
2015-11-24 23:12:14 +03:00
orangefs_i_size_write ( file - > f_mapping - > host , file - > f_pos ) ;
2015-07-17 17:38:12 +03:00
rc = generic_write_checks ( iocb , iter ) ;
if ( rc < = 0 ) {
gossip_err ( " %s: generic_write_checks failed, rc:%zd:. \n " ,
__func__ , rc ) ;
goto out ;
}
2015-11-13 21:05:11 +03:00
/*
* if we are appending , generic_write_checks would have updated
* pos to the end of the file , so we will wait till now to set
* pos . . .
*/
pos = * ( & iocb - > ki_pos ) ;
2015-11-24 23:12:14 +03:00
rc = do_readv_writev ( ORANGEFS_IO_WRITE ,
2015-07-17 17:38:12 +03:00
file ,
& pos ,
2015-10-09 01:22:08 +03:00
iter ) ;
2015-07-17 17:38:12 +03:00
if ( rc < 0 ) {
gossip_err ( " %s: do_readv_writev failed, rc:%zd:. \n " ,
__func__ , rc ) ;
goto out ;
}
iocb - > ki_pos = pos ;
2016-08-15 22:33:42 +03:00
orangefs_stats . writes + + ;
2015-07-17 17:38:12 +03:00
out :
2016-04-12 07:43:20 +03:00
inode_unlock ( file - > f_mapping - > host ) ;
2015-07-17 17:38:12 +03:00
return rc ;
}
/*
* Perform a miscellaneous operation on a file .
*/
2015-11-24 23:12:14 +03:00
static long orangefs_ioctl ( struct file * file , unsigned int cmd , unsigned long arg )
2015-07-17 17:38:12 +03:00
{
int ret = - ENOTTY ;
__u64 val = 0 ;
unsigned long uval ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" orangefs_ioctl: called with cmd %d \n " ,
2015-07-17 17:38:12 +03:00
cmd ) ;
/*
* we understand some general ioctls on files , such as the immutable
* and append flags
*/
if ( cmd = = FS_IOC_GETFLAGS ) {
val = 0 ;
2015-11-24 23:12:14 +03:00
ret = orangefs_inode_getxattr ( file_inode ( file ) ,
" user.pvfs2.meta_hint " ,
& val , sizeof ( val ) ) ;
2015-07-17 17:38:12 +03:00
if ( ret < 0 & & ret ! = - ENODATA )
return ret ;
else if ( ret = = - ENODATA )
val = 0 ;
uval = val ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" orangefs_ioctl: FS_IOC_GETFLAGS: %llu \n " ,
2015-07-17 17:38:12 +03:00
( unsigned long long ) uval ) ;
return put_user ( uval , ( int __user * ) arg ) ;
} else if ( cmd = = FS_IOC_SETFLAGS ) {
ret = 0 ;
if ( get_user ( uval , ( int __user * ) arg ) )
return - EFAULT ;
/*
2015-11-24 23:12:14 +03:00
* ORANGEFS_MIRROR_FL is set internally when the mirroring mode
2015-07-17 17:38:12 +03:00
* is turned on for a file . The user is not allowed to turn
* on this bit , but the bit is present if the user first gets
* the flags and then updates the flags with some new
* settings . So , we ignore it in the following edit . bligon .
*/
2015-11-24 23:12:14 +03:00
if ( ( uval & ~ ORANGEFS_MIRROR_FL ) &
2015-07-17 17:38:12 +03:00
( ~ ( FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NOATIME_FL ) ) ) {
2015-11-24 23:12:14 +03:00
gossip_err ( " orangefs_ioctl: the FS_IOC_SETFLAGS only supports setting one of FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NOATIME_FL \n " ) ;
2015-07-17 17:38:12 +03:00
return - EINVAL ;
}
val = uval ;
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" orangefs_ioctl: FS_IOC_SETFLAGS: %llu \n " ,
2015-07-17 17:38:12 +03:00
( unsigned long long ) val ) ;
2015-11-24 23:12:14 +03:00
ret = orangefs_inode_setxattr ( file_inode ( file ) ,
" user.pvfs2.meta_hint " ,
& val , sizeof ( val ) , 0 ) ;
2015-07-17 17:38:12 +03:00
}
return ret ;
}
/*
* Memory map a region of a file .
*/
2015-11-24 23:12:14 +03:00
static int orangefs_file_mmap ( struct file * file , struct vm_area_struct * vma )
2015-07-17 17:38:12 +03:00
{
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" orangefs_file_mmap: called on %s \n " ,
2015-07-17 17:38:12 +03:00
( file ?
( char * ) file - > f_path . dentry - > d_name . name :
( char * ) " Unknown " ) ) ;
/* set the sequential readahead hint */
vma - > vm_flags | = VM_SEQ_READ ;
vma - > vm_flags & = ~ VM_RAND_READ ;
2015-09-30 20:11:54 +03:00
/* Use readonly mmap since we cannot support writable maps. */
return generic_file_readonly_mmap ( file , vma ) ;
2015-07-17 17:38:12 +03:00
}
# define mapping_nrpages(idata) ((idata)->nrpages)
/*
* Called to notify the module that there are no more references to
* this file ( i . e . no processes have it open ) .
*
* \ note Not called when each file is closed .
*/
2015-11-24 23:12:14 +03:00
static int orangefs_file_release ( struct inode * inode , struct file * file )
2015-07-17 17:38:12 +03:00
{
gossip_debug ( GOSSIP_FILE_DEBUG ,
2016-08-07 19:20:01 +03:00
" orangefs_file_release: called on %pD \n " ,
file ) ;
2015-07-17 17:38:12 +03:00
2015-11-24 23:12:14 +03:00
orangefs_flush_inode ( inode ) ;
2015-07-17 17:38:12 +03:00
/*
2016-08-02 21:31:05 +03:00
* remove all associated inode pages from the page cache and
2015-10-05 20:44:24 +03:00
* readahead cache ( if any ) ; this forces an expensive refresh of
* data for the next caller of mmap ( or ' get_block ' accesses )
2015-07-17 17:38:12 +03:00
*/
2016-10-21 07:33:57 +03:00
if ( file_inode ( file ) & &
file_inode ( file ) - > i_mapping & &
mapping_nrpages ( & file_inode ( file ) - > i_data ) ) {
2016-08-12 23:12:09 +03:00
if ( orangefs_features & ORANGEFS_FEATURE_READAHEAD ) {
gossip_debug ( GOSSIP_INODE_DEBUG ,
" calling flush_racache on %pU \n " ,
get_khandle_from_ino ( inode ) ) ;
flush_racache ( inode ) ;
gossip_debug ( GOSSIP_INODE_DEBUG ,
" flush_racache finished \n " ) ;
}
2016-10-21 07:33:57 +03:00
truncate_inode_pages ( file_inode ( file ) - > i_mapping ,
2015-07-17 17:38:12 +03:00
0 ) ;
2016-08-02 23:32:15 +03:00
}
2015-07-17 17:38:12 +03:00
return 0 ;
}
/*
* Push all data for a specific file onto permanent storage .
*/
2015-11-24 23:12:14 +03:00
static int orangefs_fsync ( struct file * file ,
2015-07-28 20:27:51 +03:00
loff_t start ,
loff_t end ,
int datasync )
2015-07-17 17:38:12 +03:00
{
int ret = - EINVAL ;
2015-11-24 23:12:14 +03:00
struct orangefs_inode_s * orangefs_inode =
2016-10-21 07:33:57 +03:00
ORANGEFS_I ( file_inode ( file ) ) ;
2015-11-24 23:12:14 +03:00
struct orangefs_kernel_op_s * new_op = NULL ;
2015-07-17 17:38:12 +03:00
/* required call */
filemap_write_and_wait_range ( file - > f_mapping , start , end ) ;
2015-11-24 23:12:14 +03:00
new_op = op_alloc ( ORANGEFS_VFS_OP_FSYNC ) ;
2015-07-17 17:38:12 +03:00
if ( ! new_op )
return - ENOMEM ;
2015-11-24 23:12:14 +03:00
new_op - > upcall . req . fsync . refn = orangefs_inode - > refn ;
2015-07-17 17:38:12 +03:00
ret = service_operation ( new_op ,
2015-11-24 23:12:14 +03:00
" orangefs_fsync " ,
2016-10-21 07:33:57 +03:00
get_interruptible_flag ( file_inode ( file ) ) ) ;
2015-07-17 17:38:12 +03:00
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" orangefs_fsync got return value of %d \n " ,
2015-07-17 17:38:12 +03:00
ret ) ;
op_release ( new_op ) ;
2016-10-21 07:33:57 +03:00
orangefs_flush_inode ( file_inode ( file ) ) ;
2015-07-17 17:38:12 +03:00
return ret ;
}
/*
* Change the file pointer position for an instance of an open file .
*
* \ note If . llseek is overriden , we must acquire lock as described in
* Documentation / filesystems / Locking .
*
* Future upgrade could support SEEK_DATA and SEEK_HOLE but would
* require much changes to the FS
*/
2015-11-24 23:12:14 +03:00
static loff_t orangefs_file_llseek ( struct file * file , loff_t offset , int origin )
2015-07-17 17:38:12 +03:00
{
int ret = - EINVAL ;
2016-02-17 04:25:19 +03:00
struct inode * inode = file_inode ( file ) ;
2015-07-17 17:38:12 +03:00
2016-02-17 04:25:19 +03:00
if ( origin = = SEEK_END ) {
2015-07-17 17:38:12 +03:00
/*
* revalidate the inode ' s file size .
* NOTE : We are only interested in file size here ,
* so we set mask accordingly .
*/
2016-03-15 19:33:20 +03:00
ret = orangefs_inode_getattr ( file - > f_mapping - > host , 0 , 1 ) ;
if ( ret = = - ESTALE )
ret = - EIO ;
2015-07-17 17:38:12 +03:00
if ( ret ) {
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s:%s:%d calling make bad inode \n " ,
__FILE__ ,
__func__ ,
__LINE__ ) ;
return ret ;
}
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" orangefs_file_llseek: offset is %ld | origin is %d "
2015-10-05 20:44:24 +03:00
" | inode size is %lu \n " ,
2015-07-17 17:38:12 +03:00
( long ) offset ,
origin ,
2016-02-17 04:25:19 +03:00
( unsigned long ) i_size_read ( inode ) ) ;
2015-07-17 17:38:12 +03:00
return generic_file_llseek ( file , offset , origin ) ;
}
/*
* Support local locks ( locks that only this kernel knows about )
* if Orangefs was mounted - o local_lock .
*/
2015-11-24 23:12:14 +03:00
static int orangefs_lock ( struct file * filp , int cmd , struct file_lock * fl )
2015-07-17 17:38:12 +03:00
{
2015-09-24 19:53:05 +03:00
int rc = - EINVAL ;
2015-07-17 17:38:12 +03:00
2016-12-05 02:24:56 +03:00
if ( ORANGEFS_SB ( file_inode ( filp ) - > i_sb ) - > flags & ORANGEFS_OPT_LOCAL_LOCK ) {
2015-07-17 17:38:12 +03:00
if ( cmd = = F_GETLK ) {
rc = 0 ;
posix_test_lock ( filp , fl ) ;
} else {
rc = posix_lock_file ( filp , fl , NULL ) ;
}
}
return rc ;
}
2015-11-24 23:12:14 +03:00
/** ORANGEFS implementation of VFS file operations */
const struct file_operations orangefs_file_operations = {
. llseek = orangefs_file_llseek ,
. read_iter = orangefs_file_read_iter ,
. write_iter = orangefs_file_write_iter ,
. lock = orangefs_lock ,
. unlocked_ioctl = orangefs_ioctl ,
. mmap = orangefs_file_mmap ,
2015-07-17 17:38:12 +03:00
. open = generic_file_open ,
2015-11-24 23:12:14 +03:00
. release = orangefs_file_release ,
. fsync = orangefs_fsync ,
2015-07-17 17:38:12 +03:00
} ;