2005-04-17 02:20:36 +04:00
/*
* linux / fs / ufs / inode . c
*
* Copyright ( C ) 1998
* Daniel Pirkl < daniel . pirkl @ email . cz >
* Charles University , Faculty of Mathematics and Physics
*
* from
*
* linux / fs / ext2 / inode . 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 / inode . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* Goal - directed block allocation by Stephen Tweedie ( sct @ dcs . ed . ac . uk ) , 1993
* Big - endian to little - endian byte - swapping / bitmaps by
* David S . Miller ( davem @ caip . rutgers . edu ) , 1995
*/
# include <asm/uaccess.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/time.h>
# include <linux/stat.h>
# include <linux/string.h>
# include <linux/mm.h>
# include <linux/buffer_head.h>
2010-03-05 11:21:37 +03:00
# include <linux/writeback.h>
2005-04-17 02:20:36 +04:00
2008-02-08 15:21:31 +03:00
# include "ufs_fs.h"
2007-10-17 10:26:51 +04:00
# include "ufs.h"
2005-04-17 02:20:36 +04:00
# include "swab.h"
# include "util.h"
2015-06-04 21:13:14 +03:00
static int ufs_block_to_path ( struct inode * inode , sector_t i_block , unsigned offsets [ 4 ] )
2005-04-17 02:20:36 +04:00
{
struct ufs_sb_private_info * uspi = UFS_SB ( inode - > i_sb ) - > s_uspi ;
int ptrs = uspi - > s_apb ;
int ptrs_bits = uspi - > s_apbshift ;
const long direct_blocks = UFS_NDADDR ,
indirect_blocks = ptrs ,
double_blocks = ( 1 < < ( ptrs_bits * 2 ) ) ;
int n = 0 ;
2006-06-25 16:47:24 +04:00
UFSD ( " ptrs=uspi->s_apb = %d,double_blocks=%ld \n " , ptrs , double_blocks ) ;
2009-06-18 03:26:28 +04:00
if ( i_block < direct_blocks ) {
2005-04-17 02:20:36 +04:00
offsets [ n + + ] = i_block ;
} else if ( ( i_block - = direct_blocks ) < indirect_blocks ) {
offsets [ n + + ] = UFS_IND_BLOCK ;
offsets [ n + + ] = i_block ;
} else if ( ( i_block - = indirect_blocks ) < double_blocks ) {
offsets [ n + + ] = UFS_DIND_BLOCK ;
offsets [ n + + ] = i_block > > ptrs_bits ;
offsets [ n + + ] = i_block & ( ptrs - 1 ) ;
} else if ( ( ( i_block - = double_blocks ) > > ( ptrs_bits * 2 ) ) < ptrs ) {
offsets [ n + + ] = UFS_TIND_BLOCK ;
offsets [ n + + ] = i_block > > ( ptrs_bits * 2 ) ;
offsets [ n + + ] = ( i_block > > ptrs_bits ) & ( ptrs - 1 ) ;
offsets [ n + + ] = i_block & ( ptrs - 1 ) ;
} else {
ufs_warning ( inode - > i_sb , " ufs_block_to_path " , " block > big " ) ;
}
return n ;
}
2015-06-17 19:02:56 +03:00
typedef struct {
void * p ;
union {
__fs32 key32 ;
__fs64 key64 ;
} ;
struct buffer_head * bh ;
} Indirect ;
static inline int grow_chain32 ( struct ufs_inode_info * ufsi ,
struct buffer_head * bh , __fs32 * v ,
Indirect * from , Indirect * to )
{
Indirect * p ;
unsigned seq ;
to - > bh = bh ;
do {
seq = read_seqbegin ( & ufsi - > meta_lock ) ;
to - > key32 = * ( __fs32 * ) ( to - > p = v ) ;
for ( p = from ; p < = to & & p - > key32 = = * ( __fs32 * ) p - > p ; p + + )
;
} while ( read_seqretry ( & ufsi - > meta_lock , seq ) ) ;
return ( p > to ) ;
}
static inline int grow_chain64 ( struct ufs_inode_info * ufsi ,
struct buffer_head * bh , __fs64 * v ,
Indirect * from , Indirect * to )
{
Indirect * p ;
unsigned seq ;
to - > bh = bh ;
do {
seq = read_seqbegin ( & ufsi - > meta_lock ) ;
to - > key64 = * ( __fs64 * ) ( to - > p = v ) ;
for ( p = from ; p < = to & & p - > key64 = = * ( __fs64 * ) p - > p ; p + + )
;
} while ( read_seqretry ( & ufsi - > meta_lock , seq ) ) ;
return ( p > to ) ;
}
2005-04-17 02:20:36 +04:00
/*
* Returns the location of the fragment from
2011-03-31 05:57:33 +04:00
* the beginning of the filesystem .
2005-04-17 02:20:36 +04:00
*/
2015-06-04 21:27:23 +03:00
static u64 ufs_frag_map ( struct inode * inode , unsigned offsets [ 4 ] , int depth )
2005-04-17 02:20:36 +04:00
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
u64 mask = ( u64 ) uspi - > s_apbmask > > uspi - > s_fpbshift ;
int shift = uspi - > s_apbshift - uspi - > s_fpbshift ;
2015-06-17 19:02:56 +03:00
Indirect chain [ 4 ] , * q = chain ;
2015-06-04 21:27:23 +03:00
unsigned * p ;
2005-04-17 02:20:36 +04:00
unsigned flags = UFS_SB ( sb ) - > s_flags ;
2015-06-17 19:02:56 +03:00
u64 res = 0 ;
2005-04-17 02:20:36 +04:00
2006-06-29 13:24:29 +04:00
UFSD ( " : uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx \n " ,
uspi - > s_fpbshift , uspi - > s_apbmask ,
( unsigned long long ) mask ) ;
2005-04-17 02:20:36 +04:00
if ( depth = = 0 )
2015-06-17 19:02:56 +03:00
goto no_block ;
2005-04-17 02:20:36 +04:00
2015-06-17 19:02:56 +03:00
again :
2005-04-17 02:20:36 +04:00
p = offsets ;
if ( ( flags & UFS_TYPE_MASK ) = = UFS_TYPE_UFS2 )
goto ufs2 ;
2015-06-17 19:02:56 +03:00
if ( ! grow_chain32 ( ufsi , NULL , & ufsi - > i_u1 . i_data [ * p + + ] , chain , q ) )
goto changed ;
if ( ! q - > key32 )
goto no_block ;
2005-04-17 02:20:36 +04:00
while ( - - depth ) {
2015-06-17 19:02:56 +03:00
__fs32 * ptr ;
2005-04-17 02:20:36 +04:00
struct buffer_head * bh ;
2015-06-04 21:13:14 +03:00
unsigned n = * p + + ;
2005-04-17 02:20:36 +04:00
2015-06-17 19:02:56 +03:00
bh = sb_bread ( sb , uspi - > s_sbbase +
fs32_to_cpu ( sb , q - > key32 ) + ( n > > shift ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! bh )
2015-06-17 19:02:56 +03:00
goto no_block ;
ptr = ( __fs32 * ) bh - > b_data + ( n & mask ) ;
if ( ! grow_chain32 ( ufsi , bh , ptr , chain , + + q ) )
goto changed ;
if ( ! q - > key32 )
goto no_block ;
2005-04-17 02:20:36 +04:00
}
2015-06-17 19:02:56 +03:00
res = fs32_to_cpu ( sb , q - > key32 ) ;
goto found ;
2005-04-17 02:20:36 +04:00
2015-06-17 19:02:56 +03:00
ufs2 :
if ( ! grow_chain64 ( ufsi , NULL , & ufsi - > i_u1 . u2_i_data [ * p + + ] , chain , q ) )
goto changed ;
if ( ! q - > key64 )
goto no_block ;
2005-04-17 02:20:36 +04:00
while ( - - depth ) {
2015-06-17 19:02:56 +03:00
__fs64 * ptr ;
2005-04-17 02:20:36 +04:00
struct buffer_head * bh ;
2015-06-04 21:13:14 +03:00
unsigned n = * p + + ;
2005-04-17 02:20:36 +04:00
2015-06-17 19:02:56 +03:00
bh = sb_bread ( sb , uspi - > s_sbbase +
fs64_to_cpu ( sb , q - > key64 ) + ( n > > shift ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! bh )
2015-06-17 19:02:56 +03:00
goto no_block ;
ptr = ( __fs64 * ) bh - > b_data + ( n & mask ) ;
if ( ! grow_chain64 ( ufsi , bh , ptr , chain , + + q ) )
goto changed ;
if ( ! q - > key64 )
goto no_block ;
}
res = fs64_to_cpu ( sb , q - > key64 ) ;
found :
2015-06-04 21:27:23 +03:00
res + = uspi - > s_sbbase ;
2015-06-17 19:02:56 +03:00
no_block :
while ( q > chain ) {
brelse ( q - > bh ) ;
q - - ;
2005-04-17 02:20:36 +04:00
}
2015-06-17 19:02:56 +03:00
return res ;
2005-04-17 02:20:36 +04:00
2015-06-17 19:02:56 +03:00
changed :
while ( q > chain ) {
brelse ( q - > bh ) ;
q - - ;
}
goto again ;
2005-04-17 02:20:36 +04:00
}
2015-06-19 20:40:25 +03:00
/*
* Unpacking tails : we have a file with partial final block and
* we had been asked to extend it . If the fragment being written
* is within the same block , we need to extend the tail just to cover
* that fragment . Otherwise the tail is extended to full block .
*
* Note that we might need to create a _new_ tail , but that will
* be handled elsewhere ; this is strictly for resizing old
* ones .
*/
static bool
ufs_extend_tail ( struct inode * inode , u64 writes_to ,
int * err , struct page * locked_page )
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
unsigned lastfrag = ufsi - > i_lastfrag ; /* it's a short file, so unsigned is enough */
unsigned block = ufs_fragstoblks ( lastfrag ) ;
unsigned new_size ;
void * p ;
u64 tmp ;
if ( writes_to < ( lastfrag | uspi - > s_fpbmask ) )
new_size = ( writes_to & uspi - > s_fpbmask ) + 1 ;
else
new_size = uspi - > s_fpb ;
p = ufs_get_direct_data_ptr ( uspi , ufsi , block ) ;
tmp = ufs_new_fragments ( inode , p , lastfrag , ufs_data_ptr_to_cpu ( sb , p ) ,
new_size , err , locked_page ) ;
return tmp ! = 0 ;
}
2006-06-25 16:47:27 +04:00
/**
* ufs_inode_getfrag ( ) - allocate new fragment ( s )
2014-08-09 01:21:08 +04:00
* @ inode : pointer to inode
2015-06-19 20:53:52 +03:00
* @ index : number of block pointer within the inode ' s array .
2014-08-09 01:21:08 +04:00
* @ new_fragment : number of new allocated fragment ( s )
* @ err : we set it if something wrong
* @ phys : pointer to where we save physical number of new allocated fragments ,
2006-06-25 16:47:27 +04:00
* NULL if we allocate not data ( indirect blocks for example ) .
2014-08-09 01:21:08 +04:00
* @ new : we set it if we allocate new block
* @ locked_page : for ufs_new_fragments ( )
2006-06-25 16:47:27 +04:00
*/
2015-06-19 07:53:06 +03:00
static u64
2015-06-19 20:53:52 +03:00
ufs_inode_getfrag ( struct inode * inode , unsigned index ,
sector_t new_fragment , int * err ,
2006-06-25 16:47:27 +04:00
long * phys , int * new , struct page * locked_page )
2005-04-17 02:20:36 +04:00
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
2006-06-25 16:47:27 +04:00
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
2015-06-19 20:53:52 +03:00
u64 tmp , goal , lastfrag ;
2015-06-19 20:40:25 +03:00
unsigned nfrags = uspi - > s_fpb ;
void * p ;
2005-04-17 02:20:36 +04:00
/* TODO : to be done for write support
if ( ( flags & UFS_TYPE_MASK ) = = UFS_TYPE_UFS2 )
goto ufs2 ;
*/
2015-06-19 20:53:52 +03:00
p = ufs_get_direct_data_ptr ( uspi , ufsi , index ) ;
2007-02-12 11:54:32 +03:00
tmp = ufs_data_ptr_to_cpu ( sb , p ) ;
2015-06-19 20:40:25 +03:00
if ( tmp )
goto out ;
2007-02-12 11:54:32 +03:00
2005-04-17 02:20:36 +04:00
lastfrag = ufsi - > i_lastfrag ;
2015-06-19 20:40:25 +03:00
/* will that be a new tail? */
if ( new_fragment < UFS_NDIR_FRAGMENT & & new_fragment > = lastfrag )
nfrags = ( new_fragment & uspi - > s_fpbmask ) + 1 ;
goal = 0 ;
2015-06-19 20:53:52 +03:00
if ( index ) {
2015-06-19 20:40:25 +03:00
goal = ufs_data_ptr_to_cpu ( sb ,
2015-06-19 20:53:52 +03:00
ufs_get_direct_data_ptr ( uspi , ufsi , index - 1 ) ) ;
2015-06-19 20:40:25 +03:00
if ( goal )
goal + = uspi - > s_fpb ;
2005-04-17 02:20:36 +04:00
}
2015-06-19 20:53:52 +03:00
tmp = ufs_new_fragments ( inode , p , ufs_blknum ( new_fragment ) ,
2015-06-19 20:40:25 +03:00
goal , uspi - > s_fpb , err ,
phys ! = NULL ? locked_page : NULL ) ;
2005-04-17 02:20:36 +04:00
if ( ! tmp ) {
* err = - ENOSPC ;
2015-06-19 07:53:06 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2015-06-19 07:10:00 +03:00
if ( phys ) {
2005-04-17 02:20:36 +04:00
* err = 0 ;
* new = 1 ;
}
inode - > i_ctime = CURRENT_TIME_SEC ;
if ( IS_SYNC ( inode ) )
ufs_sync_inode ( inode ) ;
mark_inode_dirty ( inode ) ;
2015-06-19 07:10:00 +03:00
out :
2015-06-19 07:53:06 +03:00
return tmp + uspi - > s_sbbase ;
2005-04-17 02:20:36 +04:00
/* This part : To be implemented ....
Required only for writing , not required for READ - ONLY .
ufs2 :
u2_block = ufs_fragstoblks ( fragment ) ;
u2_blockoff = ufs_fragnum ( fragment ) ;
p = ufsi - > i_u1 . u2_i_data + block ;
goal = 0 ;
repeat2 :
tmp = fs32_to_cpu ( sb , * p ) ;
lastfrag = ufsi - > i_lastfrag ;
*/
}
2006-06-25 16:47:27 +04:00
/**
* ufs_inode_getblock ( ) - allocate new block
2014-08-09 01:21:08 +04:00
* @ inode : pointer to inode
2015-06-19 08:23:08 +03:00
* @ ind_block : block number of the indirect block
* @ index : number of pointer within the indirect block
2014-08-09 01:21:08 +04:00
* @ new_fragment : number of new allocated fragment
2006-06-25 16:47:27 +04:00
* ( block will hold this fragment and also uspi - > s_fpb - 1 )
2014-08-09 01:21:08 +04:00
* @ err : see ufs_inode_getfrag ( )
* @ phys : see ufs_inode_getfrag ( )
* @ new : see ufs_inode_getfrag ( )
* @ locked_page : see ufs_inode_getfrag ( )
2006-06-25 16:47:27 +04:00
*/
2015-06-19 07:53:06 +03:00
static u64
2015-06-19 08:23:08 +03:00
ufs_inode_getblock ( struct inode * inode , u64 ind_block ,
2015-06-19 08:06:21 +03:00
unsigned index , sector_t new_fragment , int * err ,
2006-06-25 16:47:27 +04:00
long * phys , int * new , struct page * locked_page )
2005-04-17 02:20:36 +04:00
{
2006-06-25 16:47:27 +04:00
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
2015-06-19 08:23:08 +03:00
int shift = uspi - > s_apbshift - uspi - > s_fpbshift ;
2015-06-19 08:06:21 +03:00
u64 tmp = 0 , goal ;
2015-06-19 08:23:08 +03:00
struct buffer_head * bh ;
2007-02-12 11:54:32 +03:00
void * p ;
2005-04-17 02:20:36 +04:00
2015-06-19 08:23:08 +03:00
if ( ! ind_block )
return 0 ;
bh = sb_bread ( sb , ind_block + ( index > > shift ) ) ;
2015-06-19 21:10:53 +03:00
if ( unlikely ( ! bh ) ) {
* err = - EIO ;
2015-06-19 08:23:08 +03:00
return 0 ;
2015-06-19 21:10:53 +03:00
}
2015-06-19 08:23:08 +03:00
index & = uspi - > s_apbmask > > uspi - > s_fpbshift ;
2007-02-12 11:54:32 +03:00
if ( uspi - > fs_magic = = UFS2_MAGIC )
2015-06-19 08:06:21 +03:00
p = ( __fs64 * ) bh - > b_data + index ;
2007-02-12 11:54:32 +03:00
else
2015-06-19 08:06:21 +03:00
p = ( __fs32 * ) bh - > b_data + index ;
2015-06-19 05:39:46 +03:00
2007-02-12 11:54:32 +03:00
tmp = ufs_data_ptr_to_cpu ( sb , p ) ;
2015-06-19 07:10:00 +03:00
if ( tmp )
2015-06-19 05:39:46 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
2015-06-19 08:06:21 +03:00
if ( index & & ( uspi - > fs_magic = = UFS2_MAGIC ?
( tmp = fs64_to_cpu ( sb , ( ( __fs64 * ) bh - > b_data ) [ index - 1 ] ) ) :
( tmp = fs32_to_cpu ( sb , ( ( __fs32 * ) bh - > b_data ) [ index - 1 ] ) ) ) )
2005-04-17 02:20:36 +04:00
goal = tmp + uspi - > s_fpb ;
else
goal = bh - > b_blocknr + uspi - > s_fpb ;
2006-06-25 16:47:20 +04:00
tmp = ufs_new_fragments ( inode , p , ufs_blknum ( new_fragment ) , goal ,
uspi - > s_fpb , err , locked_page ) ;
2015-06-19 05:39:46 +03:00
if ( ! tmp )
2005-04-17 02:20:36 +04:00
goto out ;
2006-06-25 16:47:19 +04:00
2015-06-19 07:10:00 +03:00
if ( new )
2005-04-17 02:20:36 +04:00
* new = 1 ;
mark_buffer_dirty ( bh ) ;
if ( IS_SYNC ( inode ) )
sync_dirty_buffer ( bh ) ;
inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
out :
brelse ( bh ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2015-06-19 07:53:06 +03:00
if ( tmp )
tmp + = uspi - > s_sbbase ;
return tmp ;
2005-04-17 02:20:36 +04:00
}
2006-06-25 16:47:27 +04:00
/**
2011-04-08 21:33:07 +04:00
* ufs_getfrag_block ( ) - ` get_block_t ' function , interface between UFS and
2006-06-25 16:47:27 +04:00
* readpage , writepage and so on
2005-04-17 02:20:36 +04:00
*/
2015-06-17 19:44:14 +03:00
static int ufs_getfrag_block ( struct inode * inode , sector_t fragment , struct buffer_head * bh_result , int create )
2005-04-17 02:20:36 +04:00
{
2015-06-19 21:20:21 +03:00
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
int err = 0 , new = 0 ;
2015-06-04 21:27:23 +03:00
unsigned offsets [ 4 ] ;
int depth = ufs_block_to_path ( inode , fragment > > uspi - > s_fpbshift , offsets ) ;
2005-04-17 02:20:36 +04:00
u64 phys64 = 0 ;
2015-06-19 21:20:21 +03:00
unsigned long phys ;
2015-06-19 07:53:06 +03:00
unsigned frag = fragment & uspi - > s_fpbmask ;
2015-06-17 19:44:14 +03:00
2005-04-17 02:20:36 +04:00
if ( ! create ) {
2015-06-04 21:27:23 +03:00
phys64 = ufs_frag_map ( inode , offsets , depth ) ;
2015-06-19 21:20:21 +03:00
goto out ;
2005-04-17 02:20:36 +04:00
}
/* This code entered only while writing ....? */
2015-06-17 19:02:56 +03:00
mutex_lock ( & UFS_I ( inode ) - > truncate_mutex ) ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:24 +04:00
UFSD ( " ENTER, ino %lu, fragment %llu \n " , inode - > i_ino , ( unsigned long long ) fragment ) ;
2015-06-19 21:20:21 +03:00
if ( unlikely ( ! depth ) ) {
ufs_warning ( sb , " ufs_get_block " , " block > big " ) ;
err = - EIO ;
goto out ;
}
2015-06-19 20:40:25 +03:00
if ( UFS_I ( inode ) - > i_lastfrag < UFS_NDIR_FRAGMENT ) {
unsigned lastfrag = UFS_I ( inode ) - > i_lastfrag ;
unsigned tailfrags = lastfrag & uspi - > s_fpbmask ;
if ( tailfrags & & fragment > = lastfrag ) {
if ( ! ufs_extend_tail ( inode , fragment ,
& err , bh_result - > b_page ) )
2015-06-19 21:20:21 +03:00
goto out ;
2015-06-19 20:40:25 +03:00
}
}
2015-06-04 21:34:43 +03:00
if ( depth = = 1 ) {
2015-06-19 20:53:52 +03:00
phys64 = ufs_inode_getfrag ( inode , offsets [ 0 ] , fragment ,
& err , & phys , & new , bh_result - > b_page ) ;
2015-06-19 21:08:16 +03:00
} else {
int i ;
2015-06-19 20:53:52 +03:00
phys64 = ufs_inode_getfrag ( inode , offsets [ 0 ] , fragment ,
& err , NULL , NULL , bh_result - > b_page ) ;
2015-06-19 21:08:16 +03:00
for ( i = 1 ; i < depth - 1 ; i + + )
phys64 = ufs_inode_getblock ( inode , phys64 , offsets [ i ] ,
fragment , & err , NULL , NULL , NULL ) ;
phys64 = ufs_inode_getblock ( inode , phys64 , offsets [ depth - 1 ] ,
fragment , & err , & phys , & new , bh_result - > b_page ) ;
2005-04-17 02:20:36 +04:00
}
2015-06-19 21:20:21 +03:00
out :
2015-06-19 07:53:06 +03:00
if ( phys64 ) {
phys64 + = frag ;
2015-06-19 21:20:21 +03:00
map_bh ( bh_result , sb , phys64 ) ;
if ( new )
set_buffer_new ( bh_result ) ;
2015-06-19 07:53:06 +03:00
}
2015-06-17 19:02:56 +03:00
mutex_unlock ( & UFS_I ( inode ) - > truncate_mutex ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
static int ufs_writepage ( struct page * page , struct writeback_control * wbc )
{
return block_write_full_page ( page , ufs_getfrag_block , wbc ) ;
}
2007-10-16 12:25:19 +04:00
2005-04-17 02:20:36 +04:00
static int ufs_readpage ( struct file * file , struct page * page )
{
return block_read_full_page ( page , ufs_getfrag_block ) ;
}
2007-10-16 12:25:19 +04:00
2010-06-04 13:29:56 +04:00
int ufs_prepare_chunk ( struct page * page , loff_t pos , unsigned len )
2005-04-17 02:20:36 +04:00
{
2010-06-04 13:29:57 +04:00
return __block_write_begin ( page , pos , len , ufs_getfrag_block ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-16 12:25:19 +04:00
2015-06-17 19:44:14 +03:00
static void ufs_truncate_blocks ( struct inode * ) ;
2012-12-15 14:45:14 +04:00
static void ufs_write_failed ( struct address_space * mapping , loff_t to )
{
struct inode * inode = mapping - > host ;
2015-06-17 01:06:40 +03:00
if ( to > inode - > i_size ) {
2013-09-13 02:13:56 +04:00
truncate_pagecache ( inode , inode - > i_size ) ;
2015-06-17 01:06:40 +03:00
ufs_truncate_blocks ( inode ) ;
}
2012-12-15 14:45:14 +04:00
}
2007-10-16 12:25:19 +04:00
static int ufs_write_begin ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned flags ,
struct page * * pagep , void * * fsdata )
{
2010-06-04 13:29:58 +04:00
int ret ;
ret = block_write_begin ( mapping , pos , len , flags , pagep ,
2010-06-04 13:29:56 +04:00
ufs_getfrag_block ) ;
2012-12-15 14:45:14 +04:00
if ( unlikely ( ret ) )
ufs_write_failed ( mapping , pos + len ) ;
2010-06-04 13:29:58 +04:00
return ret ;
2007-10-16 12:25:19 +04:00
}
2015-06-17 01:06:40 +03:00
static int ufs_write_end ( struct file * file , struct address_space * mapping ,
loff_t pos , unsigned len , unsigned copied ,
struct page * page , void * fsdata )
{
int ret ;
ret = generic_write_end ( file , mapping , pos , len , copied , page , fsdata ) ;
if ( ret < len )
ufs_write_failed ( mapping , pos + len ) ;
return ret ;
}
2005-04-17 02:20:36 +04:00
static sector_t ufs_bmap ( struct address_space * mapping , sector_t block )
{
return generic_block_bmap ( mapping , block , ufs_getfrag_block ) ;
}
2007-10-16 12:25:19 +04:00
2006-06-28 15:26:44 +04:00
const struct address_space_operations ufs_aops = {
2005-04-17 02:20:36 +04:00
. readpage = ufs_readpage ,
. writepage = ufs_writepage ,
2007-10-16 12:25:19 +04:00
. write_begin = ufs_write_begin ,
2015-06-17 01:06:40 +03:00
. write_end = ufs_write_end ,
2005-04-17 02:20:36 +04:00
. bmap = ufs_bmap
} ;
2006-06-25 16:47:21 +04:00
static void ufs_set_inode_ops ( struct inode * inode )
{
if ( S_ISREG ( inode - > i_mode ) ) {
inode - > i_op = & ufs_file_inode_operations ;
inode - > i_fop = & ufs_file_operations ;
inode - > i_mapping - > a_ops = & ufs_aops ;
} else if ( S_ISDIR ( inode - > i_mode ) ) {
inode - > i_op = & ufs_dir_inode_operations ;
inode - > i_fop = & ufs_dir_operations ;
inode - > i_mapping - > a_ops = & ufs_aops ;
} else if ( S_ISLNK ( inode - > i_mode ) ) {
2015-05-02 17:28:56 +03:00
if ( ! inode - > i_blocks ) {
2006-06-25 16:47:21 +04:00
inode - > i_op = & ufs_fast_symlink_inode_operations ;
2015-05-02 17:28:56 +03:00
inode - > i_link = ( char * ) UFS_I ( inode ) - > i_u1 . i_symlink ;
} else {
2010-04-15 02:56:58 +04:00
inode - > i_op = & ufs_symlink_inode_operations ;
2006-06-25 16:47:21 +04:00
inode - > i_mapping - > a_ops = & ufs_aops ;
}
} else
init_special_inode ( inode , inode - > i_mode ,
ufs_get_inode_dev ( inode - > i_sb , UFS_I ( inode ) ) ) ;
}
2007-04-17 09:53:24 +04:00
static int ufs1_read_inode ( struct inode * inode , struct ufs_inode * ufs_inode )
2005-04-17 02:20:36 +04:00
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
2006-06-27 13:53:59 +04:00
struct super_block * sb = inode - > i_sb ;
2011-07-26 10:49:13 +04:00
umode_t mode ;
2005-04-17 02:20:36 +04:00
/*
* Copy data to the in - core inode .
*/
inode - > i_mode = mode = fs16_to_cpu ( sb , ufs_inode - > ui_mode ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , fs16_to_cpu ( sb , ufs_inode - > ui_nlink ) ) ;
2007-04-17 09:53:24 +04:00
if ( inode - > i_nlink = = 0 ) {
2005-04-17 02:20:36 +04:00
ufs_error ( sb , " ufs_read_inode " , " inode %lu has zero nlink \n " , inode - > i_ino ) ;
2007-04-17 09:53:24 +04:00
return - 1 ;
}
2015-06-17 19:44:14 +03:00
2005-04-17 02:20:36 +04:00
/*
* Linux now has 32 - bit uid and gid , so we can support EFT .
*/
2012-02-11 00:21:22 +04:00
i_uid_write ( inode , ufs_get_inode_uid ( sb , ufs_inode ) ) ;
i_gid_write ( inode , ufs_get_inode_gid ( sb , ufs_inode ) ) ;
2005-04-17 02:20:36 +04:00
inode - > i_size = fs64_to_cpu ( sb , ufs_inode - > ui_size ) ;
inode - > i_atime . tv_sec = fs32_to_cpu ( sb , ufs_inode - > ui_atime . tv_sec ) ;
inode - > i_ctime . tv_sec = fs32_to_cpu ( sb , ufs_inode - > ui_ctime . tv_sec ) ;
inode - > i_mtime . tv_sec = fs32_to_cpu ( sb , ufs_inode - > ui_mtime . tv_sec ) ;
inode - > i_mtime . tv_nsec = 0 ;
inode - > i_atime . tv_nsec = 0 ;
inode - > i_ctime . tv_nsec = 0 ;
inode - > i_blocks = fs32_to_cpu ( sb , ufs_inode - > ui_blocks ) ;
2007-02-12 11:54:31 +03:00
inode - > i_generation = fs32_to_cpu ( sb , ufs_inode - > ui_gen ) ;
2005-04-17 02:20:36 +04:00
ufsi - > i_flags = fs32_to_cpu ( sb , ufs_inode - > ui_flags ) ;
ufsi - > i_shadow = fs32_to_cpu ( sb , ufs_inode - > ui_u3 . ui_sun . ui_shadow ) ;
ufsi - > i_oeftflag = fs32_to_cpu ( sb , ufs_inode - > ui_u3 . ui_sun . ui_oeftflag ) ;
2006-06-27 13:53:59 +04:00
2015-06-17 19:44:14 +03:00
2005-04-17 02:20:36 +04:00
if ( S_ISCHR ( mode ) | | S_ISBLK ( mode ) | | inode - > i_blocks ) {
2009-01-09 01:43:49 +03:00
memcpy ( ufsi - > i_u1 . i_data , & ufs_inode - > ui_u2 . ui_addr ,
sizeof ( ufs_inode - > ui_u2 . ui_addr ) ) ;
2006-06-25 16:47:25 +04:00
} else {
2009-01-09 01:43:49 +03:00
memcpy ( ufsi - > i_u1 . i_symlink , ufs_inode - > ui_u2 . ui_symlink ,
2009-01-09 01:43:50 +03:00
sizeof ( ufs_inode - > ui_u2 . ui_symlink ) - 1 ) ;
ufsi - > i_u1 . i_symlink [ sizeof ( ufs_inode - > ui_u2 . ui_symlink ) - 1 ] = 0 ;
2005-04-17 02:20:36 +04:00
}
2007-04-17 09:53:24 +04:00
return 0 ;
2006-06-27 13:53:59 +04:00
}
2005-04-17 02:20:36 +04:00
2007-04-17 09:53:24 +04:00
static int ufs2_read_inode ( struct inode * inode , struct ufs2_inode * ufs2_inode )
2006-06-27 13:53:59 +04:00
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
struct super_block * sb = inode - > i_sb ;
2011-07-26 10:49:13 +04:00
umode_t mode ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:47:24 +04:00
UFSD ( " Reading ufs2 inode, ino %lu \n " , inode - > i_ino ) ;
2005-04-17 02:20:36 +04:00
/*
* Copy data to the in - core inode .
*/
inode - > i_mode = mode = fs16_to_cpu ( sb , ufs2_inode - > ui_mode ) ;
2011-10-28 16:13:29 +04:00
set_nlink ( inode , fs16_to_cpu ( sb , ufs2_inode - > ui_nlink ) ) ;
2007-04-17 09:53:24 +04:00
if ( inode - > i_nlink = = 0 ) {
2005-04-17 02:20:36 +04:00
ufs_error ( sb , " ufs_read_inode " , " inode %lu has zero nlink \n " , inode - > i_ino ) ;
2007-04-17 09:53:24 +04:00
return - 1 ;
}
2005-04-17 02:20:36 +04:00
/*
* Linux now has 32 - bit uid and gid , so we can support EFT .
*/
2012-02-11 00:21:22 +04:00
i_uid_write ( inode , fs32_to_cpu ( sb , ufs2_inode - > ui_uid ) ) ;
i_gid_write ( inode , fs32_to_cpu ( sb , ufs2_inode - > ui_gid ) ) ;
2005-04-17 02:20:36 +04:00
inode - > i_size = fs64_to_cpu ( sb , ufs2_inode - > ui_size ) ;
2007-03-17 00:38:07 +03:00
inode - > i_atime . tv_sec = fs64_to_cpu ( sb , ufs2_inode - > ui_atime ) ;
inode - > i_ctime . tv_sec = fs64_to_cpu ( sb , ufs2_inode - > ui_ctime ) ;
inode - > i_mtime . tv_sec = fs64_to_cpu ( sb , ufs2_inode - > ui_mtime ) ;
inode - > i_atime . tv_nsec = fs32_to_cpu ( sb , ufs2_inode - > ui_atimensec ) ;
inode - > i_ctime . tv_nsec = fs32_to_cpu ( sb , ufs2_inode - > ui_ctimensec ) ;
inode - > i_mtime . tv_nsec = fs32_to_cpu ( sb , ufs2_inode - > ui_mtimensec ) ;
2005-04-17 02:20:36 +04:00
inode - > i_blocks = fs64_to_cpu ( sb , ufs2_inode - > ui_blocks ) ;
2007-02-12 11:54:31 +03:00
inode - > i_generation = fs32_to_cpu ( sb , ufs2_inode - > ui_gen ) ;
2005-04-17 02:20:36 +04:00
ufsi - > i_flags = fs32_to_cpu ( sb , ufs2_inode - > ui_flags ) ;
/*
ufsi - > i_shadow = fs32_to_cpu ( sb , ufs_inode - > ui_u3 . ui_sun . ui_shadow ) ;
ufsi - > i_oeftflag = fs32_to_cpu ( sb , ufs_inode - > ui_u3 . ui_sun . ui_oeftflag ) ;
*/
if ( S_ISCHR ( mode ) | | S_ISBLK ( mode ) | | inode - > i_blocks ) {
2009-01-09 01:43:49 +03:00
memcpy ( ufsi - > i_u1 . u2_i_data , & ufs2_inode - > ui_u2 . ui_addr ,
sizeof ( ufs2_inode - > ui_u2 . ui_addr ) ) ;
2006-06-27 13:53:59 +04:00
} else {
2009-01-09 01:43:49 +03:00
memcpy ( ufsi - > i_u1 . i_symlink , ufs2_inode - > ui_u2 . ui_symlink ,
2009-01-09 01:43:50 +03:00
sizeof ( ufs2_inode - > ui_u2 . ui_symlink ) - 1 ) ;
ufsi - > i_u1 . i_symlink [ sizeof ( ufs2_inode - > ui_u2 . ui_symlink ) - 1 ] = 0 ;
2005-04-17 02:20:36 +04:00
}
2007-04-17 09:53:24 +04:00
return 0 ;
2006-06-27 13:53:59 +04:00
}
2008-02-07 11:15:48 +03:00
struct inode * ufs_iget ( struct super_block * sb , unsigned long ino )
2006-06-27 13:53:59 +04:00
{
2008-02-07 11:15:48 +03:00
struct ufs_inode_info * ufsi ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
2006-06-27 13:53:59 +04:00
struct buffer_head * bh ;
2008-02-07 11:15:48 +03:00
struct inode * inode ;
2007-04-17 09:53:24 +04:00
int err ;
2006-06-27 13:53:59 +04:00
2008-02-07 11:15:48 +03:00
UFSD ( " ENTER, ino %lu \n " , ino ) ;
2006-06-27 13:53:59 +04:00
2008-02-07 11:15:48 +03:00
if ( ino < UFS_ROOTINO | | ino > ( uspi - > s_ncg * uspi - > s_ipg ) ) {
2006-06-27 13:53:59 +04:00
ufs_warning ( sb , " ufs_read_inode " , " bad inode number (%lu) \n " ,
2008-02-07 11:15:48 +03:00
ino ) ;
return ERR_PTR ( - EIO ) ;
2006-06-27 13:53:59 +04:00
}
2008-02-07 11:15:48 +03:00
inode = iget_locked ( sb , ino ) ;
if ( ! inode )
return ERR_PTR ( - ENOMEM ) ;
if ( ! ( inode - > i_state & I_NEW ) )
return inode ;
ufsi = UFS_I ( inode ) ;
2006-06-27 13:53:59 +04:00
bh = sb_bread ( sb , uspi - > s_sbbase + ufs_inotofsba ( inode - > i_ino ) ) ;
if ( ! bh ) {
ufs_warning ( sb , " ufs_read_inode " , " unable to read inode %lu \n " ,
inode - > i_ino ) ;
goto bad_inode ;
}
if ( ( UFS_SB ( sb ) - > s_flags & UFS_TYPE_MASK ) = = UFS_TYPE_UFS2 ) {
struct ufs2_inode * ufs2_inode = ( struct ufs2_inode * ) bh - > b_data ;
2007-04-17 09:53:24 +04:00
err = ufs2_read_inode ( inode ,
ufs2_inode + ufs_inotofsbo ( inode - > i_ino ) ) ;
2006-06-27 13:53:59 +04:00
} else {
struct ufs_inode * ufs_inode = ( struct ufs_inode * ) bh - > b_data ;
2007-04-17 09:53:24 +04:00
err = ufs1_read_inode ( inode ,
ufs_inode + ufs_inotofsbo ( inode - > i_ino ) ) ;
2006-06-27 13:53:59 +04:00
}
2007-04-17 09:53:24 +04:00
if ( err )
goto bad_inode ;
2006-06-27 13:53:59 +04:00
inode - > i_version + + ;
ufsi - > i_lastfrag =
( inode - > i_size + uspi - > s_fsize - 1 ) > > uspi - > s_fshift ;
ufsi - > i_dir_start_lookup = 0 ;
2005-04-17 02:20:36 +04:00
ufsi - > i_osync = 0 ;
2006-06-25 16:47:21 +04:00
ufs_set_inode_ops ( inode ) ;
2005-04-17 02:20:36 +04:00
brelse ( bh ) ;
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2008-02-07 11:15:48 +03:00
unlock_new_inode ( inode ) ;
return inode ;
2006-06-27 13:53:59 +04:00
bad_inode :
2008-02-07 11:15:48 +03:00
iget_failed ( inode ) ;
return ERR_PTR ( - EIO ) ;
2005-04-17 02:20:36 +04:00
}
2007-02-12 11:54:31 +03:00
static void ufs1_update_inode ( struct inode * inode , struct ufs_inode * ufs_inode )
2005-04-17 02:20:36 +04:00
{
2007-02-12 11:54:31 +03:00
struct super_block * sb = inode - > i_sb ;
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
2005-04-17 02:20:36 +04:00
ufs_inode - > ui_mode = cpu_to_fs16 ( sb , inode - > i_mode ) ;
ufs_inode - > ui_nlink = cpu_to_fs16 ( sb , inode - > i_nlink ) ;
2012-02-11 00:21:22 +04:00
ufs_set_inode_uid ( sb , ufs_inode , i_uid_read ( inode ) ) ;
ufs_set_inode_gid ( sb , ufs_inode , i_gid_read ( inode ) ) ;
2015-06-17 19:44:14 +03:00
2005-04-17 02:20:36 +04:00
ufs_inode - > ui_size = cpu_to_fs64 ( sb , inode - > i_size ) ;
ufs_inode - > ui_atime . tv_sec = cpu_to_fs32 ( sb , inode - > i_atime . tv_sec ) ;
ufs_inode - > ui_atime . tv_usec = 0 ;
ufs_inode - > ui_ctime . tv_sec = cpu_to_fs32 ( sb , inode - > i_ctime . tv_sec ) ;
ufs_inode - > ui_ctime . tv_usec = 0 ;
ufs_inode - > ui_mtime . tv_sec = cpu_to_fs32 ( sb , inode - > i_mtime . tv_sec ) ;
ufs_inode - > ui_mtime . tv_usec = 0 ;
ufs_inode - > ui_blocks = cpu_to_fs32 ( sb , inode - > i_blocks ) ;
ufs_inode - > ui_flags = cpu_to_fs32 ( sb , ufsi - > i_flags ) ;
2007-02-12 11:54:31 +03:00
ufs_inode - > ui_gen = cpu_to_fs32 ( sb , inode - > i_generation ) ;
2005-04-17 02:20:36 +04:00
2007-02-12 11:54:31 +03:00
if ( ( UFS_SB ( sb ) - > s_flags & UFS_UID_MASK ) = = UFS_UID_EFT ) {
2005-04-17 02:20:36 +04:00
ufs_inode - > ui_u3 . ui_sun . ui_shadow = cpu_to_fs32 ( sb , ufsi - > i_shadow ) ;
ufs_inode - > ui_u3 . ui_sun . ui_oeftflag = cpu_to_fs32 ( sb , ufsi - > i_oeftflag ) ;
}
if ( S_ISCHR ( inode - > i_mode ) | | S_ISBLK ( inode - > i_mode ) ) {
/* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */
ufs_inode - > ui_u2 . ui_addr . ui_db [ 0 ] = ufsi - > i_u1 . i_data [ 0 ] ;
} else if ( inode - > i_blocks ) {
2009-01-09 01:43:49 +03:00
memcpy ( & ufs_inode - > ui_u2 . ui_addr , ufsi - > i_u1 . i_data ,
sizeof ( ufs_inode - > ui_u2 . ui_addr ) ) ;
2005-04-17 02:20:36 +04:00
}
else {
2009-01-09 01:43:49 +03:00
memcpy ( & ufs_inode - > ui_u2 . ui_symlink , ufsi - > i_u1 . i_symlink ,
sizeof ( ufs_inode - > ui_u2 . ui_symlink ) ) ;
2005-04-17 02:20:36 +04:00
}
if ( ! inode - > i_nlink )
memset ( ufs_inode , 0 , sizeof ( struct ufs_inode ) ) ;
2007-02-12 11:54:31 +03:00
}
static void ufs2_update_inode ( struct inode * inode , struct ufs2_inode * ufs_inode )
{
struct super_block * sb = inode - > i_sb ;
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
UFSD ( " ENTER \n " ) ;
ufs_inode - > ui_mode = cpu_to_fs16 ( sb , inode - > i_mode ) ;
ufs_inode - > ui_nlink = cpu_to_fs16 ( sb , inode - > i_nlink ) ;
2012-02-11 00:21:22 +04:00
ufs_inode - > ui_uid = cpu_to_fs32 ( sb , i_uid_read ( inode ) ) ;
ufs_inode - > ui_gid = cpu_to_fs32 ( sb , i_gid_read ( inode ) ) ;
2007-02-12 11:54:31 +03:00
ufs_inode - > ui_size = cpu_to_fs64 ( sb , inode - > i_size ) ;
2007-03-17 00:38:07 +03:00
ufs_inode - > ui_atime = cpu_to_fs64 ( sb , inode - > i_atime . tv_sec ) ;
ufs_inode - > ui_atimensec = cpu_to_fs32 ( sb , inode - > i_atime . tv_nsec ) ;
ufs_inode - > ui_ctime = cpu_to_fs64 ( sb , inode - > i_ctime . tv_sec ) ;
ufs_inode - > ui_ctimensec = cpu_to_fs32 ( sb , inode - > i_ctime . tv_nsec ) ;
ufs_inode - > ui_mtime = cpu_to_fs64 ( sb , inode - > i_mtime . tv_sec ) ;
ufs_inode - > ui_mtimensec = cpu_to_fs32 ( sb , inode - > i_mtime . tv_nsec ) ;
2007-02-12 11:54:31 +03:00
ufs_inode - > ui_blocks = cpu_to_fs64 ( sb , inode - > i_blocks ) ;
ufs_inode - > ui_flags = cpu_to_fs32 ( sb , ufsi - > i_flags ) ;
ufs_inode - > ui_gen = cpu_to_fs32 ( sb , inode - > i_generation ) ;
if ( S_ISCHR ( inode - > i_mode ) | | S_ISBLK ( inode - > i_mode ) ) {
/* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */
ufs_inode - > ui_u2 . ui_addr . ui_db [ 0 ] = ufsi - > i_u1 . u2_i_data [ 0 ] ;
} else if ( inode - > i_blocks ) {
2009-01-09 01:43:49 +03:00
memcpy ( & ufs_inode - > ui_u2 . ui_addr , ufsi - > i_u1 . u2_i_data ,
sizeof ( ufs_inode - > ui_u2 . ui_addr ) ) ;
2007-02-12 11:54:31 +03:00
} else {
2009-01-09 01:43:49 +03:00
memcpy ( & ufs_inode - > ui_u2 . ui_symlink , ufsi - > i_u1 . i_symlink ,
sizeof ( ufs_inode - > ui_u2 . ui_symlink ) ) ;
2007-02-12 11:54:31 +03:00
}
if ( ! inode - > i_nlink )
memset ( ufs_inode , 0 , sizeof ( struct ufs2_inode ) ) ;
UFSD ( " EXIT \n " ) ;
}
static int ufs_update_inode ( struct inode * inode , int do_sync )
{
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
struct buffer_head * bh ;
UFSD ( " ENTER, ino %lu \n " , inode - > i_ino ) ;
if ( inode - > i_ino < UFS_ROOTINO | |
inode - > i_ino > ( uspi - > s_ncg * uspi - > s_ipg ) ) {
ufs_warning ( sb , " ufs_read_inode " , " bad inode number (%lu) \n " , inode - > i_ino ) ;
return - 1 ;
}
bh = sb_bread ( sb , ufs_inotofsba ( inode - > i_ino ) ) ;
if ( ! bh ) {
ufs_warning ( sb , " ufs_read_inode " , " unable to read inode %lu \n " , inode - > i_ino ) ;
return - 1 ;
}
if ( uspi - > fs_magic = = UFS2_MAGIC ) {
struct ufs2_inode * ufs2_inode = ( struct ufs2_inode * ) bh - > b_data ;
ufs2_update_inode ( inode ,
ufs2_inode + ufs_inotofsbo ( inode - > i_ino ) ) ;
} else {
struct ufs_inode * ufs_inode = ( struct ufs_inode * ) bh - > b_data ;
ufs1_update_inode ( inode , ufs_inode + ufs_inotofsbo ( inode - > i_ino ) ) ;
}
2015-06-17 19:44:14 +03:00
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( bh ) ;
if ( do_sync )
sync_dirty_buffer ( bh ) ;
brelse ( bh ) ;
2015-06-17 19:44:14 +03:00
2006-06-25 16:47:24 +04:00
UFSD ( " EXIT \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2010-03-05 11:21:37 +03:00
int ufs_write_inode ( struct inode * inode , struct writeback_control * wbc )
2005-04-17 02:20:36 +04:00
{
2015-06-16 09:35:14 +03:00
return ufs_update_inode ( inode , wbc - > sync_mode = = WB_SYNC_ALL ) ;
2005-04-17 02:20:36 +04:00
}
int ufs_sync_inode ( struct inode * inode )
{
return ufs_update_inode ( inode , 1 ) ;
}
2010-06-06 03:40:56 +04:00
void ufs_evict_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2010-06-06 03:40:56 +04:00
int want_delete = 0 ;
if ( ! inode - > i_nlink & & ! is_bad_inode ( inode ) )
want_delete = 1 ;
2006-07-01 15:36:24 +04:00
2014-04-04 01:47:49 +04:00
truncate_inode_pages_final ( & inode - > i_data ) ;
2010-06-06 03:40:56 +04:00
if ( want_delete ) {
inode - > i_size = 0 ;
2015-06-17 01:04:16 +03:00
if ( inode - > i_blocks )
ufs_truncate_blocks ( inode ) ;
2010-06-06 03:40:56 +04:00
}
invalidate_inode_buffers ( inode ) ;
2012-05-03 16:48:02 +04:00
clear_inode ( inode ) ;
2010-06-06 03:40:56 +04:00
2015-06-16 09:35:14 +03:00
if ( want_delete )
2014-09-02 11:40:17 +04:00
ufs_free_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
}
2015-06-17 19:44:14 +03:00
2015-06-18 09:18:54 +03:00
struct to_free {
struct inode * inode ;
u64 to ;
unsigned count ;
} ;
static inline void free_data ( struct to_free * ctx , u64 from , unsigned count )
{
if ( ctx - > count & & ctx - > to ! = from ) {
ufs_free_blocks ( ctx - > inode , ctx - > to - ctx - > count , ctx - > count ) ;
ctx - > count = 0 ;
}
ctx - > count + = count ;
ctx - > to = from + count ;
}
2015-06-17 19:44:14 +03:00
# define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
# define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
static void ufs_trunc_direct ( struct inode * inode )
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
struct super_block * sb ;
struct ufs_sb_private_info * uspi ;
void * p ;
u64 frag1 , frag2 , frag3 , frag4 , block1 , block2 ;
2015-06-18 09:18:54 +03:00
struct to_free ctx = { . inode = inode } ;
2015-06-17 19:44:14 +03:00
unsigned i , tmp ;
UFSD ( " ENTER: ino %lu \n " , inode - > i_ino ) ;
sb = inode - > i_sb ;
uspi = UFS_SB ( sb ) - > s_uspi ;
frag1 = DIRECT_FRAGMENT ;
frag4 = min_t ( u64 , UFS_NDIR_FRAGMENT , ufsi - > i_lastfrag ) ;
frag2 = ( ( frag1 & uspi - > s_fpbmask ) ? ( ( frag1 | uspi - > s_fpbmask ) + 1 ) : frag1 ) ;
frag3 = frag4 & ~ uspi - > s_fpbmask ;
block1 = block2 = 0 ;
if ( frag2 > frag3 ) {
frag2 = frag4 ;
frag3 = frag4 = 0 ;
} else if ( frag2 < frag3 ) {
block1 = ufs_fragstoblks ( frag2 ) ;
block2 = ufs_fragstoblks ( frag3 ) ;
}
UFSD ( " ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu, "
" frag3 %llu, frag4 %llu \n " , inode - > i_ino ,
( unsigned long long ) frag1 , ( unsigned long long ) frag2 ,
( unsigned long long ) block1 , ( unsigned long long ) block2 ,
( unsigned long long ) frag3 , ( unsigned long long ) frag4 ) ;
if ( frag1 > = frag2 )
goto next1 ;
/*
* Free first free fragments
*/
p = ufs_get_direct_data_ptr ( uspi , ufsi , ufs_fragstoblks ( frag1 ) ) ;
tmp = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( ! tmp )
ufs_panic ( sb , " ufs_trunc_direct " , " internal error " ) ;
frag2 - = frag1 ;
frag1 = ufs_fragnum ( frag1 ) ;
ufs_free_fragments ( inode , tmp + frag1 , frag2 ) ;
next1 :
/*
* Free whole blocks
*/
for ( i = block1 ; i < block2 ; i + + ) {
p = ufs_get_direct_data_ptr ( uspi , ufsi , i ) ;
tmp = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( ! tmp )
continue ;
write_seqlock ( & ufsi - > meta_lock ) ;
ufs_data_ptr_clear ( uspi , p ) ;
write_sequnlock ( & ufsi - > meta_lock ) ;
2015-06-18 09:18:54 +03:00
free_data ( & ctx , tmp , uspi - > s_fpb ) ;
2015-06-17 19:44:14 +03:00
}
2015-06-18 09:18:54 +03:00
free_data ( & ctx , 0 , 0 ) ;
2015-06-17 19:44:14 +03:00
if ( frag3 > = frag4 )
goto next3 ;
/*
* Free last free fragments
*/
p = ufs_get_direct_data_ptr ( uspi , ufsi , ufs_fragstoblks ( frag3 ) ) ;
tmp = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( ! tmp )
ufs_panic ( sb , " ufs_truncate_direct " , " internal error " ) ;
frag4 = ufs_fragnum ( frag4 ) ;
write_seqlock ( & ufsi - > meta_lock ) ;
ufs_data_ptr_clear ( uspi , p ) ;
write_sequnlock ( & ufsi - > meta_lock ) ;
ufs_free_fragments ( inode , tmp , frag4 ) ;
next3 :
UFSD ( " EXIT: ino %lu \n " , inode - > i_ino ) ;
}
2015-06-19 03:07:08 +03:00
static void free_full_branch ( struct inode * inode , u64 ind_block , int depth )
2015-06-19 00:11:49 +03:00
{
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
2015-06-19 03:07:08 +03:00
struct ufs_buffer_head * ubh = ubh_bread ( sb , ind_block , uspi - > s_bsize ) ;
2015-06-19 00:11:49 +03:00
unsigned i ;
2015-06-19 03:07:08 +03:00
if ( ! ubh )
2015-06-19 00:11:49 +03:00
return ;
if ( - - depth ) {
2015-06-19 03:07:08 +03:00
for ( i = 0 ; i < uspi - > s_apb ; i + + ) {
void * p = ubh_get_data_ptr ( uspi , ubh , i ) ;
u64 block = ufs_data_ptr_to_cpu ( sb , p ) ;
2015-06-19 03:14:02 +03:00
if ( block )
2015-06-19 03:07:08 +03:00
free_full_branch ( inode , block , depth ) ;
2015-06-19 00:11:49 +03:00
}
} else {
struct to_free ctx = { . inode = inode } ;
for ( i = 0 ; i < uspi - > s_apb ; i + + ) {
2015-06-19 03:07:08 +03:00
void * p = ubh_get_data_ptr ( uspi , ubh , i ) ;
u64 block = ufs_data_ptr_to_cpu ( sb , p ) ;
2015-06-19 03:14:02 +03:00
if ( block )
2015-06-19 03:07:08 +03:00
free_data ( & ctx , block , uspi - > s_fpb ) ;
2015-06-19 00:11:49 +03:00
}
free_data ( & ctx , 0 , 0 ) ;
}
ubh_bforget ( ubh ) ;
2015-06-19 03:07:08 +03:00
ufs_free_blocks ( inode , ind_block , uspi - > s_fpb ) ;
2015-06-19 00:11:49 +03:00
}
2015-06-19 02:13:02 +03:00
static void free_branch_tail ( struct inode * inode , unsigned from , struct ufs_buffer_head * ubh , int depth )
2015-06-17 19:44:14 +03:00
{
2015-06-18 21:21:09 +03:00
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
unsigned i ;
2015-06-17 19:44:14 +03:00
2015-06-18 22:33:47 +03:00
if ( - - depth ) {
2015-06-19 02:13:02 +03:00
for ( i = from ; i < uspi - > s_apb ; i + + ) {
2015-06-19 03:07:08 +03:00
void * p = ubh_get_data_ptr ( uspi , ubh , i ) ;
u64 block = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( block ) {
write_seqlock ( & UFS_I ( inode ) - > meta_lock ) ;
ufs_data_ptr_clear ( uspi , p ) ;
write_sequnlock ( & UFS_I ( inode ) - > meta_lock ) ;
ubh_mark_buffer_dirty ( ubh ) ;
free_full_branch ( inode , block , depth ) ;
}
2015-06-18 23:13:56 +03:00
}
2015-06-18 22:33:47 +03:00
} else {
2015-06-18 09:18:54 +03:00
struct to_free ctx = { . inode = inode } ;
2015-06-18 22:33:47 +03:00
for ( i = from ; i < uspi - > s_apb ; i + + ) {
2015-06-19 03:07:08 +03:00
void * p = ubh_get_data_ptr ( uspi , ubh , i ) ;
u64 block = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( block ) {
write_seqlock ( & UFS_I ( inode ) - > meta_lock ) ;
ufs_data_ptr_clear ( uspi , p ) ;
write_sequnlock ( & UFS_I ( inode ) - > meta_lock ) ;
ubh_mark_buffer_dirty ( ubh ) ;
free_data ( & ctx , block , uspi - > s_fpb ) ;
}
2015-06-18 22:33:47 +03:00
}
2015-06-18 09:18:54 +03:00
free_data ( & ctx , 0 , 0 ) ;
2015-06-17 19:44:14 +03:00
}
2015-06-18 22:33:47 +03:00
if ( IS_SYNC ( inode ) & & ubh_buffer_dirty ( ubh ) )
ubh_sync_block ( ubh ) ;
ubh_brelse ( ubh ) ;
2015-06-17 19:44:14 +03:00
}
static int ufs_alloc_lastblock ( struct inode * inode , loff_t size )
{
int err = 0 ;
struct super_block * sb = inode - > i_sb ;
struct address_space * mapping = inode - > i_mapping ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
unsigned i , end ;
sector_t lastfrag ;
struct page * lastpage ;
struct buffer_head * bh ;
u64 phys64 ;
lastfrag = ( size + uspi - > s_fsize - 1 ) > > uspi - > s_fshift ;
if ( ! lastfrag )
goto out ;
lastfrag - - ;
lastpage = ufs_get_locked_page ( mapping , lastfrag > >
( PAGE_CACHE_SHIFT - inode - > i_blkbits ) ) ;
if ( IS_ERR ( lastpage ) ) {
err = - EIO ;
goto out ;
}
end = lastfrag & ( ( 1 < < ( PAGE_CACHE_SHIFT - inode - > i_blkbits ) ) - 1 ) ;
bh = page_buffers ( lastpage ) ;
for ( i = 0 ; i < end ; + + i )
bh = bh - > b_this_page ;
err = ufs_getfrag_block ( inode , lastfrag , bh , 1 ) ;
if ( unlikely ( err ) )
goto out_unlock ;
if ( buffer_new ( bh ) ) {
clear_buffer_new ( bh ) ;
unmap_underlying_metadata ( bh - > b_bdev ,
bh - > b_blocknr ) ;
/*
* we do not zeroize fragment , because of
* if it maped to hole , it already contains zeroes
*/
set_buffer_uptodate ( bh ) ;
mark_buffer_dirty ( bh ) ;
set_page_dirty ( lastpage ) ;
}
if ( lastfrag > = UFS_IND_FRAGMENT ) {
end = uspi - > s_fpb - ufs_fragnum ( lastfrag ) - 1 ;
phys64 = bh - > b_blocknr + 1 ;
for ( i = 0 ; i < end ; + + i ) {
bh = sb_getblk ( sb , i + phys64 ) ;
lock_buffer ( bh ) ;
memset ( bh - > b_data , 0 , sb - > s_blocksize ) ;
set_buffer_uptodate ( bh ) ;
mark_buffer_dirty ( bh ) ;
unlock_buffer ( bh ) ;
sync_dirty_buffer ( bh ) ;
brelse ( bh ) ;
}
}
out_unlock :
ufs_put_locked_page ( lastpage ) ;
out :
return err ;
}
static void __ufs_truncate_blocks ( struct inode * inode )
{
struct ufs_inode_info * ufsi = UFS_I ( inode ) ;
struct super_block * sb = inode - > i_sb ;
struct ufs_sb_private_info * uspi = UFS_SB ( sb ) - > s_uspi ;
2015-06-18 21:21:09 +03:00
unsigned offsets [ 4 ] ;
2015-06-17 08:10:03 +03:00
int depth = ufs_block_to_path ( inode , DIRECT_BLOCK , offsets ) ;
2015-06-18 21:55:50 +03:00
int depth2 ;
2015-06-18 22:47:17 +03:00
unsigned i ;
2015-06-19 02:13:02 +03:00
struct ufs_buffer_head * ubh [ 3 ] ;
void * p ;
u64 block ;
2015-06-18 21:55:50 +03:00
if ( ! depth )
return ;
/* find the last non-zero in offsets[] */
for ( depth2 = depth - 1 ; depth2 ; depth2 - - )
if ( offsets [ depth2 ] )
break ;
2015-06-17 19:44:14 +03:00
mutex_lock ( & ufsi - > truncate_mutex ) ;
2015-06-18 22:47:17 +03:00
if ( depth = = 1 ) {
2015-06-17 08:10:03 +03:00
ufs_trunc_direct ( inode ) ;
2015-06-18 22:47:17 +03:00
offsets [ 0 ] = UFS_IND_BLOCK ;
} else {
2015-06-19 02:13:02 +03:00
/* get the blocks that should be partially emptied */
p = ufs_get_direct_data_ptr ( uspi , ufsi , offsets [ 0 ] ) ;
for ( i = 0 ; i < depth2 ; i + + ) {
offsets [ i ] + + ; /* next branch is fully freed */
block = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( ! block )
break ;
ubh [ i ] = ubh_bread ( sb , block , uspi - > s_bsize ) ;
if ( ! ubh [ i ] ) {
write_seqlock ( & ufsi - > meta_lock ) ;
ufs_data_ptr_clear ( uspi , p ) ;
write_sequnlock ( & ufsi - > meta_lock ) ;
break ;
}
p = ubh_get_data_ptr ( uspi , ubh [ i ] , offsets [ i + 1 ] ) ;
}
2015-06-19 03:17:32 +03:00
while ( i - - )
2015-06-19 02:13:02 +03:00
free_branch_tail ( inode , offsets [ i + 1 ] , ubh [ i ] , depth - i - 1 ) ;
2015-06-18 22:47:17 +03:00
}
for ( i = offsets [ 0 ] ; i < = UFS_TIND_BLOCK ; i + + ) {
2015-06-19 03:07:08 +03:00
p = ufs_get_direct_data_ptr ( uspi , ufsi , i ) ;
block = ufs_data_ptr_to_cpu ( sb , p ) ;
if ( block ) {
write_seqlock ( & ufsi - > meta_lock ) ;
ufs_data_ptr_clear ( uspi , p ) ;
write_sequnlock ( & ufsi - > meta_lock ) ;
free_full_branch ( inode , block , i - UFS_IND_BLOCK + 1 ) ;
}
2015-06-17 08:10:03 +03:00
}
2015-06-17 19:44:14 +03:00
ufsi - > i_lastfrag = DIRECT_FRAGMENT ;
2015-06-19 03:09:39 +03:00
mark_inode_dirty ( inode ) ;
2015-06-17 19:44:14 +03:00
mutex_unlock ( & ufsi - > truncate_mutex ) ;
}
static int ufs_truncate ( struct inode * inode , loff_t size )
{
int err = 0 ;
UFSD ( " ENTER: ino %lu, i_size: %llu, old_i_size: %llu \n " ,
inode - > i_ino , ( unsigned long long ) size ,
( unsigned long long ) i_size_read ( inode ) ) ;
if ( ! ( S_ISREG ( inode - > i_mode ) | | S_ISDIR ( inode - > i_mode ) | |
S_ISLNK ( inode - > i_mode ) ) )
return - EINVAL ;
if ( IS_APPEND ( inode ) | | IS_IMMUTABLE ( inode ) )
return - EPERM ;
err = ufs_alloc_lastblock ( inode , size ) ;
if ( err )
goto out ;
block_truncate_page ( inode - > i_mapping , size , ufs_getfrag_block ) ;
truncate_setsize ( inode , size ) ;
__ufs_truncate_blocks ( inode ) ;
inode - > i_mtime = inode - > i_ctime = CURRENT_TIME_SEC ;
mark_inode_dirty ( inode ) ;
out :
UFSD ( " EXIT: err %d \n " , err ) ;
return err ;
}
void ufs_truncate_blocks ( struct inode * inode )
{
if ( ! ( S_ISREG ( inode - > i_mode ) | | S_ISDIR ( inode - > i_mode ) | |
S_ISLNK ( inode - > i_mode ) ) )
return ;
if ( IS_APPEND ( inode ) | | IS_IMMUTABLE ( inode ) )
return ;
__ufs_truncate_blocks ( inode ) ;
}
int ufs_setattr ( struct dentry * dentry , struct iattr * attr )
{
struct inode * inode = d_inode ( dentry ) ;
unsigned int ia_valid = attr - > ia_valid ;
int error ;
error = inode_change_ok ( inode , attr ) ;
if ( error )
return error ;
if ( ia_valid & ATTR_SIZE & & attr - > ia_size ! = inode - > i_size ) {
error = ufs_truncate ( inode , attr - > ia_size ) ;
if ( error )
return error ;
}
setattr_copy ( inode , attr ) ;
mark_inode_dirty ( inode ) ;
return 0 ;
}
const struct inode_operations ufs_file_inode_operations = {
. setattr = ufs_setattr ,
} ;