2005-04-17 02:20:36 +04:00
/*
* file . c
*
* PURPOSE
* File handling routines for the OSTA - UDF ( tm ) filesystem .
*
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License ( GPL ) . Copies of the GPL can be obtained from :
* ftp : //prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work .
*
* ( C ) 1998 - 1999 Dave Boynton
* ( C ) 1998 - 2004 Ben Fennema
* ( C ) 1999 - 2000 Stelias Computing Inc
*
* HISTORY
*
* 10 / 02 / 98 dgb Attempt to integrate into udf . o
* 10 / 07 / 98 Switched to using generic_readpage , etc . , like isofs
* And it works !
* 12 / 06 / 98 blf Added udf_file_read . uses generic_file_read for all cases but
* ICBTAG_FLAG_AD_IN_ICB .
* 04 / 06 / 99 64 bit file handling on 32 bit systems taken from ext2 file . c
* 05 / 12 / 99 Preliminary file write support
*/
# include "udfdecl.h"
# include <linux/fs.h>
2014-06-18 21:38:24 +04:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
2007-07-21 15:37:18 +04:00
# include <linux/string.h> /* memset */
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2005-04-17 02:20:36 +04:00
# include <linux/errno.h>
# include <linux/pagemap.h>
2015-02-22 19:58:50 +03:00
# include <linux/uio.h>
2005-04-17 02:20:36 +04:00
# include "udf_i.h"
# include "udf_sb.h"
2012-09-05 17:48:23 +04:00
static void __udf_adinicb_readpage ( struct page * page )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = page - > mapping - > host ;
char * kaddr ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
kaddr = kmap ( page ) ;
2008-02-08 15:20:44 +03:00
memcpy ( kaddr , iinfo - > i_ext . i_data + iinfo - > i_lenEAttr , inode - > i_size ) ;
2012-09-05 17:48:23 +04:00
memset ( kaddr + inode - > i_size , 0 , PAGE_CACHE_SIZE - inode - > i_size ) ;
2005-04-17 02:20:36 +04:00
flush_dcache_page ( page ) ;
SetPageUptodate ( page ) ;
kunmap ( page ) ;
2012-09-05 17:48:23 +04:00
}
static int udf_adinicb_readpage ( struct file * file , struct page * page )
{
BUG_ON ( ! PageLocked ( page ) ) ;
__udf_adinicb_readpage ( page ) ;
2005-04-17 02:20:36 +04:00
unlock_page ( page ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-02-08 15:20:36 +03:00
static int udf_adinicb_writepage ( struct page * page ,
struct writeback_control * wbc )
2005-04-17 02:20:36 +04:00
{
struct inode * inode = page - > mapping - > host ;
char * kaddr ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
2005-05-01 19:59:01 +04:00
BUG_ON ( ! PageLocked ( page ) ) ;
2005-04-17 02:20:36 +04:00
kaddr = kmap ( page ) ;
2008-02-08 15:20:44 +03:00
memcpy ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr , kaddr , inode - > i_size ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
SetPageUptodate ( page ) ;
kunmap ( page ) ;
unlock_page ( page ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2012-09-05 17:48:23 +04:00
static int udf_adinicb_write_begin ( struct file * file ,
struct address_space * mapping , loff_t pos ,
unsigned len , unsigned flags , struct page * * pagep ,
void * * fsdata )
{
struct page * page ;
if ( WARN_ON_ONCE ( pos > = PAGE_CACHE_SIZE ) )
return - EIO ;
page = grab_cache_page_write_begin ( mapping , 0 , flags ) ;
if ( ! page )
return - ENOMEM ;
* pagep = page ;
if ( ! PageUptodate ( page ) & & len ! = PAGE_CACHE_SIZE )
__udf_adinicb_readpage ( page ) ;
return 0 ;
}
2015-03-16 14:33:53 +03:00
static ssize_t udf_adinicb_direct_IO ( struct kiocb * iocb , struct iov_iter * iter ,
2014-03-05 06:27:34 +04:00
loff_t offset )
2012-09-05 20:44:31 +04:00
{
/* Fallback to buffered I/O. */
return 0 ;
}
2006-06-28 15:26:44 +04:00
const struct address_space_operations udf_adinicb_aops = {
2007-07-21 15:37:18 +04:00
. readpage = udf_adinicb_readpage ,
. writepage = udf_adinicb_writepage ,
2012-09-05 17:48:23 +04:00
. write_begin = udf_adinicb_write_begin ,
2014-07-15 05:38:51 +04:00
. write_end = simple_write_end ,
2012-09-05 20:44:31 +04:00
. direct_IO = udf_adinicb_direct_IO ,
2005-04-17 02:20:36 +04:00
} ;
2014-04-03 11:31:17 +04:00
static ssize_t udf_file_write_iter ( struct kiocb * iocb , struct iov_iter * from )
2005-04-17 02:20:36 +04:00
{
ssize_t retval ;
2006-10-01 10:28:48 +04:00
struct file * file = iocb - > ki_filp ;
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( file ) ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2015-04-07 22:26:36 +03:00
int err ;
2005-04-17 02:20:36 +04:00
2014-02-18 15:00:21 +04:00
mutex_lock ( & inode - > i_mutex ) ;
2015-04-07 22:26:36 +03:00
2015-04-09 19:55:47 +03:00
retval = generic_write_checks ( iocb , from ) ;
if ( retval < = 0 )
2015-04-07 22:26:36 +03:00
goto out ;
2010-11-16 16:33:48 +03:00
down_write ( & iinfo - > i_data_sem ) ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
2015-04-07 22:26:36 +03:00
loff_t end = iocb - > ki_pos + iov_iter_count ( from ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
if ( inode - > i_sb - > s_blocksize <
2015-04-07 22:26:36 +03:00
( udf_file_entry_alloc_offset ( inode ) + end ) ) {
2010-10-22 02:30:26 +04:00
err = udf_expand_file_adinicb ( inode ) ;
if ( err ) {
2014-02-18 15:00:21 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
udf_debug ( " udf_expand_adinicb: err=%d \n " , err ) ;
return err ;
}
2007-07-19 12:47:43 +04:00
} else {
2015-04-07 22:26:36 +03:00
iinfo - > i_lenAlloc = max ( end , inode - > i_size ) ;
2011-12-10 05:30:48 +04:00
up_write ( & iinfo - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
}
2011-12-10 05:30:48 +04:00
} else
up_write ( & iinfo - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
2014-04-03 11:31:17 +04:00
retval = __generic_file_write_iter ( iocb , from ) ;
2015-04-07 18:28:12 +03:00
out :
2014-02-18 15:00:21 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
if ( retval > 0 ) {
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2014-02-18 15:00:21 +04:00
err = generic_write_sync ( file , iocb - > ki_pos - retval , retval ) ;
if ( err < 0 )
retval = err ;
}
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return retval ;
}
2010-05-05 17:15:39 +04:00
long udf_ioctl ( struct file * filp , unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2013-01-24 02:07:38 +04:00
struct inode * inode = file_inode ( filp ) ;
2007-07-21 15:37:18 +04:00
long old_block , new_block ;
2005-04-17 02:20:36 +04:00
int result = - EINVAL ;
2011-06-19 19:49:08 +04:00
if ( inode_permission ( inode , MAY_READ ) ! = 0 ) {
2010-05-05 17:15:39 +04:00
udf_debug ( " no permission to access inode %lu \n " , inode - > i_ino ) ;
result = - EPERM ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( ! arg ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " invalid argument to udf_ioctl \n " ) ;
2010-05-05 17:15:39 +04:00
result = - EINVAL ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
switch ( cmd ) {
case UDF_GETVOLIDENT :
2008-02-08 15:20:36 +03:00
if ( copy_to_user ( ( char __user * ) arg ,
UDF_SB ( inode - > i_sb ) - > s_volume_ident , 32 ) )
2010-05-05 17:15:39 +04:00
result = - EFAULT ;
2008-02-08 15:20:36 +03:00
else
2010-05-05 17:15:39 +04:00
result = 0 ;
goto out ;
2007-07-19 12:47:43 +04:00
case UDF_RELOCATE_BLOCKS :
2010-05-05 17:15:39 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) ) {
2013-02-20 06:13:55 +04:00
result = - EPERM ;
2010-05-05 17:15:39 +04:00
goto out ;
}
if ( get_user ( old_block , ( long __user * ) arg ) ) {
result = - EFAULT ;
goto out ;
}
2008-02-08 15:20:36 +03:00
result = udf_relocate_blocks ( inode - > i_sb ,
old_block , & new_block ) ;
if ( result = = 0 )
2007-07-21 15:37:18 +04:00
result = put_user ( new_block , ( long __user * ) arg ) ;
2010-05-05 17:15:39 +04:00
goto out ;
2007-07-19 12:47:43 +04:00
case UDF_GETEASIZE :
2008-02-08 15:20:42 +03:00
result = put_user ( UDF_I ( inode ) - > i_lenEAttr , ( int __user * ) arg ) ;
2010-05-05 17:15:39 +04:00
goto out ;
2007-07-19 12:47:43 +04:00
case UDF_GETEABLOCK :
2008-02-08 15:20:42 +03:00
result = copy_to_user ( ( char __user * ) arg ,
UDF_I ( inode ) - > i_ext . i_data ,
UDF_I ( inode ) - > i_lenEAttr ) ? - EFAULT : 0 ;
2010-05-05 17:15:39 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2010-05-05 17:15:39 +04:00
out :
2005-04-17 02:20:36 +04:00
return result ;
}
2007-07-19 12:47:43 +04:00
static int udf_release_file ( struct inode * inode , struct file * filp )
2005-04-17 02:20:36 +04:00
{
2014-09-09 15:03:03 +04:00
if ( filp - > f_mode & FMODE_WRITE & &
2015-01-28 10:38:20 +03:00
atomic_read ( & inode - > i_writecount ) = = 1 ) {
2014-09-09 15:03:03 +04:00
/*
* Grab i_mutex to avoid races with writes changing i_size
* while we are running .
*/
mutex_lock ( & inode - > i_mutex ) ;
2010-11-16 20:40:47 +03:00
down_write ( & UDF_I ( inode ) - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
udf_discard_prealloc ( inode ) ;
2009-12-03 15:39:28 +03:00
udf_truncate_tail_extent ( inode ) ;
2010-11-16 20:40:47 +03:00
up_write ( & UDF_I ( inode ) - > i_data_sem ) ;
2014-09-09 15:03:03 +04:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2006-03-28 13:56:42 +04:00
const struct file_operations udf_file_operations = {
2014-04-02 22:33:16 +04:00
. read_iter = generic_file_read_iter ,
2010-05-05 17:15:39 +04:00
. unlocked_ioctl = udf_ioctl ,
2010-05-19 18:28:56 +04:00
. open = generic_file_open ,
2007-07-21 15:37:18 +04:00
. mmap = generic_file_mmap ,
2014-04-03 11:31:17 +04:00
. write_iter = udf_file_write_iter ,
2007-07-21 15:37:18 +04:00
. release = udf_release_file ,
2010-05-26 19:53:41 +04:00
. fsync = generic_file_fsync ,
2007-07-21 15:37:18 +04:00
. splice_read = generic_file_splice_read ,
2008-09-08 21:44:17 +04:00
. llseek = generic_file_llseek ,
2005-04-17 02:20:36 +04:00
} ;
2010-06-04 13:29:59 +04:00
static int udf_setattr ( struct dentry * dentry , struct iattr * attr )
{
2015-03-18 01:25:59 +03:00
struct inode * inode = d_inode ( dentry ) ;
2010-06-04 13:29:59 +04:00
int error ;
error = inode_change_ok ( inode , attr ) ;
if ( error )
return error ;
2010-06-04 13:30:02 +04:00
if ( ( attr - > ia_valid & ATTR_SIZE ) & &
attr - > ia_size ! = i_size_read ( inode ) ) {
2010-10-22 02:30:26 +04:00
error = udf_setsize ( inode , attr - > ia_size ) ;
2010-06-04 13:30:02 +04:00
if ( error )
return error ;
}
setattr_copy ( inode , attr ) ;
mark_inode_dirty ( inode ) ;
return 0 ;
2010-06-04 13:29:59 +04:00
}
2007-02-12 11:55:40 +03:00
const struct inode_operations udf_file_inode_operations = {
2010-06-04 13:29:59 +04:00
. setattr = udf_setattr ,
2005-04-17 02:20:36 +04:00
} ;