2005-04-17 02:20:36 +04:00
/*
* linux / fs / ext2 / file . c
*
* 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
*
* ext2 fs regular file handling primitives
*
* 64 - bit file support on 64 - bit platforms by Jakub Jelinek
* ( jj @ sunsite . ms . mff . cuni . cz )
*/
# include <linux/time.h>
2009-12-16 03:46:49 +03:00
# include <linux/pagemap.h>
2015-09-09 00:58:40 +03:00
# include <linux/dax.h>
2010-03-03 17:05:07 +03:00
# include <linux/quotaops.h>
2016-09-19 04:30:29 +03:00
# include <linux/iomap.h>
# include <linux/uio.h>
2005-04-17 02:20:36 +04:00
# include "ext2.h"
# include "xattr.h"
# include "acl.h"
2015-02-17 02:59:25 +03:00
# ifdef CONFIG_FS_DAX
2016-09-19 04:30:29 +03:00
static ssize_t ext2_dax_read_iter ( struct kiocb * iocb , struct iov_iter * to )
{
struct inode * inode = iocb - > ki_filp - > f_mapping - > host ;
ssize_t ret ;
if ( ! iov_iter_count ( to ) )
return 0 ; /* skip atime */
inode_lock_shared ( inode ) ;
ret = iomap_dax_rw ( iocb , to , & ext2_iomap_ops ) ;
inode_unlock_shared ( inode ) ;
file_accessed ( iocb - > ki_filp ) ;
return ret ;
}
static ssize_t ext2_dax_write_iter ( struct kiocb * iocb , struct iov_iter * from )
{
struct file * file = iocb - > ki_filp ;
struct inode * inode = file - > f_mapping - > host ;
ssize_t ret ;
inode_lock ( inode ) ;
ret = generic_write_checks ( iocb , from ) ;
if ( ret < = 0 )
goto out_unlock ;
ret = file_remove_privs ( file ) ;
if ( ret )
goto out_unlock ;
ret = file_update_time ( file ) ;
if ( ret )
goto out_unlock ;
ret = iomap_dax_rw ( iocb , from , & ext2_iomap_ops ) ;
if ( ret > 0 & & iocb - > ki_pos > i_size_read ( inode ) ) {
i_size_write ( inode , iocb - > ki_pos ) ;
mark_inode_dirty ( inode ) ;
}
out_unlock :
inode_unlock ( inode ) ;
if ( ret > 0 )
ret = generic_write_sync ( iocb , ret ) ;
return ret ;
}
2015-10-14 01:25:37 +03:00
/*
* The lock ordering for ext2 DAX fault paths is :
*
* mmap_sem ( MM )
* sb_start_pagefault ( vfs , freeze )
* ext2_inode_info - > dax_sem
* address_space - > i_mmap_rwsem or page_lock ( mutually exclusive in DAX )
* ext2_inode_info - > truncate_mutex
*
* The default page_lock and i_size verification done by non - DAX fault paths
* is sufficient because ext2 doesn ' t support hole punching .
*/
2015-02-17 02:59:02 +03:00
static int ext2_dax_fault ( struct vm_area_struct * vma , struct vm_fault * vmf )
{
2015-10-14 01:25:37 +03:00
struct inode * inode = file_inode ( vma - > vm_file ) ;
struct ext2_inode_info * ei = EXT2_I ( inode ) ;
int ret ;
if ( vmf - > flags & FAULT_FLAG_WRITE ) {
sb_start_pagefault ( inode - > i_sb ) ;
file_update_time ( vma - > vm_file ) ;
}
down_read ( & ei - > dax_sem ) ;
2016-09-19 04:30:29 +03:00
ret = iomap_dax_fault ( vma , vmf , & ext2_iomap_ops ) ;
2015-10-14 01:25:37 +03:00
up_read ( & ei - > dax_sem ) ;
if ( vmf - > flags & FAULT_FLAG_WRITE )
sb_end_pagefault ( inode - > i_sb ) ;
return ret ;
2015-02-17 02:59:02 +03:00
}
2015-09-09 00:59:00 +03:00
static int ext2_dax_pmd_fault ( struct vm_area_struct * vma , unsigned long addr ,
pmd_t * pmd , unsigned int flags )
{
2015-10-14 01:25:37 +03:00
struct inode * inode = file_inode ( vma - > vm_file ) ;
struct ext2_inode_info * ei = EXT2_I ( inode ) ;
int ret ;
if ( flags & FAULT_FLAG_WRITE ) {
sb_start_pagefault ( inode - > i_sb ) ;
file_update_time ( vma - > vm_file ) ;
}
down_read ( & ei - > dax_sem ) ;
2016-07-27 01:21:05 +03:00
ret = dax_pmd_fault ( vma , addr , pmd , flags , ext2_get_block ) ;
2015-10-14 01:25:37 +03:00
up_read ( & ei - > dax_sem ) ;
if ( flags & FAULT_FLAG_WRITE )
sb_end_pagefault ( inode - > i_sb ) ;
return ret ;
2015-09-09 00:59:00 +03:00
}
2015-10-14 01:25:37 +03:00
static int ext2_dax_pfn_mkwrite ( struct vm_area_struct * vma ,
struct vm_fault * vmf )
{
struct inode * inode = file_inode ( vma - > vm_file ) ;
struct ext2_inode_info * ei = EXT2_I ( inode ) ;
loff_t size ;
2016-01-23 02:10:50 +03:00
int ret ;
2015-10-14 01:25:37 +03:00
sb_start_pagefault ( inode - > i_sb ) ;
file_update_time ( vma - > vm_file ) ;
down_read ( & ei - > dax_sem ) ;
/* check that the faulting page hasn't raced with truncate */
size = ( i_size_read ( inode ) + PAGE_SIZE - 1 ) > > PAGE_SHIFT ;
if ( vmf - > pgoff > = size )
ret = VM_FAULT_SIGBUS ;
2016-01-23 02:10:50 +03:00
else
ret = dax_pfn_mkwrite ( vma , vmf ) ;
2015-10-14 01:25:37 +03:00
up_read ( & ei - > dax_sem ) ;
sb_end_pagefault ( inode - > i_sb ) ;
return ret ;
2015-02-17 02:59:02 +03:00
}
static const struct vm_operations_struct ext2_dax_vm_ops = {
. fault = ext2_dax_fault ,
2015-09-09 00:59:00 +03:00
. pmd_fault = ext2_dax_pmd_fault ,
2016-02-27 22:01:13 +03:00
. page_mkwrite = ext2_dax_fault ,
2015-10-14 01:25:37 +03:00
. pfn_mkwrite = ext2_dax_pfn_mkwrite ,
2015-02-17 02:59:02 +03:00
} ;
static int ext2_file_mmap ( struct file * file , struct vm_area_struct * vma )
{
if ( ! IS_DAX ( file_inode ( file ) ) )
return generic_file_mmap ( file , vma ) ;
file_accessed ( file ) ;
vma - > vm_ops = & ext2_dax_vm_ops ;
2015-09-09 00:59:00 +03:00
vma - > vm_flags | = VM_MIXEDMAP | VM_HUGEPAGE ;
2015-02-17 02:59:02 +03:00
return 0 ;
}
# else
# define ext2_file_mmap generic_file_mmap
# endif
2005-04-17 02:20:36 +04:00
/*
2007-07-16 10:40:22 +04:00
* Called when filp is released . This happens when all file descriptors
* for a single struct file are closed . Note that different open ( ) calls
* for the same file yield different struct file structures .
2005-04-17 02:20:36 +04:00
*/
static int ext2_release_file ( struct inode * inode , struct file * filp )
{
2007-10-17 10:30:46 +04:00
if ( filp - > f_mode & FMODE_WRITE ) {
mutex_lock ( & EXT2_I ( inode ) - > truncate_mutex ) ;
ext2_discard_reservation ( inode ) ;
mutex_unlock ( & EXT2_I ( inode ) - > truncate_mutex ) ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-07-17 04:44:56 +04:00
int ext2_fsync ( struct file * file , loff_t start , loff_t end , int datasync )
2009-12-16 03:46:49 +03:00
{
int ret ;
2010-05-26 19:53:25 +04:00
struct super_block * sb = file - > f_mapping - > host - > i_sb ;
2009-12-16 03:46:49 +03:00
struct address_space * mapping = sb - > s_bdev - > bd_inode - > i_mapping ;
2011-07-17 04:44:56 +04:00
ret = generic_file_fsync ( file , start , end , datasync ) ;
2009-12-16 03:46:49 +03:00
if ( ret = = - EIO | | test_and_clear_bit ( AS_EIO , & mapping - > flags ) ) {
/* We don't really know where the IO error happened... */
ext2_error ( sb , __func__ ,
" detected IO error when writing metadata buffers " ) ;
ret = - EIO ;
}
return ret ;
}
2016-09-19 04:30:29 +03:00
static ssize_t ext2_file_read_iter ( struct kiocb * iocb , struct iov_iter * to )
{
# ifdef CONFIG_FS_DAX
if ( IS_DAX ( iocb - > ki_filp - > f_mapping - > host ) )
return ext2_dax_read_iter ( iocb , to ) ;
# endif
return generic_file_read_iter ( iocb , to ) ;
}
static ssize_t ext2_file_write_iter ( struct kiocb * iocb , struct iov_iter * from )
{
# ifdef CONFIG_FS_DAX
if ( IS_DAX ( iocb - > ki_filp - > f_mapping - > host ) )
return ext2_dax_write_iter ( iocb , from ) ;
# endif
return generic_file_write_iter ( iocb , from ) ;
}
2006-03-28 13:56:42 +04:00
const struct file_operations ext2_file_operations = {
2005-04-17 02:20:36 +04:00
. llseek = generic_file_llseek ,
2016-09-19 04:30:29 +03:00
. read_iter = ext2_file_read_iter ,
. write_iter = ext2_file_write_iter ,
2008-02-06 12:40:10 +03:00
. unlocked_ioctl = ext2_ioctl ,
2006-08-29 22:06:20 +04:00
# ifdef CONFIG_COMPAT
. compat_ioctl = ext2_compat_ioctl ,
# endif
2015-02-17 02:59:02 +03:00
. mmap = ext2_file_mmap ,
2010-03-03 17:05:06 +03:00
. open = dquot_file_open ,
2005-04-17 02:20:36 +04:00
. release = ext2_release_file ,
2009-12-16 03:46:49 +03:00
. fsync = ext2_fsync ,
2016-10-08 02:59:59 +03:00
. get_unmapped_area = thp_get_unmapped_area ,
2006-03-30 17:15:30 +04:00
. splice_read = generic_file_splice_read ,
2014-04-05 12:27:08 +04:00
. splice_write = iter_file_splice_write ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-12 11:55:38 +03:00
const struct inode_operations ext2_file_inode_operations = {
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_EXT2_FS_XATTR
. listxattr = ext2_listxattr ,
# endif
. setattr = ext2_setattr ,
2011-07-23 19:37:31 +04:00
. get_acl = ext2_get_acl ,
2013-12-20 17:16:44 +04:00
. set_acl = ext2_set_acl ,
2008-10-04 01:32:43 +04:00
. fiemap = ext2_fiemap ,
2005-04-17 02:20:36 +04:00
} ;