2006-10-11 12:20:50 +04:00
/*
2006-10-11 12:20:53 +04:00
* linux / fs / ext4 / file . c
2006-10-11 12:20:50 +04:00
*
* Copyright ( C ) 1992 , 1993 , 1994 , 1995
* Remy Card ( card @ masi . ibp . fr )
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie ( Paris VI )
*
* from
*
* linux / fs / minix / file . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
2006-10-11 12:20:53 +04:00
* ext4 fs regular file handling primitives
2006-10-11 12:20:50 +04:00
*
* 64 - bit file support on 64 - bit platforms by Jakub Jelinek
* ( jj @ sunsite . ms . mff . cuni . cz )
*/
# include <linux/time.h>
# include <linux/fs.h>
2006-10-11 12:21:01 +04:00
# include <linux/jbd2.h>
2008-04-30 02:13:32 +04:00
# include "ext4.h"
# include "ext4_jbd2.h"
2006-10-11 12:20:50 +04:00
# include "xattr.h"
# include "acl.h"
/*
* Called when an inode is released . Note that this is different
2006-10-11 12:20:53 +04:00
* from ext4_file_open : open gets called at every open , but release
2006-10-11 12:20:50 +04:00
* gets called only when / all / the files are closed .
*/
2008-09-09 06:25:24 +04:00
static int ext4_release_file ( struct inode * inode , struct file * filp )
2006-10-11 12:20:50 +04:00
{
/* if we are the last writer on the inode, drop the block reservation */
if ( ( filp - > f_mode & FMODE_WRITE ) & &
( atomic_read ( & inode - > i_writecount ) = = 1 ) )
{
2008-01-29 07:58:26 +03:00
down_write ( & EXT4_I ( inode ) - > i_data_sem ) ;
2008-10-10 17:40:52 +04:00
ext4_discard_preallocations ( inode ) ;
2008-01-29 07:58:26 +03:00
up_write ( & EXT4_I ( inode ) - > i_data_sem ) ;
2006-10-11 12:20:50 +04:00
}
if ( is_dx ( inode ) & & filp - > private_data )
2006-10-11 12:20:53 +04:00
ext4_htree_free_dir_info ( filp - > private_data ) ;
2006-10-11 12:20:50 +04:00
return 0 ;
}
static ssize_t
2006-10-11 12:20:53 +04:00
ext4_file_write ( struct kiocb * iocb , const struct iovec * iov ,
2006-10-11 12:20:50 +04:00
unsigned long nr_segs , loff_t pos )
{
struct file * file = iocb - > ki_filp ;
2006-12-08 13:36:38 +03:00
struct inode * inode = file - > f_path . dentry - > d_inode ;
2006-10-11 12:20:50 +04:00
ssize_t ret ;
int err ;
2008-01-29 07:58:27 +03:00
/*
* If we have encountered a bitmap - format file , the size limit
* is smaller than s_maxbytes , which is for extent - mapped files .
*/
if ( ! ( EXT4_I ( inode ) - > i_flags & EXT4_EXTENTS_FL ) ) {
struct ext4_sb_info * sbi = EXT4_SB ( inode - > i_sb ) ;
size_t length = iov_length ( iov , nr_segs ) ;
2006-10-11 12:20:50 +04:00
2008-01-29 07:58:27 +03:00
if ( pos > sbi - > s_bitmap_maxbytes )
return - EFBIG ;
if ( pos + length > sbi - > s_bitmap_maxbytes ) {
nr_segs = iov_shorten ( ( struct iovec * ) iov , nr_segs ,
sbi - > s_bitmap_maxbytes - pos ) ;
}
}
ret = generic_file_aio_write ( iocb , iov , nr_segs , pos ) ;
2006-10-11 12:20:50 +04:00
/*
* Skip flushing if there was an error , or if nothing was written .
*/
if ( ret < = 0 )
return ret ;
/*
* If the inode is IS_SYNC , or is O_SYNC and we are doing data
* journalling then we need to make sure that we force the transaction
* to disk to keep all metadata uptodate synchronously .
*/
if ( file - > f_flags & O_SYNC ) {
/*
* If we are non - data - journaled , then the dirty data has
* already been flushed to backing store by generic_osync_inode ,
* and the inode has been flushed too if there have been any
* modifications other than mere timestamp updates .
*
* Open question - - - do we care about flushing timestamps too
* if the inode is IS_SYNC ?
*/
2006-10-11 12:20:53 +04:00
if ( ! ext4_should_journal_data ( inode ) )
2006-10-11 12:20:50 +04:00
return ret ;
goto force_commit ;
}
/*
* So we know that there has been no forced data flush . If the inode
* is marked IS_SYNC , we need to force one ourselves .
*/
if ( ! IS_SYNC ( inode ) )
return ret ;
/*
* Open question # 2 - - - should we force data to disk here too ? If we
* don ' t , the only impact is that data = writeback filesystems won ' t
* flush data to disk automatically on IS_SYNC , only metadata ( but
* historically , that is what ext2 has done . )
*/
force_commit :
2006-10-11 12:20:53 +04:00
err = ext4_force_commit ( inode - > i_sb ) ;
2006-10-11 12:20:50 +04:00
if ( err )
return err ;
return ret ;
}
2008-07-12 03:27:31 +04:00
static struct vm_operations_struct ext4_file_vm_ops = {
. fault = filemap_fault ,
. page_mkwrite = ext4_page_mkwrite ,
} ;
static int ext4_file_mmap ( struct file * file , struct vm_area_struct * vma )
{
struct address_space * mapping = file - > f_mapping ;
if ( ! mapping - > a_ops - > readpage )
return - ENOEXEC ;
file_accessed ( file ) ;
vma - > vm_ops = & ext4_file_vm_ops ;
vma - > vm_flags | = VM_CAN_NONLINEAR ;
return 0 ;
}
2006-10-11 12:20:53 +04:00
const struct file_operations ext4_file_operations = {
2006-10-11 12:20:50 +04:00
. llseek = generic_file_llseek ,
. read = do_sync_read ,
. write = do_sync_write ,
. aio_read = generic_file_aio_read ,
2006-10-11 12:20:53 +04:00
. aio_write = ext4_file_write ,
2008-04-30 06:03:54 +04:00
. unlocked_ioctl = ext4_ioctl ,
2006-10-11 12:20:50 +04:00
# ifdef CONFIG_COMPAT
2006-10-11 12:20:53 +04:00
. compat_ioctl = ext4_compat_ioctl ,
2006-10-11 12:20:50 +04:00
# endif
2008-07-12 03:27:31 +04:00
. mmap = ext4_file_mmap ,
2006-10-11 12:20:50 +04:00
. open = generic_file_open ,
2006-10-11 12:20:53 +04:00
. release = ext4_release_file ,
. fsync = ext4_sync_file ,
2006-10-11 12:20:50 +04:00
. splice_read = generic_file_splice_read ,
. splice_write = generic_file_splice_write ,
} ;
2007-02-12 11:55:38 +03:00
const struct inode_operations ext4_file_inode_operations = {
2006-10-11 12:20:53 +04:00
. truncate = ext4_truncate ,
. setattr = ext4_setattr ,
2008-07-12 03:27:31 +04:00
. getattr = ext4_getattr ,
2008-10-11 04:02:48 +04:00
# ifdef CONFIG_EXT4_FS_XATTR
2006-10-11 12:20:50 +04:00
. setxattr = generic_setxattr ,
. getxattr = generic_getxattr ,
2006-10-11 12:20:53 +04:00
. listxattr = ext4_listxattr ,
2006-10-11 12:20:50 +04:00
. removexattr = generic_removexattr ,
# endif
2006-10-11 12:20:53 +04:00
. permission = ext4_permission ,
2007-07-18 05:42:41 +04:00
. fallocate = ext4_fallocate ,
2008-10-07 08:46:36 +04:00
. fiemap = ext4_fiemap ,
2006-10-11 12:20:50 +04:00
} ;