2005-04-17 02:20:36 +04:00
/*
* linux / fs / hpfs / file . c
*
* Mikulas Patocka ( mikulas @ artax . karlin . mff . cuni . cz ) , 1998 - 1999
*
* file VFS functions
*/
# include "hpfs_fn.h"
2013-07-04 20:44:27 +04:00
# include <linux/mpage.h>
2005-04-17 02:20:36 +04:00
# define BLOCKS(size) (((size) + 511) >> 9)
static int hpfs_file_release ( struct inode * inode , struct file * file )
{
2011-01-22 22:26:12 +03:00
hpfs_lock ( inode - > i_sb ) ;
2005-04-17 02:20:36 +04:00
hpfs_write_if_changed ( inode ) ;
2011-01-22 22:26:12 +03:00
hpfs_unlock ( inode - > i_sb ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2011-07-17 04:44:56 +04:00
int hpfs_file_fsync ( struct file * file , loff_t start , loff_t end , int datasync )
2005-04-17 02:20:36 +04:00
{
2011-05-08 22:44:19 +04:00
struct inode * inode = file - > f_mapping - > host ;
2011-07-17 04:44:56 +04:00
int ret ;
ret = filemap_write_and_wait_range ( file - > f_mapping , start , end ) ;
if ( ret )
return ret ;
2011-05-08 22:44:19 +04:00
return sync_blockdev ( inode - > i_sb - > s_bdev ) ;
2005-04-17 02:20:36 +04:00
}
/*
* generic_file_read often calls bmap with non - existing sector ,
* so we must ignore such errors .
*/
2013-07-04 20:44:27 +04:00
static secno hpfs_bmap ( struct inode * inode , unsigned file_secno , unsigned * n_secs )
2005-04-17 02:20:36 +04:00
{
struct hpfs_inode_info * hpfs_inode = hpfs_i ( inode ) ;
unsigned n , disk_secno ;
struct fnode * fnode ;
struct buffer_head * bh ;
if ( BLOCKS ( hpfs_i ( inode ) - > mmu_private ) < = file_secno ) return 0 ;
n = file_secno - hpfs_inode - > i_file_sec ;
2013-07-04 20:44:27 +04:00
if ( n < hpfs_inode - > i_n_secs ) {
* n_secs = hpfs_inode - > i_n_secs - n ;
return hpfs_inode - > i_disk_sec + n ;
}
2005-04-17 02:20:36 +04:00
if ( ! ( fnode = hpfs_map_fnode ( inode - > i_sb , inode - > i_ino , & bh ) ) ) return 0 ;
disk_secno = hpfs_bplus_lookup ( inode - > i_sb , inode , & fnode - > btree , file_secno , bh ) ;
if ( disk_secno = = - 1 ) return 0 ;
if ( hpfs_chk_sectors ( inode - > i_sb , disk_secno , 1 , " bmap " ) ) return 0 ;
2013-07-04 20:44:27 +04:00
n = file_secno - hpfs_inode - > i_file_sec ;
if ( n < hpfs_inode - > i_n_secs ) {
* n_secs = hpfs_inode - > i_n_secs - n ;
return hpfs_inode - > i_disk_sec + n ;
}
* n_secs = 1 ;
2005-04-17 02:20:36 +04:00
return disk_secno ;
}
2012-12-15 14:53:50 +04:00
void hpfs_truncate ( struct inode * i )
2005-04-17 02:20:36 +04:00
{
if ( IS_IMMUTABLE ( i ) ) return /*-EPERM*/ ;
2011-05-08 22:42:54 +04:00
hpfs_lock_assert ( i - > i_sb ) ;
2005-04-17 02:20:36 +04:00
hpfs_i ( i ) - > i_n_secs = 0 ;
i - > i_blocks = 1 + ( ( i - > i_size + 511 ) > > 9 ) ;
hpfs_i ( i ) - > mmu_private = i - > i_size ;
hpfs_truncate_btree ( i - > i_sb , i - > i_ino , 1 , ( ( i - > i_size + 511 ) > > 9 ) ) ;
hpfs_write_inode ( i ) ;
hpfs_i ( i ) - > i_n_secs = 0 ;
}
static int hpfs_get_block ( struct inode * inode , sector_t iblock , struct buffer_head * bh_result , int create )
{
2011-05-08 22:42:54 +04:00
int r ;
2005-04-17 02:20:36 +04:00
secno s ;
2013-07-04 20:44:27 +04:00
unsigned n_secs ;
2011-05-08 22:42:54 +04:00
hpfs_lock ( inode - > i_sb ) ;
2013-07-04 20:44:27 +04:00
s = hpfs_bmap ( inode , iblock , & n_secs ) ;
2005-04-17 02:20:36 +04:00
if ( s ) {
2013-07-04 20:44:27 +04:00
if ( bh_result - > b_size > > 9 < n_secs )
n_secs = bh_result - > b_size > > 9 ;
2005-04-17 02:20:36 +04:00
map_bh ( bh_result , inode - > i_sb , s ) ;
2013-07-04 20:44:27 +04:00
bh_result - > b_size = n_secs < < 9 ;
2011-05-08 22:42:54 +04:00
goto ret_0 ;
2005-04-17 02:20:36 +04:00
}
2011-05-08 22:42:54 +04:00
if ( ! create ) goto ret_0 ;
2005-04-17 02:20:36 +04:00
if ( iblock < < 9 ! = hpfs_i ( inode ) - > mmu_private ) {
BUG ( ) ;
2011-05-08 22:42:54 +04:00
r = - EIO ;
goto ret_r ;
2005-04-17 02:20:36 +04:00
}
if ( ( s = hpfs_add_sector_to_btree ( inode - > i_sb , inode - > i_ino , 1 , inode - > i_blocks - 1 ) ) = = - 1 ) {
hpfs_truncate_btree ( inode - > i_sb , inode - > i_ino , 1 , inode - > i_blocks - 1 ) ;
2011-05-08 22:42:54 +04:00
r = - ENOSPC ;
goto ret_r ;
2005-04-17 02:20:36 +04:00
}
inode - > i_blocks + + ;
hpfs_i ( inode ) - > mmu_private + = 512 ;
set_buffer_new ( bh_result ) ;
map_bh ( bh_result , inode - > i_sb , s ) ;
2011-05-08 22:42:54 +04:00
ret_0 :
r = 0 ;
ret_r :
hpfs_unlock ( inode - > i_sb ) ;
return r ;
2005-04-17 02:20:36 +04:00
}
2013-07-04 20:44:27 +04:00
static int hpfs_readpage ( struct file * file , struct page * page )
{
return mpage_readpage ( page , hpfs_get_block ) ;
}
2005-04-17 02:20:36 +04:00
static int hpfs_writepage ( struct page * page , struct writeback_control * wbc )
{
2013-07-04 20:44:27 +04:00
return block_write_full_page ( page , hpfs_get_block , wbc ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:25:10 +04:00
2013-07-04 20:44:27 +04:00
static int hpfs_readpages ( struct file * file , struct address_space * mapping ,
struct list_head * pages , unsigned nr_pages )
{
return mpage_readpages ( mapping , pages , nr_pages , hpfs_get_block ) ;
}
static int hpfs_writepages ( struct address_space * mapping ,
struct writeback_control * wbc )
2005-04-17 02:20:36 +04:00
{
2013-07-04 20:44:27 +04:00
return mpage_writepages ( mapping , wbc , hpfs_get_block ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:25:10 +04:00
2012-12-15 14:53:50 +04:00
static void hpfs_write_failed ( struct address_space * mapping , loff_t to )
{
struct inode * inode = mapping - > host ;
2013-06-09 03:25:57 +04:00
hpfs_lock ( inode - > i_sb ) ;
2012-12-15 14:53:50 +04:00
if ( to > inode - > i_size ) {
2013-09-13 02:13:56 +04:00
truncate_pagecache ( inode , inode - > i_size ) ;
2012-12-15 14:53:50 +04:00
hpfs_truncate ( inode ) ;
}
2013-06-09 03:25:57 +04:00
hpfs_unlock ( inode - > i_sb ) ;
2012-12-15 14:53:50 +04:00
}
2007-10-16 12:25:10 +04:00
static int hpfs_write_begin ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata )
2005-04-17 02:20:36 +04:00
{
2010-06-04 13:29:55 +04:00
int ret ;
2007-10-16 12:25:10 +04:00
* pagep = NULL ;
2010-06-04 13:29:55 +04:00
ret = cont_write_begin ( file , mapping , pos , len , flags , pagep , fsdata ,
2007-10-16 12:25:10 +04:00
hpfs_get_block ,
& hpfs_i ( mapping - > host ) - > mmu_private ) ;
2012-12-15 14:53:50 +04:00
if ( unlikely ( ret ) )
hpfs_write_failed ( mapping , pos + len ) ;
2010-06-04 13:29:55 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:25:10 +04:00
2013-03-20 04:35:00 +04:00
static int hpfs_write_end ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * pagep , void * fsdata )
{
struct inode * inode = mapping - > host ;
int err ;
err = generic_write_end ( file , mapping , pos , len , copied , pagep , fsdata ) ;
if ( err < len )
hpfs_write_failed ( mapping , pos + len ) ;
if ( ! ( err < 0 ) ) {
/* make sure we write it on close, if not earlier */
hpfs_lock ( inode - > i_sb ) ;
hpfs_i ( inode ) - > i_dirty = 1 ;
hpfs_unlock ( inode - > i_sb ) ;
}
return err ;
}
2005-04-17 02:20:36 +04:00
static sector_t _hpfs_bmap ( struct address_space * mapping , sector_t block )
{
return generic_block_bmap ( mapping , block , hpfs_get_block ) ;
}
2007-10-16 12:25:10 +04:00
2006-06-28 15:26:44 +04:00
const struct address_space_operations hpfs_aops = {
2005-04-17 02:20:36 +04:00
. readpage = hpfs_readpage ,
. writepage = hpfs_writepage ,
2013-07-04 20:44:27 +04:00
. readpages = hpfs_readpages ,
. writepages = hpfs_writepages ,
2007-10-16 12:25:10 +04:00
. write_begin = hpfs_write_begin ,
2013-03-20 04:35:00 +04:00
. write_end = hpfs_write_end ,
2005-04-17 02:20:36 +04:00
. bmap = _hpfs_bmap
} ;
2006-03-28 13:56:42 +04:00
const struct file_operations hpfs_file_ops =
2005-04-17 02:20:36 +04:00
{
. llseek = generic_file_llseek ,
2014-04-02 22:33:16 +04:00
. read_iter = generic_file_read_iter ,
2014-04-03 11:17:43 +04:00
. write_iter = generic_file_write_iter ,
2005-04-17 02:20:36 +04:00
. mmap = generic_file_mmap ,
. release = hpfs_file_release ,
. fsync = hpfs_file_fsync ,
2007-06-01 13:49:19 +04:00
. splice_read = generic_file_splice_read ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-12 11:55:39 +03:00
const struct inode_operations hpfs_file_iops =
2005-04-17 02:20:36 +04:00
{
2008-08-11 02:27:59 +04:00
. setattr = hpfs_setattr ,
2005-04-17 02:20:36 +04:00
} ;