2005-04-16 15:20:36 -07:00
/*
* Copyright 2000 by Hans Reiser , licensing governed by reiserfs / README
*/
# include <linux/time.h>
2012-03-17 01:16:43 -04:00
# include "reiserfs.h"
2012-03-17 01:03:10 -04:00
# include "acl.h"
2012-03-17 00:59:06 -04:00
# include "xattr.h"
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
# include <linux/pagemap.h>
# include <linux/swap.h>
# include <linux/writeback.h>
# include <linux/blkdev.h>
# include <linux/buffer_head.h>
# include <linux/quotaops.h>
/*
* * We pack the tails of files on file close , not at the time they are written .
* * This implies an unnecessary copy of the tail and an unnecessary indirect item
* * insertion / balancing , for files that are written in one write .
* * It avoids unnecessary tail packings ( balances ) for files that are written in
* * multiple writes and are small enough to have tails .
2009-03-30 14:02:44 -04:00
* *
2005-04-16 15:20:36 -07:00
* * file_release is called by the VFS layer when the file is closed . If
* * this is the last open file descriptor , and the file
* * small enough to have a tail , and the tail is currently in an
* * unformatted node , the tail is converted back into a direct item .
2009-03-30 14:02:44 -04:00
* *
2005-04-16 15:20:36 -07:00
* * We use reiserfs_truncate_file to pack the tail , since it already has
2009-03-30 14:02:44 -04:00
* * all the conditions coded .
2005-04-16 15:20:36 -07:00
*/
2005-07-12 20:21:28 -07:00
static int reiserfs_file_release ( struct inode * inode , struct file * filp )
2005-04-16 15:20:36 -07:00
{
2005-07-12 20:21:28 -07:00
struct reiserfs_transaction_handle th ;
int err ;
int jbegin_failure = 0 ;
2005-04-16 15:20:36 -07:00
2006-10-03 23:36:38 +02:00
BUG_ON ( ! S_ISREG ( inode - > i_mode ) ) ;
2005-04-16 15:20:36 -07:00
2010-07-04 12:18:57 +04:00
if ( atomic_add_unless ( & REISERFS_I ( inode ) - > openers , - 1 , 1 ) )
return 0 ;
mutex_lock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
if ( ! atomic_dec_and_test ( & REISERFS_I ( inode ) - > openers ) ) {
mutex_unlock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
return 0 ;
}
2005-07-12 20:21:28 -07:00
/* fast out for when nothing needs to be done */
2010-07-04 12:18:57 +04:00
if ( ( ! ( REISERFS_I ( inode ) - > i_flags & i_pack_on_close_mask ) | |
2005-07-12 20:21:28 -07:00
! tail_has_to_be_packed ( inode ) ) & &
REISERFS_I ( inode ) - > i_prealloc_count < = 0 ) {
2010-07-04 12:18:57 +04:00
mutex_unlock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
2005-07-12 20:21:28 -07:00
return 0 ;
}
2005-04-16 15:20:36 -07:00
2006-08-05 12:15:08 -07:00
reiserfs_write_lock ( inode - > i_sb ) ;
2005-07-12 20:21:28 -07:00
/* freeing preallocation only involves relogging blocks that
* are already in the current transaction . preallocation gets
* freed at the end of each transaction , so it is impossible for
* us to log any additional blocks ( including quota blocks )
*/
err = journal_begin ( & th , inode - > i_sb , 1 ) ;
2005-04-16 15:20:36 -07:00
if ( err ) {
2005-07-12 20:21:28 -07:00
/* uh oh, we can't allow the inode to go away while there
* is still preallocation blocks pending . Try to join the
* aborted transaction
*/
jbegin_failure = err ;
err = journal_join_abort ( & th , inode - > i_sb , 1 ) ;
if ( err ) {
/* hmpf, our choices here aren't good. We can pin the inode
* which will disallow unmount from every happening , we can
* do nothing , which will corrupt random memory on unmount ,
* or we can forcibly remove the file from the preallocation
* list , which will leak blocks on disk . Lets pin the inode
* and let the admin know what is going on .
*/
igrab ( inode ) ;
2009-03-30 14:02:21 -04:00
reiserfs_warning ( inode - > i_sb , " clm-9001 " ,
2005-07-12 20:21:28 -07:00
" pinning inode %lu because the "
2006-11-25 11:09:30 -08:00
" preallocation can't be freed " ,
inode - > i_ino ) ;
2005-07-12 20:21:28 -07:00
goto out ;
}
2005-04-16 15:20:36 -07:00
}
2005-07-12 20:21:28 -07:00
reiserfs_update_inode_transaction ( inode ) ;
2005-04-16 15:20:36 -07:00
# ifdef REISERFS_PREALLOCATE
2005-07-12 20:21:28 -07:00
reiserfs_discard_prealloc ( & th , inode ) ;
2005-04-16 15:20:36 -07:00
# endif
2005-07-12 20:21:28 -07:00
err = journal_end ( & th , inode - > i_sb , 1 ) ;
/* copy back the error code from journal_begin */
if ( ! err )
err = jbegin_failure ;
2010-07-04 12:18:57 +04:00
if ( ! err & &
2005-07-12 20:21:28 -07:00
( REISERFS_I ( inode ) - > i_flags & i_pack_on_close_mask ) & &
tail_has_to_be_packed ( inode ) ) {
2010-07-04 12:18:57 +04:00
2005-07-12 20:21:28 -07:00
/* if regular file is released by last holder and it has been
appended ( we append by unformatted node only ) or its direct
item ( s ) had to be converted , then it may have to be
indirect2direct converted */
err = reiserfs_truncate_file ( inode , 0 ) ;
}
out :
reiserfs_write_unlock ( inode - > i_sb ) ;
2010-07-04 12:18:57 +04:00
mutex_unlock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
2005-07-12 20:21:28 -07:00
return err ;
2005-04-16 15:20:36 -07:00
}
2010-07-04 12:18:57 +04:00
static int reiserfs_file_open ( struct inode * inode , struct file * file )
2007-01-22 20:40:46 -08:00
{
2010-07-04 12:18:57 +04:00
int err = dquot_file_open ( inode , file ) ;
if ( ! atomic_inc_not_zero ( & REISERFS_I ( inode ) - > openers ) ) {
/* somebody might be tailpacking on final close; wait for it */
mutex_lock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
atomic_inc ( & REISERFS_I ( inode ) - > openers ) ;
mutex_unlock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
}
return err ;
2007-01-22 20:40:46 -08:00
}
2012-12-15 11:47:31 +01:00
void reiserfs_vfs_truncate_file ( struct inode * inode )
2005-07-12 20:21:28 -07:00
{
2010-07-04 12:18:57 +04:00
mutex_lock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
2005-07-12 20:21:28 -07:00
reiserfs_truncate_file ( inode , 1 ) ;
2010-07-04 12:18:57 +04:00
mutex_unlock ( & ( REISERFS_I ( inode ) - > tailpack ) ) ;
2005-04-16 15:20:36 -07:00
}
/* Sync a reiserfs file. */
/*
* FIXME : sync_mapping_buffers ( ) never has anything to sync . Can
* be removed . . .
*/
2011-07-16 20:44:56 -04:00
static int reiserfs_sync_file ( struct file * filp , loff_t start , loff_t end ,
int datasync )
2005-07-12 20:21:28 -07:00
{
2010-05-26 17:53:25 +02:00
struct inode * inode = filp - > f_mapping - > host ;
2009-03-30 14:02:50 -04:00
int err ;
2005-07-12 20:21:28 -07:00
int barrier_done ;
2011-07-16 20:44:56 -04:00
err = filemap_write_and_wait_range ( inode - > i_mapping , start , end ) ;
if ( err )
return err ;
mutex_lock ( & inode - > i_mutex ) ;
2009-03-30 14:02:47 -04:00
BUG_ON ( ! S_ISREG ( inode - > i_mode ) ) ;
2009-03-30 14:02:50 -04:00
err = sync_mapping_buffers ( inode - > i_mapping ) ;
2009-03-30 14:02:47 -04:00
reiserfs_write_lock ( inode - > i_sb ) ;
barrier_done = reiserfs_commit_for_inode ( inode ) ;
reiserfs_write_unlock ( inode - > i_sb ) ;
if ( barrier_done ! = 1 & & reiserfs_barrier_flush ( inode - > i_sb ) )
2010-09-16 20:51:46 +02:00
blkdev_issue_flush ( inode - > i_sb - > s_bdev , GFP_KERNEL , NULL ) ;
2011-07-16 20:44:56 -04:00
mutex_unlock ( & inode - > i_mutex ) ;
2005-07-12 20:21:28 -07:00
if ( barrier_done < 0 )
return barrier_done ;
2009-03-30 14:02:50 -04:00
return ( err < 0 ) ? - EIO : 0 ;
2005-04-16 15:20:36 -07:00
}
/* taken fs/buffer.c:__block_commit_write */
int reiserfs_commit_page ( struct inode * inode , struct page * page ,
2005-07-12 20:21:28 -07:00
unsigned from , unsigned to )
2005-04-16 15:20:36 -07:00
{
2005-07-12 20:21:28 -07:00
unsigned block_start , block_end ;
int partial = 0 ;
unsigned blocksize ;
struct buffer_head * bh , * head ;
unsigned long i_size_index = inode - > i_size > > PAGE_CACHE_SHIFT ;
int new ;
int logit = reiserfs_file_data_log ( inode ) ;
struct super_block * s = inode - > i_sb ;
int bh_per_page = PAGE_CACHE_SIZE / s - > s_blocksize ;
struct reiserfs_transaction_handle th ;
int ret = 0 ;
th . t_trans_id = 0 ;
blocksize = 1 < < inode - > i_blkbits ;
if ( logit ) {
reiserfs_write_lock ( s ) ;
ret = journal_begin ( & th , s , bh_per_page + 1 ) ;
if ( ret )
goto drop_write_lock ;
reiserfs_update_inode_transaction ( inode ) ;
}
for ( bh = head = page_buffers ( page ) , block_start = 0 ;
bh ! = head | | ! block_start ;
block_start = block_end , bh = bh - > b_this_page ) {
new = buffer_new ( bh ) ;
clear_buffer_new ( bh ) ;
block_end = block_start + blocksize ;
if ( block_end < = from | | block_start > = to ) {
if ( ! buffer_uptodate ( bh ) )
partial = 1 ;
} else {
set_buffer_uptodate ( bh ) ;
if ( logit ) {
reiserfs_prepare_for_journal ( s , bh , 1 ) ;
journal_mark_dirty ( & th , s , bh ) ;
} else if ( ! buffer_dirty ( bh ) ) {
mark_buffer_dirty ( bh ) ;
/* do data=ordered on any page past the end
* of file and any buffer marked BH_New .
*/
if ( reiserfs_data_ordered ( inode - > i_sb ) & &
( new | | page - > index > = i_size_index ) ) {
reiserfs_add_ordered_list ( inode , bh ) ;
}
}
}
2005-04-16 15:20:36 -07:00
}
2005-07-12 20:21:28 -07:00
if ( logit ) {
ret = journal_end ( & th , s , bh_per_page + 1 ) ;
drop_write_lock :
reiserfs_write_unlock ( s ) ;
}
/*
* If this is a partial write which happened to make all buffers
* uptodate then we can optimize away a bogus readpage ( ) for
* the next read ( ) . Here we ' discover ' whether the page went
* uptodate as a result of this ( potentially partial ) write .
*/
if ( ! partial )
SetPageUptodate ( page ) ;
return ret ;
2005-04-16 15:20:36 -07:00
}
2006-03-28 01:56:42 -08:00
const struct file_operations reiserfs_file_operations = {
2006-09-30 23:28:46 -07:00
. read = do_sync_read ,
2013-03-19 19:46:45 -04:00
. write = do_sync_write ,
2009-10-14 23:22:17 +02:00
. unlocked_ioctl = reiserfs_ioctl ,
2006-08-29 19:06:18 +01:00
# ifdef CONFIG_COMPAT
. compat_ioctl = reiserfs_compat_ioctl ,
# endif
2010-07-04 12:18:57 +04:00
. mmap = generic_file_mmap ,
. open = reiserfs_file_open ,
2005-07-12 20:21:28 -07:00
. release = reiserfs_file_release ,
. fsync = reiserfs_sync_file ,
. aio_read = generic_file_aio_read ,
2006-06-26 00:24:57 -07:00
. aio_write = generic_file_aio_write ,
2006-03-30 15:15:30 +02:00
. splice_read = generic_file_splice_read ,
. splice_write = generic_file_splice_write ,
2008-09-08 19:42:50 +02:00
. llseek = generic_file_llseek ,
2005-04-16 15:20:36 -07:00
} ;
2007-02-12 00:55:40 -08:00
const struct inode_operations reiserfs_file_inode_operations = {
2005-07-12 20:21:28 -07:00
. setattr = reiserfs_setattr ,
. setxattr = reiserfs_setxattr ,
. getxattr = reiserfs_getxattr ,
. listxattr = reiserfs_listxattr ,
. removexattr = reiserfs_removexattr ,
. permission = reiserfs_permission ,
2011-07-23 17:37:31 +02:00
. get_acl = reiserfs_get_acl ,
2005-04-16 15:20:36 -07:00
} ;