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
2010-07-27 19:56:07 +04:00
if ( ( pos > sbi - > s_bitmap_maxbytes | |
( pos = = sbi - > s_bitmap_maxbytes & & length > 0 ) ) )
2008-01-29 07:58:27 +03:00
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 ) ;
2011-01-10 20:29:43 +03:00
struct ext4_inode_info * ei = EXT4_I ( inode ) ;
2009-06-13 18:09:48 +04:00
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 ) ) ;
2010-06-12 07:14:04 +04:00
ext4_mark_super_dirty ( sb ) ;
2009-06-13 18:09:48 +04:00
}
}
2011-01-10 20:29:43 +03:00
/*
* Set up the jbd2_inode if we are opening the inode for
* writing and the journal is present
*/
if ( sbi - > s_journal & & ! ei - > jinode & & ( filp - > f_mode & FMODE_WRITE ) ) {
struct jbd2_inode * jinode = jbd2_alloc_inode ( GFP_KERNEL ) ;
spin_lock ( & inode - > i_lock ) ;
if ( ! ei - > jinode ) {
if ( ! jinode ) {
spin_unlock ( & inode - > i_lock ) ;
return - ENOMEM ;
}
ei - > jinode = jinode ;
jbd2_journal_init_jbd_inode ( ei - > jinode , inode ) ;
jinode = NULL ;
}
spin_unlock ( & inode - > i_lock ) ;
if ( unlikely ( jinode ! = NULL ) )
jbd2_free_inode ( jinode ) ;
}
2010-03-03 17:05:06 +03:00
return dquot_file_open ( inode , filp ) ;
2009-06-13 18:09:48 +04:00
}
2010-10-28 05:30:06 +04:00
/*
* ext4_llseek ( ) copied from generic_file_llseek ( ) to handle both
* block - mapped and extent - mapped maxbytes values . This should
* otherwise be identical with generic_file_llseek ( ) .
*/
loff_t ext4_llseek ( struct file * file , loff_t offset , int origin )
{
struct inode * inode = file - > f_mapping - > host ;
loff_t maxbytes ;
if ( ! ( ext4_test_inode_flag ( inode , EXT4_INODE_EXTENTS ) ) )
maxbytes = EXT4_SB ( inode - > i_sb ) - > s_bitmap_maxbytes ;
else
maxbytes = inode - > i_sb - > s_maxbytes ;
mutex_lock ( & inode - > i_mutex ) ;
switch ( origin ) {
case SEEK_END :
offset + = inode - > i_size ;
break ;
case SEEK_CUR :
if ( offset = = 0 ) {
mutex_unlock ( & inode - > i_mutex ) ;
return file - > f_pos ;
}
offset + = file - > f_pos ;
break ;
}
if ( offset < 0 | | offset > maxbytes ) {
mutex_unlock ( & inode - > i_mutex ) ;
return - EINVAL ;
}
if ( offset ! = file - > f_pos ) {
file - > f_pos = offset ;
file - > f_version = 0 ;
}
mutex_unlock ( & inode - > i_mutex ) ;
return offset ;
}
2006-10-11 12:20:53 +04:00
const struct file_operations ext4_file_operations = {
2010-10-28 05:30:06 +04:00
. llseek = ext4_llseek ,
2006-10-11 12:20:50 +04:00
. 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
} ;