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"
# include "pvfs2-kernel.h"
# include "pvfs2-bufmap.h"
# include <linux/fs.h>
# include <linux/pagemap.h>
# define wake_up_daemon_for_return(op) \
do { \
spin_lock ( & op - > lock ) ; \
op - > io_completed = 1 ; \
spin_unlock ( & op - > lock ) ; \
wake_up_interruptible ( & op - > io_completion_waitq ) ; \
} while ( 0 )
/*
* 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
*/
2015-11-24 23:12:14 +03:00
static int precopy_buffers ( struct orangefs_bufmap * bufmap ,
2015-07-17 17:38:12 +03:00
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 ) {
2015-11-24 23:12:14 +03:00
ret = orangefs_bufmap_copy_from_iovec ( bufmap ,
iter ,
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
*/
2015-11-24 23:12:14 +03:00
static int postcopy_buffers ( struct orangefs_bufmap * bufmap ,
2015-07-17 17:38:12 +03:00
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 ) {
2015-11-24 23:12:14 +03:00
ret = orangefs_bufmap_copy_to_iovec ( bufmap ,
iter ,
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_bufmap * bufmap = NULL ;
struct orangefs_kernel_op_s * new_op = NULL ;
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 ) ;
2015-07-17 17:38:12 +03:00
if ( ! new_op ) {
ret = - ENOMEM ;
goto out ;
}
/* synchronous I/O */
2015-11-24 23:12:14 +03:00
new_op - > upcall . req . io . async_vfs_io = ORANGEFS_VFS_SYNC_IO ;
2015-07-17 17:38:12 +03:00
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 */
2015-11-24 23:12:14 +03:00
ret = orangefs_bufmap_get ( & bufmap , & buffer_index ) ;
2015-07-17 17:38:12 +03:00
if ( ret < 0 ) {
gossip_debug ( GOSSIP_FILE_DEBUG ,
2015-11-24 23:12:14 +03:00
" %s: orangefs_bufmap_get failure (%ld) \n " ,
2015-07-17 17:38:12 +03:00
__func__ , ( long ) ret ) ;
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 ) {
2015-07-17 17:38:12 +03:00
ret = precopy_buffers ( bufmap ,
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 ) ) {
2015-11-24 23:12:14 +03:00
orangefs_bufmap_put ( bufmap , buffer_index ) ;
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 ) {
handle_io_error ( ) ; /* defined in pvfs2-kernel.h */
/*
2015-10-05 20:44:24 +03:00
* don ' t write an error to syslog on signaled operation
* termination unless we ' ve got debugging turned on , as
* this can happen regularly ( i . e . ctrl - c )
2015-07-17 17:38:12 +03:00
*/
if ( ret = = - EINTR )
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s: returning error %ld \n " , __func__ ,
( long ) ret ) ;
else
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 ) ;
goto out ;
}
/*
* 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 ) {
2015-07-17 17:38:12 +03:00
ret = postcopy_buffers ( bufmap ,
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 ) ;
2015-07-17 17:38:12 +03:00
if ( ret < 0 ) {
/*
* put error codes in downcall so that handle_io_error ( )
* preserves it properly
*/
new_op - > downcall . status = ret ;
handle_io_error ( ) ;
goto out ;
}
}
gossip_debug ( GOSSIP_FILE_DEBUG ,
" %s(%pU): Amount written as returned by the sys-io call:%d \n " ,
__func__ ,
handle ,
( int ) new_op - > downcall . resp . io . amt_complete ) ;
ret = new_op - > downcall . resp . io . amt_complete ;
/*
2015-10-05 20:44:24 +03:00
* tell the device file owner waiting on I / O that this read has
* completed and it can return now . in this exact case , on
* wakeup the daemon will free the op , so we * cannot * touch it
* after this .
2015-07-17 17:38:12 +03:00
*/
wake_up_daemon_for_return ( new_op ) ;
new_op = NULL ;
out :
if ( buffer_index > = 0 ) {
2015-11-24 23:12:14 +03:00
orangefs_bufmap_put ( bufmap , 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 ;
}
if ( new_op ) {
op_release ( new_op ) ;
new_op = NULL ;
}
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 */
if ( total_count > 0 )
ret = total_count ;
out :
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 ) ;
2015-07-17 17:38:12 +03:00
inode - > i_mtime = CURRENT_TIME ;
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 ;
2015-11-24 23:12:14 +03:00
g_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
2015-11-24 23:12:14 +03:00
g_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
mutex_lock ( & file - > f_mapping - > host - > i_mutex ) ;
/* Make sure generic_write_checks sees an up to date inode size. */
if ( file - > f_flags & O_APPEND ) {
2015-11-24 23:12:14 +03:00
rc = orangefs_inode_getattr ( file - > f_mapping - > host ,
ORANGEFS_ATTR_SYS_SIZE ) ;
2015-07-17 17:38:12 +03:00
if ( rc ) {
2015-11-24 23:12:14 +03:00
gossip_err ( " %s: orangefs_inode_getattr failed, rc:%zd:. \n " ,
2015-07-17 17:38:12 +03:00
__func__ , rc ) ;
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 ;
2015-11-24 23:12:14 +03:00
g_orangefs_stats . writes + + ;
2015-07-17 17:38:12 +03:00
out :
mutex_unlock ( & file - > f_mapping - > host - > i_mutex ) ;
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 ) ,
ORANGEFS_XATTR_NAME_DEFAULT_PREFIX ,
" 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 ) ,
ORANGEFS_XATTR_NAME_DEFAULT_PREFIX ,
" 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 ,
2015-11-24 23:12:14 +03:00
" orangefs_file_release: called on %s \n " ,
2015-07-17 17:38:12 +03:00
file - > f_path . dentry - > d_name . name ) ;
2015-11-24 23:12:14 +03:00
orangefs_flush_inode ( inode ) ;
2015-07-17 17:38:12 +03:00
/*
2015-10-05 20:44:24 +03:00
* remove all associated inode pages from the page cache and mmap
* 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
*/
if ( file - > f_path . dentry - > d_inode & &
file - > f_path . dentry - > d_inode - > i_mapping & &
mapping_nrpages ( & file - > f_path . dentry - > d_inode - > i_data ) )
truncate_inode_pages ( file - > f_path . dentry - > d_inode - > i_mapping ,
0 ) ;
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 =
ORANGEFS_I ( file - > f_path . dentry - > d_inode ) ;
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 " ,
2015-07-17 17:38:12 +03:00
get_interruptible_flag ( file - > f_path . dentry - > d_inode ) ) ;
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 ) ;
2015-11-24 23:12:14 +03:00
orangefs_flush_inode ( file - > f_path . dentry - > d_inode ) ;
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 ;
struct inode * inode = file - > f_path . dentry - > d_inode ;
if ( ! inode ) {
2015-11-24 23:12:14 +03:00
gossip_err ( " orangefs_file_llseek: invalid inode (NULL) \n " ) ;
2015-07-17 17:38:12 +03:00
return ret ;
}
2015-11-24 23:12:14 +03:00
if ( origin = = ORANGEFS_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 .
*/
2015-11-24 23:12:14 +03:00
ret = orangefs_inode_getattr ( inode , ORANGEFS_ATTR_SYS_SIZE ) ;
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__ ) ;
2015-11-24 23:12:14 +03:00
orangefs_make_bad_inode ( inode ) ;
2015-07-17 17:38:12 +03:00
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 ,
( unsigned long ) file - > f_path . dentry - > d_inode - > i_size ) ;
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
2015-11-24 23:12:14 +03:00
if ( ORANGEFS_SB ( filp - > f_inode - > 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
} ;