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>
# include <asm/uaccess.h>
# 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/smp_lock.h>
# include <linux/pagemap.h>
# include <linux/buffer_head.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/aio.h>
2005-04-17 02:20:36 +04:00
# include "udf_i.h"
# include "udf_sb.h"
2007-07-19 12:47:43 +04:00
static int udf_adinicb_readpage ( struct file * file , 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
2005-05-01 19:59:01 +04:00
BUG_ON ( ! PageLocked ( page ) ) ;
2005-04-17 02:20:36 +04:00
kaddr = kmap ( page ) ;
memset ( kaddr , 0 , PAGE_CACHE_SIZE ) ;
2008-02-08 15:20:44 +03:00
memcpy ( kaddr , iinfo - > i_ext . i_data + iinfo - > i_lenEAttr , inode - > i_size ) ;
2005-04-17 02:20:36 +04:00
flush_dcache_page ( page ) ;
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 ;
}
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 ;
}
2007-10-16 12:25:20 +04:00
static int udf_adinicb_write_end ( struct file * file ,
struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * page , void * fsdata )
2005-04-17 02:20:36 +04:00
{
2007-10-16 12:25:20 +04:00
struct inode * inode = mapping - > host ;
unsigned offset = pos & ( PAGE_CACHE_SIZE - 1 ) ;
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
2007-10-16 12:25:20 +04:00
kaddr = kmap_atomic ( page , KM_USER0 ) ;
2008-02-08 15:20:44 +03:00
memcpy ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr + offset ,
2007-10-16 12:25:20 +04:00
kaddr + offset , copied ) ;
kunmap_atomic ( kaddr , KM_USER0 ) ;
return simple_write_end ( file , mapping , pos , len , copied , page , fsdata ) ;
2005-04-17 02:20:36 +04:00
}
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 ,
. sync_page = block_sync_page ,
2007-10-16 12:25:20 +04:00
. write_begin = simple_write_begin ,
. write_end = udf_adinicb_write_end ,
2005-04-17 02:20:36 +04:00
} ;
2006-10-01 10:28:48 +04:00
static ssize_t udf_file_aio_write ( struct kiocb * iocb , const struct iovec * iov ,
2007-07-19 12:47:43 +04:00
unsigned long nr_segs , loff_t ppos )
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 ;
2006-12-08 13:37:44 +03:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
2005-04-17 02:20:36 +04:00
int err , pos ;
2006-10-01 10:28:48 +04:00
size_t count = iocb - > ki_left ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
2005-04-17 02:20:36 +04:00
if ( file - > f_flags & O_APPEND )
pos = inode - > i_size ;
else
2006-10-01 10:28:48 +04:00
pos = ppos ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
if ( inode - > i_sb - > s_blocksize <
( udf_file_entry_alloc_offset ( inode ) +
2007-07-21 15:37:18 +04:00
pos + count ) ) {
2005-04-17 02:20:36 +04:00
udf_expand_file_adinicb ( inode , pos + count , & err ) ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
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 {
2005-04-17 02:20:36 +04:00
if ( pos + count > inode - > i_size )
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc = pos + count ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc = inode - > i_size ;
2005-04-17 02:20:36 +04:00
}
}
2006-10-01 10:28:48 +04:00
retval = generic_file_aio_write ( iocb , iov , nr_segs , ppos ) ;
2005-04-17 02:20:36 +04:00
if ( retval > 0 )
mark_inode_dirty ( inode ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return retval ;
}
int udf_ioctl ( struct inode * inode , struct file * filp , unsigned int cmd ,
2007-07-19 12:47:43 +04:00
unsigned long arg )
2005-04-17 02:20:36 +04:00
{
2007-07-21 15:37:18 +04:00
long old_block , new_block ;
2005-04-17 02:20:36 +04:00
int result = - EINVAL ;
2007-07-19 12:47:43 +04:00
if ( file_permission ( filp , MAY_READ ) ! = 0 ) {
2007-07-21 15:37:18 +04:00
udf_debug ( " no permission to access inode %lu \n " ,
inode - > i_ino ) ;
2005-04-17 02:20:36 +04:00
return - EPERM ;
}
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 " ) ;
return - EINVAL ;
}
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 ) )
return - EFAULT ;
else
return 0 ;
2007-07-19 12:47:43 +04:00
case UDF_RELOCATE_BLOCKS :
2007-07-21 15:37:18 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EACCES ;
if ( get_user ( old_block , ( long __user * ) arg ) )
return - EFAULT ;
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 ) ;
return result ;
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 ) ;
2007-07-19 12:47:43 +04:00
break ;
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 ;
2007-07-19 12:47:43 +04:00
break ;
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
{
2007-07-19 12:47:43 +04:00
if ( filp - > f_mode & FMODE_WRITE ) {
2009-08-07 02:27:27 +04:00
mutex_lock ( & inode - > i_mutex ) ;
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
udf_discard_prealloc ( inode ) ;
2009-12-03 15:39:28 +03:00
udf_truncate_tail_extent ( inode ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
2009-08-07 02:27:27 +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 = {
2007-07-21 15:37:18 +04:00
. read = do_sync_read ,
. aio_read = generic_file_aio_read ,
. ioctl = udf_ioctl ,
. open = generic_file_open ,
. mmap = generic_file_mmap ,
. write = do_sync_write ,
. aio_write = udf_file_aio_write ,
. release = udf_release_file ,
2009-06-07 23:40:27 +04:00
. fsync = simple_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
} ;
2007-02-12 11:55:40 +03:00
const struct inode_operations udf_file_inode_operations = {
2007-07-19 12:47:43 +04:00
. truncate = udf_truncate ,
2005-04-17 02:20:36 +04:00
} ;