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>
2009-06-13 18:09:48 +04:00
# include <linux/mount.h>
# include <linux/path.h>
2010-03-03 17:05:07 +03:00
# include <linux/quotaops.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
{
2010-01-24 22:34:07 +03:00
if ( ext4_test_inode_state ( inode , EXT4_STATE_DA_ALLOC_CLOSE ) ) {
2009-02-24 16:21:14 +03:00
ext4_alloc_da_blocks ( inode ) ;
2010-01-24 22:34:07 +03:00
ext4_clear_inode_state ( inode , EXT4_STATE_DA_ALLOC_CLOSE ) ;
2009-02-24 16:21:14 +03:00
}
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 ) & &
2009-03-28 05:36:43 +03:00
( atomic_read ( & inode - > i_writecount ) = = 1 ) & &
! EXT4_I ( inode ) - > i_reserved_data_blocks )
2006-10-11 12:20:50 +04:00
{
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 )
{
2009-08-18 19:48:27 +04:00
struct inode * inode = iocb - > ki_filp - > f_path . dentry - > d_inode ;
2006-10-11 12:20:50 +04:00
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 .
*/
2010-05-17 06:00:00 +04:00
if ( ! ( ext4_test_inode_flag ( inode , EXT4_INODE_EXTENTS ) ) ) {
2008-01-29 07:58:27 +03:00
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 ) ;
}
}
2009-08-18 19:48:27 +04:00
return generic_file_aio_write ( iocb , iov , nr_segs , pos ) ;
2006-10-11 12:20:50 +04:00
}
2009-09-27 22:29:37 +04:00
static const struct vm_operations_struct ext4_file_vm_ops = {
2008-07-12 03:27:31 +04:00
. 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 ;
}
2009-06-13 18:09:48 +04:00
static int ext4_file_open ( struct inode * inode , struct file * filp )
{
struct super_block * sb = inode - > i_sb ;
struct ext4_sb_info * sbi = EXT4_SB ( inode - > i_sb ) ;
struct vfsmount * mnt = filp - > f_path . mnt ;
struct path path ;
char buf [ 64 ] , * cp ;
if ( unlikely ( ! ( sbi - > s_mount_flags & EXT4_MF_MNTDIR_SAMPLED ) & &
! ( sb - > s_flags & MS_RDONLY ) ) ) {
sbi - > s_mount_flags | = EXT4_MF_MNTDIR_SAMPLED ;
/*
* Sample where the filesystem has been mounted and
* store it in the superblock for sysadmin convenience
* when trying to sort through large numbers of block
* devices or filesystem images .
*/
memset ( buf , 0 , sizeof ( buf ) ) ;
2010-01-24 04:10:29 +03:00
path . mnt = mnt ;
path . dentry = mnt - > mnt_root ;
2009-06-13 18:09:48 +04:00
cp = d_path ( & path , buf , sizeof ( buf ) ) ;
if ( ! IS_ERR ( cp ) ) {
memcpy ( sbi - > s_es - > s_last_mounted , cp ,
sizeof ( sbi - > s_es - > s_last_mounted ) ) ;
sb - > s_dirt = 1 ;
}
}
2010-03-03 17:05:06 +03:00
return dquot_file_open ( inode , filp ) ;
2009-06-13 18:09:48 +04:00
}
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 ,
2009-06-13 18:09:48 +04:00
. open = ext4_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
2009-08-28 23:12:24 +04:00
. check_acl = ext4_check_acl ,
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
} ;