2005-04-17 02:20:36 +04:00
/*
* inode . c
*
* PURPOSE
* Inode handling routines for the OSTA - UDF ( tm ) filesystem .
*
* COPYRIGHT
* This file is distributed under the terms of the GNU General Public
* License ( GPL ) . Copies of the GPL can be obtained from :
* ftp : //prep.ai.mit.edu/pub/gnu/GPL
* Each contributing author retains all rights to their own work .
*
* ( C ) 1998 Dave Boynton
* ( C ) 1998 - 2004 Ben Fennema
* ( C ) 1999 - 2000 Stelias Computing Inc
*
* HISTORY
*
* 10 / 04 / 98 dgb Added rudimentary directory functions
* 10 / 07 / 98 Fully working udf_block_map ! It works !
* 11 / 25 / 98 bmap altered to better support extents
2008-02-08 15:20:36 +03:00
* 12 / 06 / 98 blf partition support in udf_iget , udf_block_map
* and udf_read_inode
2005-04-17 02:20:36 +04:00
* 12 / 12 / 98 rewrote udf_block_map to handle next extents and descs across
* block boundaries ( which is not actually allowed )
* 12 / 20 / 98 added support for strategy 4096
* 03 / 07 / 99 rewrote udf_block_map ( again )
* New funcs , inode_bmap , udf_next_aext
* 04 / 19 / 99 Support for writing device EA ' s for major / minor #
*/
# include "udfdecl.h"
# include <linux/mm.h>
# include <linux/smp_lock.h>
# include <linux/module.h>
# include <linux/pagemap.h>
# include <linux/buffer_head.h>
# include <linux/writeback.h>
# include <linux/slab.h>
# include "udf_i.h"
# include "udf_sb.h"
MODULE_AUTHOR ( " Ben Fennema " ) ;
MODULE_DESCRIPTION ( " Universal Disk Format Filesystem " ) ;
MODULE_LICENSE ( " GPL " ) ;
# define EXTENT_MERGE_SIZE 5
static mode_t udf_convert_permissions ( struct fileEntry * ) ;
static int udf_update_inode ( struct inode * , int ) ;
static void udf_fill_inode ( struct inode * , struct buffer_head * ) ;
2007-07-16 10:39:47 +04:00
static int udf_alloc_i_data ( struct inode * inode , size_t size ) ;
2007-05-08 11:35:13 +04:00
static struct buffer_head * inode_getblk ( struct inode * , sector_t , int * ,
2008-02-08 15:20:48 +03:00
sector_t * , int * ) ;
2007-05-08 11:35:14 +04:00
static int8_t udf_insert_aext ( struct inode * , struct extent_position ,
2007-07-19 12:47:43 +04:00
kernel_lb_addr , uint32_t ) ;
2005-04-17 02:20:36 +04:00
static void udf_split_extents ( struct inode * , int * , int , int ,
2007-07-19 12:47:43 +04:00
kernel_long_ad [ EXTENT_MERGE_SIZE ] , int * ) ;
2005-04-17 02:20:36 +04:00
static void udf_prealloc_extents ( struct inode * , int , int ,
2007-07-19 12:47:43 +04:00
kernel_long_ad [ EXTENT_MERGE_SIZE ] , int * ) ;
2005-04-17 02:20:36 +04:00
static void udf_merge_extents ( struct inode * ,
2007-07-19 12:47:43 +04:00
kernel_long_ad [ EXTENT_MERGE_SIZE ] , int * ) ;
2005-04-17 02:20:36 +04:00
static void udf_update_extents ( struct inode * ,
2007-07-19 12:47:43 +04:00
kernel_long_ad [ EXTENT_MERGE_SIZE ] , int , int ,
struct extent_position * ) ;
2005-04-17 02:20:36 +04:00
static int udf_get_block ( struct inode * , sector_t , struct buffer_head * , int ) ;
/*
* udf_delete_inode
*
* PURPOSE
* Clean - up before the specified inode is destroyed .
*
* DESCRIPTION
* This routine is called when the kernel destroys an inode structure
* ie . when iput ( ) finds i_count = = 0.
*
* HISTORY
* July 1 , 1997 - Andrew E . Mileski
* Written , tested , and released .
*
* Called at the last iput ( ) if i_nlink is zero .
*/
2007-07-19 12:47:43 +04:00
void udf_delete_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2005-09-10 00:01:31 +04:00
truncate_inode_pages ( & inode - > i_data , 0 ) ;
2005-04-17 02:20:36 +04:00
if ( is_bad_inode ( inode ) )
goto no_delete ;
inode - > i_size = 0 ;
udf_truncate ( inode ) ;
lock_kernel ( ) ;
udf_update_inode ( inode , IS_SYNC ( inode ) ) ;
udf_free_inode ( inode ) ;
unlock_kernel ( ) ;
return ;
2007-07-21 15:37:18 +04:00
no_delete :
2005-04-17 02:20:36 +04:00
clear_inode ( inode ) ;
}
2007-06-16 21:16:14 +04:00
/*
* If we are going to release inode from memory , we discard preallocation and
* truncate last inode extent to proper length . We could use drop_inode ( ) but
* it ' s called under inode_lock and thus we cannot mark inode dirty there . We
* use clear_inode ( ) but we have to make sure to write inode as it ' s not written
* automatically .
*/
2005-04-17 02:20:36 +04:00
void udf_clear_inode ( struct inode * inode )
{
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
if ( ! ( inode - > i_sb - > s_flags & MS_RDONLY ) ) {
lock_kernel ( ) ;
2007-06-16 21:16:14 +04:00
/* Discard preallocation for directories, symlinks, etc. */
2005-04-17 02:20:36 +04:00
udf_discard_prealloc ( inode ) ;
2007-06-16 21:16:14 +04:00
udf_truncate_tail_extent ( inode ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
2008-02-08 15:20:49 +03:00
write_inode_now ( inode , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
kfree ( iinfo - > i_ext . i_data ) ;
iinfo - > i_ext . i_data = NULL ;
2005-04-17 02:20:36 +04:00
}
static int udf_writepage ( struct page * page , struct writeback_control * wbc )
{
return block_write_full_page ( page , udf_get_block , wbc ) ;
}
static int udf_readpage ( struct file * file , struct page * page )
{
return block_read_full_page ( page , udf_get_block ) ;
}
2007-10-16 12:25:20 +04:00
static int udf_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
{
2007-10-16 12:25:20 +04:00
* pagep = NULL ;
return block_write_begin ( file , mapping , pos , len , flags , pagep , fsdata ,
udf_get_block ) ;
2005-04-17 02:20:36 +04:00
}
static sector_t udf_bmap ( struct address_space * mapping , sector_t block )
{
2007-07-19 12:47:43 +04:00
return generic_block_bmap ( mapping , block , udf_get_block ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-28 15:26:44 +04:00
const struct address_space_operations udf_aops = {
2007-07-21 15:37:18 +04:00
. readpage = udf_readpage ,
. writepage = udf_writepage ,
. sync_page = block_sync_page ,
2007-10-16 12:25:20 +04:00
. write_begin = udf_write_begin ,
. write_end = generic_write_end ,
2007-07-21 15:37:18 +04:00
. bmap = udf_bmap ,
2005-04-17 02:20:36 +04:00
} ;
2007-07-19 12:47:43 +04:00
void udf_expand_file_adinicb ( struct inode * inode , int newsize , int * err )
2005-04-17 02:20:36 +04:00
{
struct page * page ;
char * kaddr ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
struct writeback_control udf_wbc = {
. sync_mode = WB_SYNC_NONE ,
. nr_to_write = 1 ,
} ;
/* from now on we have normal address_space methods */
inode - > i_data . a_ops = & udf_aops ;
2008-02-08 15:20:44 +03:00
if ( ! iinfo - > i_lenAlloc ) {
2005-04-17 02:20:36 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_USE_SHORT_AD ) )
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_SHORT ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_LONG ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
return ;
}
page = grab_cache_page ( inode - > i_mapping , 0 ) ;
2005-05-01 19:59:01 +04:00
BUG_ON ( ! PageLocked ( page ) ) ;
2007-07-19 12:47:43 +04:00
if ( ! PageUptodate ( page ) ) {
2005-04-17 02:20:36 +04:00
kaddr = kmap ( page ) ;
2008-02-08 15:20:44 +03:00
memset ( kaddr + iinfo - > i_lenAlloc , 0x00 ,
PAGE_CACHE_SIZE - iinfo - > i_lenAlloc ) ;
memcpy ( kaddr , iinfo - > i_ext . i_data + iinfo - > i_lenEAttr ,
iinfo - > i_lenAlloc ) ;
2005-04-17 02:20:36 +04:00
flush_dcache_page ( page ) ;
SetPageUptodate ( page ) ;
kunmap ( page ) ;
}
2008-02-08 15:20:44 +03:00
memset ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr , 0x00 ,
iinfo - > i_lenAlloc ) ;
iinfo - > i_lenAlloc = 0 ;
2005-04-17 02:20:36 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_USE_SHORT_AD ) )
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_SHORT ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_LONG ;
2005-04-17 02:20:36 +04:00
inode - > i_data . a_ops - > writepage ( page , & udf_wbc ) ;
page_cache_release ( page ) ;
mark_inode_dirty ( inode ) ;
}
2007-07-19 12:47:43 +04:00
struct buffer_head * udf_expand_dir_adinicb ( struct inode * inode , int * block ,
int * err )
2005-04-17 02:20:36 +04:00
{
int newblock ;
2007-05-08 11:35:14 +04:00
struct buffer_head * dbh = NULL ;
kernel_lb_addr eloc ;
uint32_t elen ;
2005-04-17 02:20:36 +04:00
uint8_t alloctype ;
2007-05-08 11:35:14 +04:00
struct extent_position epos ;
2005-04-17 02:20:36 +04:00
struct udf_fileident_bh sfibh , dfibh ;
loff_t f_pos = udf_ext0_offset ( inode ) > > 2 ;
int size = ( udf_ext0_offset ( inode ) + inode - > i_size ) > > 2 ;
struct fileIdentDesc cfi , * sfi , * dfi ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_USE_SHORT_AD ) )
alloctype = ICBTAG_FLAG_AD_SHORT ;
else
alloctype = ICBTAG_FLAG_AD_LONG ;
2007-07-19 12:47:43 +04:00
if ( ! inode - > i_size ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = alloctype ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
return NULL ;
}
/* alloc block, and copy data to it */
* block = udf_new_block ( inode - > i_sb , inode ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
iinfo - > i_location . logicalBlockNum , err ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( * block ) )
return NULL ;
newblock = udf_get_pblock ( inode - > i_sb , * block ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
2008-02-08 15:20:42 +03:00
0 ) ;
2005-04-17 02:20:36 +04:00
if ( ! newblock )
return NULL ;
dbh = udf_tgetblk ( inode - > i_sb , newblock ) ;
if ( ! dbh )
return NULL ;
lock_buffer ( dbh ) ;
memset ( dbh - > b_data , 0x00 , inode - > i_sb - > s_blocksize ) ;
set_buffer_uptodate ( dbh ) ;
unlock_buffer ( dbh ) ;
mark_buffer_dirty_inode ( dbh , inode ) ;
2008-02-08 15:20:36 +03:00
sfibh . soffset = sfibh . eoffset =
( f_pos & ( ( inode - > i_sb - > s_blocksize - 1 ) > > 2 ) ) < < 2 ;
2007-05-08 11:35:14 +04:00
sfibh . sbh = sfibh . ebh = NULL ;
2005-04-17 02:20:36 +04:00
dfibh . soffset = dfibh . eoffset = 0 ;
dfibh . sbh = dfibh . ebh = dbh ;
2007-07-19 12:47:43 +04:00
while ( ( f_pos < size ) ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_IN_ICB ;
2008-02-08 15:20:36 +03:00
sfi = udf_fileident_read ( inode , & f_pos , & sfibh , & cfi , NULL ,
NULL , NULL , NULL ) ;
2007-07-19 12:47:43 +04:00
if ( ! sfi ) {
2007-05-08 11:35:16 +04:00
brelse ( dbh ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = alloctype ;
2005-04-17 02:20:36 +04:00
sfi - > descTag . tagLocation = cpu_to_le32 ( * block ) ;
dfibh . soffset = dfibh . eoffset ;
dfibh . eoffset + = ( sfibh . eoffset - sfibh . soffset ) ;
dfi = ( struct fileIdentDesc * ) ( dbh - > b_data + dfibh . soffset ) ;
if ( udf_write_fi ( inode , sfi , dfi , & dfibh , sfi - > impUse ,
2008-02-08 15:20:36 +03:00
sfi - > fileIdent +
le16_to_cpu ( sfi - > lengthOfImpUse ) ) ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_IN_ICB ;
2007-05-08 11:35:16 +04:00
brelse ( dbh ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
}
mark_buffer_dirty_inode ( dbh , inode ) ;
2008-02-08 15:20:44 +03:00
memset ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr , 0 ,
iinfo - > i_lenAlloc ) ;
iinfo - > i_lenAlloc = 0 ;
2005-04-17 02:20:36 +04:00
eloc . logicalBlockNum = * block ;
2008-02-08 15:20:36 +03:00
eloc . partitionReferenceNum =
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ;
2005-04-17 02:20:36 +04:00
elen = inode - > i_size ;
2008-02-08 15:20:44 +03:00
iinfo - > i_lenExtents = elen ;
2007-05-08 11:35:14 +04:00
epos . bh = NULL ;
2008-02-08 15:20:44 +03:00
epos . block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
epos . offset = udf_file_entry_alloc_offset ( inode ) ;
udf_add_aext ( inode , & epos , eloc , elen , 0 ) ;
2005-04-17 02:20:36 +04:00
/* UniqueID stuff */
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
return dbh ;
}
2007-07-19 12:47:43 +04:00
static int udf_get_block ( struct inode * inode , sector_t block ,
struct buffer_head * bh_result , int create )
2005-04-17 02:20:36 +04:00
{
int err , new ;
struct buffer_head * bh ;
2008-02-08 15:20:48 +03:00
sector_t phys = 0 ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ! create ) {
2005-04-17 02:20:36 +04:00
phys = udf_block_map ( inode , block ) ;
if ( phys )
map_bh ( bh_result , inode - > i_sb , phys ) ;
return 0 ;
}
err = - EIO ;
new = 0 ;
bh = NULL ;
lock_kernel ( ) ;
if ( block < 0 )
goto abort_negative ;
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
if ( block = = iinfo - > i_next_alloc_block + 1 ) {
iinfo - > i_next_alloc_block + + ;
iinfo - > i_next_alloc_goal + + ;
2005-04-17 02:20:36 +04:00
}
err = 0 ;
bh = inode_getblk ( inode , block , & err , & phys , & new ) ;
2006-04-02 15:40:13 +04:00
BUG_ON ( bh ) ;
2005-04-17 02:20:36 +04:00
if ( err )
goto abort ;
2006-04-02 15:40:13 +04:00
BUG_ON ( ! phys ) ;
2005-04-17 02:20:36 +04:00
if ( new )
set_buffer_new ( bh_result ) ;
map_bh ( bh_result , inode - > i_sb , phys ) ;
2007-07-21 15:37:18 +04:00
abort :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return err ;
2007-07-21 15:37:18 +04:00
abort_negative :
2005-04-17 02:20:36 +04:00
udf_warning ( inode - > i_sb , " udf_get_block " , " block < 0 " ) ;
goto abort ;
}
2007-07-19 12:47:43 +04:00
static struct buffer_head * udf_getblk ( struct inode * inode , long block ,
int create , int * err )
2005-04-17 02:20:36 +04:00
{
2007-07-21 15:37:18 +04:00
struct buffer_head * bh ;
2005-04-17 02:20:36 +04:00
struct buffer_head dummy ;
dummy . b_state = 0 ;
dummy . b_blocknr = - 1000 ;
* err = udf_get_block ( inode , block , & dummy , create ) ;
2007-07-19 12:47:43 +04:00
if ( ! * err & & buffer_mapped ( & dummy ) ) {
2005-04-17 02:20:36 +04:00
bh = sb_getblk ( inode - > i_sb , dummy . b_blocknr ) ;
2007-07-19 12:47:43 +04:00
if ( buffer_new ( & dummy ) ) {
2005-04-17 02:20:36 +04:00
lock_buffer ( bh ) ;
memset ( bh - > b_data , 0x00 , inode - > i_sb - > s_blocksize ) ;
set_buffer_uptodate ( bh ) ;
unlock_buffer ( bh ) ;
mark_buffer_dirty_inode ( bh , inode ) ;
}
return bh ;
}
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return NULL ;
}
2007-05-08 11:35:21 +04:00
/* Extend the file by 'blocks' blocks, return the number of extents added */
int udf_extend_file ( struct inode * inode , struct extent_position * last_pos ,
2008-02-08 15:20:36 +03:00
kernel_long_ad * last_ext , sector_t blocks )
2007-05-08 11:35:21 +04:00
{
sector_t add ;
int count = 0 , fake = ! ( last_ext - > extLength & UDF_EXTENT_LENGTH_MASK ) ;
struct super_block * sb = inode - > i_sb ;
2007-07-21 15:37:18 +04:00
kernel_lb_addr prealloc_loc = { } ;
2007-05-08 11:35:21 +04:00
int prealloc_len = 0 ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2007-05-08 11:35:21 +04:00
/* The previous extent is fake and we should not extend by anything
* - there ' s nothing to do . . . */
if ( ! blocks & & fake )
return 0 ;
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2007-05-08 11:35:21 +04:00
/* Round the last extent up to a multiple of block size */
if ( last_ext - > extLength & ( sb - > s_blocksize - 1 ) ) {
last_ext - > extLength =
2007-07-21 15:37:18 +04:00
( last_ext - > extLength & UDF_EXTENT_FLAG_MASK ) |
( ( ( last_ext - > extLength & UDF_EXTENT_LENGTH_MASK ) +
sb - > s_blocksize - 1 ) & ~ ( sb - > s_blocksize - 1 ) ) ;
2008-02-08 15:20:44 +03:00
iinfo - > i_lenExtents =
( iinfo - > i_lenExtents + sb - > s_blocksize - 1 ) &
2007-07-21 15:37:18 +04:00
~ ( sb - > s_blocksize - 1 ) ;
2007-05-08 11:35:21 +04:00
}
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
/* Last extent are just preallocated blocks? */
2008-02-08 15:20:36 +03:00
if ( ( last_ext - > extLength & UDF_EXTENT_FLAG_MASK ) = =
EXT_NOT_RECORDED_ALLOCATED ) {
2007-05-08 11:35:21 +04:00
/* Save the extent so that we can reattach it to the end */
prealloc_loc = last_ext - > extLocation ;
prealloc_len = last_ext - > extLength ;
/* Mark the extent as a hole */
last_ext - > extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
2007-07-21 15:37:18 +04:00
( last_ext - > extLength & UDF_EXTENT_LENGTH_MASK ) ;
2007-05-08 11:35:21 +04:00
last_ext - > extLocation . logicalBlockNum = 0 ;
2008-02-08 15:20:36 +03:00
last_ext - > extLocation . partitionReferenceNum = 0 ;
2007-05-08 11:35:21 +04:00
}
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
/* Can we merge with the previous extent? */
2008-02-08 15:20:36 +03:00
if ( ( last_ext - > extLength & UDF_EXTENT_FLAG_MASK ) = =
EXT_NOT_RECORDED_NOT_ALLOCATED ) {
add = ( ( 1 < < 30 ) - sb - > s_blocksize -
( last_ext - > extLength & UDF_EXTENT_LENGTH_MASK ) ) > >
sb - > s_blocksize_bits ;
2007-05-08 11:35:21 +04:00
if ( add > blocks )
add = blocks ;
blocks - = add ;
last_ext - > extLength + = add < < sb - > s_blocksize_bits ;
}
if ( fake ) {
udf_add_aext ( inode , last_pos , last_ext - > extLocation ,
2007-07-19 12:47:43 +04:00
last_ext - > extLength , 1 ) ;
2007-05-08 11:35:21 +04:00
count + + ;
2008-02-08 15:20:36 +03:00
} else
udf_write_aext ( inode , last_pos , last_ext - > extLocation ,
last_ext - > extLength , 1 ) ;
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
/* Managed to do everything necessary? */
if ( ! blocks )
goto out ;
/* All further extents will be NOT_RECORDED_NOT_ALLOCATED */
last_ext - > extLocation . logicalBlockNum = 0 ;
2008-02-08 15:20:36 +03:00
last_ext - > extLocation . partitionReferenceNum = 0 ;
2007-07-21 15:37:18 +04:00
add = ( 1 < < ( 30 - sb - > s_blocksize_bits ) ) - 1 ;
2008-02-08 15:20:36 +03:00
last_ext - > extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
( add < < sb - > s_blocksize_bits ) ;
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
/* Create enough extents to cover the whole hole */
while ( blocks > add ) {
blocks - = add ;
if ( udf_add_aext ( inode , last_pos , last_ext - > extLocation ,
2007-07-19 12:47:43 +04:00
last_ext - > extLength , 1 ) = = - 1 )
2007-05-08 11:35:21 +04:00
return - 1 ;
count + + ;
}
if ( blocks ) {
last_ext - > extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
2007-07-21 15:37:18 +04:00
( blocks < < sb - > s_blocksize_bits ) ;
2007-05-08 11:35:21 +04:00
if ( udf_add_aext ( inode , last_pos , last_ext - > extLocation ,
2007-07-19 12:47:43 +04:00
last_ext - > extLength , 1 ) = = - 1 )
2007-05-08 11:35:21 +04:00
return - 1 ;
count + + ;
}
2007-07-21 15:37:18 +04:00
out :
2007-05-08 11:35:21 +04:00
/* Do we have some preallocated blocks saved? */
if ( prealloc_len ) {
2008-02-08 15:20:36 +03:00
if ( udf_add_aext ( inode , last_pos , prealloc_loc ,
prealloc_len , 1 ) = = - 1 )
2007-05-08 11:35:21 +04:00
return - 1 ;
last_ext - > extLocation = prealloc_loc ;
last_ext - > extLength = prealloc_len ;
count + + ;
}
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
/* last_pos should point to the last written extent... */
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2007-05-08 11:35:21 +04:00
last_pos - > offset - = sizeof ( short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2007-05-08 11:35:21 +04:00
last_pos - > offset - = sizeof ( long_ad ) ;
else
return - 1 ;
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
return count ;
}
2007-07-19 12:47:43 +04:00
static struct buffer_head * inode_getblk ( struct inode * inode , sector_t block ,
2008-02-08 15:20:48 +03:00
int * err , sector_t * phys , int * new )
2005-04-17 02:20:36 +04:00
{
2007-05-08 11:35:21 +04:00
static sector_t last_block ;
2007-05-08 11:35:14 +04:00
struct buffer_head * result = NULL ;
2005-04-17 02:20:36 +04:00
kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ;
2007-05-08 11:35:14 +04:00
struct extent_position prev_epos , cur_epos , next_epos ;
2005-04-17 02:20:36 +04:00
int count = 0 , startnum = 0 , endnum = 0 ;
2007-06-01 11:46:29 +04:00
uint32_t elen = 0 , tmpelen ;
kernel_lb_addr eloc , tmpeloc ;
2005-04-17 02:20:36 +04:00
int c = 1 ;
2007-05-08 11:35:13 +04:00
loff_t lbcount = 0 , b_off = 0 ;
uint32_t newblocknum , newblock ;
sector_t offset = 0 ;
2005-04-17 02:20:36 +04:00
int8_t etype ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
int goal = 0 , pgoal = iinfo - > i_location . logicalBlockNum ;
2007-05-08 11:35:21 +04:00
int lastblock = 0 ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
prev_epos . offset = udf_file_entry_alloc_offset ( inode ) ;
2008-02-08 15:20:44 +03:00
prev_epos . block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
prev_epos . bh = NULL ;
cur_epos = next_epos = prev_epos ;
2007-07-21 15:37:18 +04:00
b_off = ( loff_t ) block < < inode - > i_sb - > s_blocksize_bits ;
2005-04-17 02:20:36 +04:00
/* find the extent which contains the block we are looking for.
2007-07-19 12:47:43 +04:00
alternate between laarr [ 0 ] and laarr [ 1 ] for locations of the
current extent , and the previous extent */
do {
if ( prev_epos . bh ! = cur_epos . bh ) {
2007-05-08 11:35:16 +04:00
brelse ( prev_epos . bh ) ;
get_bh ( cur_epos . bh ) ;
2007-05-08 11:35:14 +04:00
prev_epos . bh = cur_epos . bh ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( cur_epos . bh ! = next_epos . bh ) {
2007-05-08 11:35:16 +04:00
brelse ( cur_epos . bh ) ;
get_bh ( next_epos . bh ) ;
2007-05-08 11:35:14 +04:00
cur_epos . bh = next_epos . bh ;
2005-04-17 02:20:36 +04:00
}
lbcount + = elen ;
2007-05-08 11:35:14 +04:00
prev_epos . block = cur_epos . block ;
cur_epos . block = next_epos . block ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
prev_epos . offset = cur_epos . offset ;
cur_epos . offset = next_epos . offset ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
etype = udf_next_aext ( inode , & next_epos , & eloc , & elen , 1 ) ;
if ( etype = = - 1 )
2005-04-17 02:20:36 +04:00
break ;
c = ! c ;
laarr [ c ] . extLength = ( etype < < 30 ) | elen ;
laarr [ c ] . extLocation = eloc ;
if ( etype ! = ( EXT_NOT_RECORDED_NOT_ALLOCATED > > 30 ) )
pgoal = eloc . logicalBlockNum +
2007-07-21 15:37:18 +04:00
( ( elen + inode - > i_sb - > s_blocksize - 1 ) > >
inode - > i_sb - > s_blocksize_bits ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
count + + ;
2005-04-17 02:20:36 +04:00
} while ( lbcount + elen < = b_off ) ;
b_off - = lbcount ;
offset = b_off > > inode - > i_sb - > s_blocksize_bits ;
2007-06-01 11:46:29 +04:00
/*
* Move prev_epos and cur_epos into indirect extent if we are at
* the pointer to it
*/
udf_next_aext ( inode , & prev_epos , & tmpeloc , & tmpelen , 0 ) ;
udf_next_aext ( inode , & cur_epos , & tmpeloc , & tmpelen , 0 ) ;
2005-04-17 02:20:36 +04:00
/* if the extent is allocated and recorded, return the block
2007-07-19 12:47:43 +04:00
if the extent is not a multiple of the blocksize , round up */
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( etype = = ( EXT_RECORDED_ALLOCATED > > 30 ) ) {
if ( elen & ( inode - > i_sb - > s_blocksize - 1 ) ) {
2005-04-17 02:20:36 +04:00
elen = EXT_RECORDED_ALLOCATED |
2007-07-21 15:37:18 +04:00
( ( elen + inode - > i_sb - > s_blocksize - 1 ) &
~ ( inode - > i_sb - > s_blocksize - 1 ) ) ;
2007-05-08 11:35:14 +04:00
etype = udf_write_aext ( inode , & cur_epos , eloc , elen , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:35:16 +04:00
brelse ( prev_epos . bh ) ;
brelse ( cur_epos . bh ) ;
brelse ( next_epos . bh ) ;
2005-04-17 02:20:36 +04:00
newblock = udf_get_lb_pblock ( inode - > i_sb , eloc , offset ) ;
* phys = newblock ;
return NULL ;
}
2007-05-08 11:35:21 +04:00
last_block = block ;
/* Are we beyond EOF? */
2007-07-19 12:47:43 +04:00
if ( etype = = - 1 ) {
2007-05-08 11:35:21 +04:00
int ret ;
if ( count ) {
if ( c )
laarr [ 0 ] = laarr [ 1 ] ;
startnum = 1 ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:21 +04:00
/* Create a fake extent when there's not one */
2008-02-08 15:20:36 +03:00
memset ( & laarr [ 0 ] . extLocation , 0x00 ,
sizeof ( kernel_lb_addr ) ) ;
2007-05-08 11:35:21 +04:00
laarr [ 0 ] . extLength = EXT_NOT_RECORDED_NOT_ALLOCATED ;
2008-02-08 15:20:36 +03:00
/* Will udf_extend_file() create real extent from
a fake one ? */
2007-05-08 11:35:21 +04:00
startnum = ( offset > 0 ) ;
}
/* Create extents for the hole between EOF and offset */
ret = udf_extend_file ( inode , & prev_epos , laarr , offset ) ;
if ( ret = = - 1 ) {
brelse ( prev_epos . bh ) ;
brelse ( cur_epos . bh ) ;
brelse ( next_epos . bh ) ;
/* We don't really know the error here so we just make
* something up */
* err = - ENOSPC ;
return NULL ;
}
c = 0 ;
offset = 0 ;
count + = ret ;
/* We are not covered by a preallocated extent? */
2008-02-08 15:20:36 +03:00
if ( ( laarr [ 0 ] . extLength & UDF_EXTENT_FLAG_MASK ) ! =
EXT_NOT_RECORDED_ALLOCATED ) {
2007-05-08 11:35:21 +04:00
/* Is there any real extent? - otherwise we overwrite
* the fake one . . . */
if ( count )
c = ! c ;
laarr [ c ] . extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
2007-07-21 15:37:18 +04:00
inode - > i_sb - > s_blocksize ;
2008-02-08 15:20:36 +03:00
memset ( & laarr [ c ] . extLocation , 0x00 ,
sizeof ( kernel_lb_addr ) ) ;
2007-07-19 12:47:43 +04:00
count + + ;
endnum + + ;
2007-05-08 11:35:21 +04:00
}
2007-07-19 12:47:43 +04:00
endnum = c + 1 ;
2005-04-17 02:20:36 +04:00
lastblock = 1 ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
endnum = startnum = ( ( count > 2 ) ? 2 : count ) ;
2008-02-08 15:20:36 +03:00
/* if the current extent is in position 0,
swap it with the previous */
2007-07-19 12:47:43 +04:00
if ( ! c & & count ! = 1 ) {
2007-05-08 11:35:21 +04:00
laarr [ 2 ] = laarr [ 0 ] ;
laarr [ 0 ] = laarr [ 1 ] ;
laarr [ 1 ] = laarr [ 2 ] ;
c = 1 ;
}
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
/* if the current block is located in an extent,
read the next extent */
etype = udf_next_aext ( inode , & next_epos , & eloc , & elen , 0 ) ;
if ( etype ! = - 1 ) {
2007-07-19 12:47:43 +04:00
laarr [ c + 1 ] . extLength = ( etype < < 30 ) | elen ;
laarr [ c + 1 ] . extLocation = eloc ;
count + + ;
startnum + + ;
endnum + + ;
2008-02-08 15:20:36 +03:00
} else
2005-04-17 02:20:36 +04:00
lastblock = 1 ;
}
/* if the current extent is not recorded but allocated, get the
2007-07-21 15:37:18 +04:00
* block in the extent corresponding to the requested block */
2008-02-08 15:20:36 +03:00
if ( ( laarr [ c ] . extLength > > 30 ) = = ( EXT_NOT_RECORDED_ALLOCATED > > 30 ) )
2005-04-17 02:20:36 +04:00
newblocknum = laarr [ c ] . extLocation . logicalBlockNum + offset ;
2008-02-08 15:20:36 +03:00
else { /* otherwise, allocate a new block */
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_next_alloc_block = = block )
goal = iinfo - > i_next_alloc_goal ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ! goal ) {
2008-02-08 15:20:36 +03:00
if ( ! ( goal = pgoal ) ) /* XXX: what was intended here? */
2008-02-08 15:20:44 +03:00
goal = iinfo - > i_location . logicalBlockNum + 1 ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
newblocknum = udf_new_block ( inode - > i_sb , inode ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
2008-02-08 15:20:36 +03:00
goal , err ) ;
if ( ! newblocknum ) {
2007-05-08 11:35:16 +04:00
brelse ( prev_epos . bh ) ;
2005-04-17 02:20:36 +04:00
* err = - ENOSPC ;
return NULL ;
}
2008-02-08 15:20:44 +03:00
iinfo - > i_lenExtents + = inode - > i_sb - > s_blocksize ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
/* if the extent the requsted block is located in contains multiple
* blocks , split the extent into at most three extents . blocks prior
* to requested block , requested block , and blocks after requested
* block */
2005-04-17 02:20:36 +04:00
udf_split_extents ( inode , & c , offset , newblocknum , laarr , & endnum ) ;
# ifdef UDF_PREALLOCATE
/* preallocate blocks */
udf_prealloc_extents ( inode , c , lastblock , laarr , & endnum ) ;
# endif
/* merge any continuous blocks in laarr */
udf_merge_extents ( inode , laarr , & endnum ) ;
/* write back the new extents, inserting new extents if the new number
2007-07-21 15:37:18 +04:00
* of extents is greater than the old number , and deleting extents if
* the new number of extents is less than the old number */
2007-05-08 11:35:14 +04:00
udf_update_extents ( inode , laarr , startnum , endnum , & prev_epos ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:16 +04:00
brelse ( prev_epos . bh ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
newblock = udf_get_pblock ( inode - > i_sb , newblocknum ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum , 0 ) ;
2008-02-08 15:20:36 +03:00
if ( ! newblock )
2005-04-17 02:20:36 +04:00
return NULL ;
* phys = newblock ;
* err = 0 ;
* new = 1 ;
2008-02-08 15:20:44 +03:00
iinfo - > i_next_alloc_block = block ;
iinfo - > i_next_alloc_goal = newblocknum ;
2005-04-17 02:20:36 +04:00
inode - > i_ctime = current_fs_time ( inode - > i_sb ) ;
if ( IS_SYNC ( inode ) )
udf_sync_inode ( inode ) ;
else
mark_inode_dirty ( inode ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return result ;
}
2007-07-19 12:47:43 +04:00
static void udf_split_extents ( struct inode * inode , int * c , int offset ,
int newblocknum ,
kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
int * endnum )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:36 +03:00
unsigned long blocksize = inode - > i_sb - > s_blocksize ;
unsigned char blocksize_bits = inode - > i_sb - > s_blocksize_bits ;
2005-04-17 02:20:36 +04:00
if ( ( laarr [ * c ] . extLength > > 30 ) = = ( EXT_NOT_RECORDED_ALLOCATED > > 30 ) | |
2008-02-08 15:20:36 +03:00
( laarr [ * c ] . extLength > > 30 ) = =
( EXT_NOT_RECORDED_NOT_ALLOCATED > > 30 ) ) {
2005-04-17 02:20:36 +04:00
int curr = * c ;
int blen = ( ( laarr [ curr ] . extLength & UDF_EXTENT_LENGTH_MASK ) +
2008-02-08 15:20:36 +03:00
blocksize - 1 ) > > blocksize_bits ;
2005-04-17 02:20:36 +04:00
int8_t etype = ( laarr [ curr ] . extLength > > 30 ) ;
2008-02-08 15:20:36 +03:00
if ( blen = = 1 )
2007-07-21 15:37:18 +04:00
;
2008-02-08 15:20:36 +03:00
else if ( ! offset | | blen = = offset + 1 ) {
2007-07-19 12:47:43 +04:00
laarr [ curr + 2 ] = laarr [ curr + 1 ] ;
laarr [ curr + 1 ] = laarr [ curr ] ;
} else {
laarr [ curr + 3 ] = laarr [ curr + 1 ] ;
laarr [ curr + 2 ] = laarr [ curr + 1 ] = laarr [ curr ] ;
}
if ( offset ) {
if ( etype = = ( EXT_NOT_RECORDED_ALLOCATED > > 30 ) ) {
2008-02-08 15:20:36 +03:00
udf_free_blocks ( inode - > i_sb , inode ,
laarr [ curr ] . extLocation ,
0 , offset ) ;
laarr [ curr ] . extLength =
EXT_NOT_RECORDED_NOT_ALLOCATED |
( offset < < blocksize_bits ) ;
2005-04-17 02:20:36 +04:00
laarr [ curr ] . extLocation . logicalBlockNum = 0 ;
2008-02-08 15:20:36 +03:00
laarr [ curr ] . extLocation .
partitionReferenceNum = 0 ;
} else
2005-04-17 02:20:36 +04:00
laarr [ curr ] . extLength = ( etype < < 30 ) |
2008-02-08 15:20:36 +03:00
( offset < < blocksize_bits ) ;
2007-07-19 12:47:43 +04:00
curr + + ;
( * c ) + + ;
( * endnum ) + + ;
2005-04-17 02:20:36 +04:00
}
2007-07-16 10:39:47 +04:00
2005-04-17 02:20:36 +04:00
laarr [ curr ] . extLocation . logicalBlockNum = newblocknum ;
if ( etype = = ( EXT_NOT_RECORDED_NOT_ALLOCATED > > 30 ) )
laarr [ curr ] . extLocation . partitionReferenceNum =
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_location . partitionReferenceNum ;
2005-04-17 02:20:36 +04:00
laarr [ curr ] . extLength = EXT_RECORDED_ALLOCATED |
2008-02-08 15:20:36 +03:00
blocksize ;
2007-07-19 12:47:43 +04:00
curr + + ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( blen ! = offset + 1 ) {
2005-04-17 02:20:36 +04:00
if ( etype = = ( EXT_NOT_RECORDED_ALLOCATED > > 30 ) )
2008-02-08 15:20:36 +03:00
laarr [ curr ] . extLocation . logicalBlockNum + =
offset + 1 ;
2007-07-21 15:37:18 +04:00
laarr [ curr ] . extLength = ( etype < < 30 ) |
2008-02-08 15:20:36 +03:00
( ( blen - ( offset + 1 ) ) < < blocksize_bits ) ;
2007-07-19 12:47:43 +04:00
curr + + ;
( * endnum ) + + ;
2005-04-17 02:20:36 +04:00
}
}
}
static void udf_prealloc_extents ( struct inode * inode , int c , int lastblock ,
2007-07-19 12:47:43 +04:00
kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
int * endnum )
2005-04-17 02:20:36 +04:00
{
int start , length = 0 , currlength = 0 , i ;
2007-07-19 12:47:43 +04:00
if ( * endnum > = ( c + 1 ) ) {
2005-04-17 02:20:36 +04:00
if ( ! lastblock )
return ;
else
start = c ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:36 +03:00
if ( ( laarr [ c + 1 ] . extLength > > 30 ) = =
( EXT_NOT_RECORDED_ALLOCATED > > 30 ) ) {
2007-07-19 12:47:43 +04:00
start = c + 1 ;
2008-02-08 15:20:36 +03:00
length = currlength =
( ( ( laarr [ c + 1 ] . extLength &
UDF_EXTENT_LENGTH_MASK ) +
inode - > i_sb - > s_blocksize - 1 ) > >
inode - > i_sb - > s_blocksize_bits ) ;
} else
2005-04-17 02:20:36 +04:00
start = c ;
}
2007-07-19 12:47:43 +04:00
for ( i = start + 1 ; i < = * endnum ; i + + ) {
if ( i = = * endnum ) {
2005-04-17 02:20:36 +04:00
if ( lastblock )
length + = UDF_DEFAULT_PREALLOC_BLOCKS ;
2008-02-08 15:20:36 +03:00
} else if ( ( laarr [ i ] . extLength > > 30 ) = =
( EXT_NOT_RECORDED_NOT_ALLOCATED > > 30 ) ) {
length + = ( ( ( laarr [ i ] . extLength &
UDF_EXTENT_LENGTH_MASK ) +
inode - > i_sb - > s_blocksize - 1 ) > >
inode - > i_sb - > s_blocksize_bits ) ;
} else
2005-04-17 02:20:36 +04:00
break ;
}
2007-07-19 12:47:43 +04:00
if ( length ) {
2005-04-17 02:20:36 +04:00
int next = laarr [ start ] . extLocation . logicalBlockNum +
2007-07-21 15:37:18 +04:00
( ( ( laarr [ start ] . extLength & UDF_EXTENT_LENGTH_MASK ) +
2008-02-08 15:20:36 +03:00
inode - > i_sb - > s_blocksize - 1 ) > >
inode - > i_sb - > s_blocksize_bits ) ;
2005-04-17 02:20:36 +04:00
int numalloc = udf_prealloc_blocks ( inode - > i_sb , inode ,
2008-02-08 15:20:36 +03:00
laarr [ start ] . extLocation . partitionReferenceNum ,
next , ( UDF_DEFAULT_PREALLOC_BLOCKS > length ?
length : UDF_DEFAULT_PREALLOC_BLOCKS ) -
currlength ) ;
2007-07-21 15:37:18 +04:00
if ( numalloc ) {
2008-02-08 15:20:36 +03:00
if ( start = = ( c + 1 ) )
2005-04-17 02:20:36 +04:00
laarr [ start ] . extLength + =
2008-02-08 15:20:36 +03:00
( numalloc < <
inode - > i_sb - > s_blocksize_bits ) ;
else {
2007-07-19 12:47:43 +04:00
memmove ( & laarr [ c + 2 ] , & laarr [ c + 1 ] ,
sizeof ( long_ad ) * ( * endnum - ( c + 1 ) ) ) ;
( * endnum ) + + ;
laarr [ c + 1 ] . extLocation . logicalBlockNum = next ;
laarr [ c + 1 ] . extLocation . partitionReferenceNum =
2008-02-08 15:20:36 +03:00
laarr [ c ] . extLocation .
partitionReferenceNum ;
laarr [ c + 1 ] . extLength =
EXT_NOT_RECORDED_ALLOCATED |
( numalloc < <
inode - > i_sb - > s_blocksize_bits ) ;
2007-07-19 12:47:43 +04:00
start = c + 1 ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
for ( i = start + 1 ; numalloc & & i < * endnum ; i + + ) {
2008-02-08 15:20:36 +03:00
int elen = ( ( laarr [ i ] . extLength &
UDF_EXTENT_LENGTH_MASK ) +
inode - > i_sb - > s_blocksize - 1 ) > >
inode - > i_sb - > s_blocksize_bits ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( elen > numalloc ) {
2005-04-17 02:20:36 +04:00
laarr [ i ] . extLength - =
2008-02-08 15:20:36 +03:00
( numalloc < <
inode - > i_sb - > s_blocksize_bits ) ;
2005-04-17 02:20:36 +04:00
numalloc = 0 ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
numalloc - = elen ;
2007-07-19 12:47:43 +04:00
if ( * endnum > ( i + 1 ) )
2008-02-08 15:20:36 +03:00
memmove ( & laarr [ i ] ,
& laarr [ i + 1 ] ,
sizeof ( long_ad ) *
( * endnum - ( i + 1 ) ) ) ;
2007-07-19 12:47:43 +04:00
i - - ;
( * endnum ) - - ;
2005-04-17 02:20:36 +04:00
}
}
2008-02-08 15:20:42 +03:00
UDF_I ( inode ) - > i_lenExtents + =
2008-02-08 15:20:36 +03:00
numalloc < < inode - > i_sb - > s_blocksize_bits ;
2005-04-17 02:20:36 +04:00
}
}
}
static void udf_merge_extents ( struct inode * inode ,
2007-07-19 12:47:43 +04:00
kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
int * endnum )
2005-04-17 02:20:36 +04:00
{
int i ;
2008-02-08 15:20:36 +03:00
unsigned long blocksize = inode - > i_sb - > s_blocksize ;
unsigned char blocksize_bits = inode - > i_sb - > s_blocksize_bits ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
for ( i = 0 ; i < ( * endnum - 1 ) ; i + + ) {
2008-02-08 15:20:36 +03:00
kernel_long_ad * li /*l[i]*/ = & laarr [ i ] ;
kernel_long_ad * lip1 /*l[i plus 1]*/ = & laarr [ i + 1 ] ;
if ( ( ( li - > extLength > > 30 ) = = ( lip1 - > extLength > > 30 ) ) & &
( ( ( li - > extLength > > 30 ) = =
( EXT_NOT_RECORDED_NOT_ALLOCATED > > 30 ) ) | |
( ( lip1 - > extLocation . logicalBlockNum -
li - > extLocation . logicalBlockNum ) = =
( ( ( li - > extLength & UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) > > blocksize_bits ) ) ) ) {
if ( ( ( li - > extLength & UDF_EXTENT_LENGTH_MASK ) +
( lip1 - > extLength & UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) & ~ UDF_EXTENT_LENGTH_MASK ) {
lip1 - > extLength = ( lip1 - > extLength -
( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) +
UDF_EXTENT_LENGTH_MASK ) &
~ ( blocksize - 1 ) ;
li - > extLength = ( li - > extLength &
UDF_EXTENT_FLAG_MASK ) +
( UDF_EXTENT_LENGTH_MASK + 1 ) -
blocksize ;
lip1 - > extLocation . logicalBlockNum =
li - > extLocation . logicalBlockNum +
( ( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) > >
blocksize_bits ) ;
} else {
li - > extLength = lip1 - > extLength +
( ( ( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) & ~ ( blocksize - 1 ) ) ;
if ( * endnum > ( i + 2 ) )
memmove ( & laarr [ i + 1 ] , & laarr [ i + 2 ] ,
sizeof ( long_ad ) *
( * endnum - ( i + 2 ) ) ) ;
i - - ;
( * endnum ) - - ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
} else if ( ( ( li - > extLength > > 30 ) = =
( EXT_NOT_RECORDED_ALLOCATED > > 30 ) ) & &
( ( lip1 - > extLength > > 30 ) = =
( EXT_NOT_RECORDED_NOT_ALLOCATED > > 30 ) ) ) {
udf_free_blocks ( inode - > i_sb , inode , li - > extLocation , 0 ,
( ( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) > > blocksize_bits ) ;
li - > extLocation . logicalBlockNum = 0 ;
li - > extLocation . partitionReferenceNum = 0 ;
if ( ( ( li - > extLength & UDF_EXTENT_LENGTH_MASK ) +
( lip1 - > extLength & UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) & ~ UDF_EXTENT_LENGTH_MASK ) {
lip1 - > extLength = ( lip1 - > extLength -
( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) +
UDF_EXTENT_LENGTH_MASK ) &
~ ( blocksize - 1 ) ;
li - > extLength = ( li - > extLength &
UDF_EXTENT_FLAG_MASK ) +
( UDF_EXTENT_LENGTH_MASK + 1 ) -
blocksize ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:36 +03:00
li - > extLength = lip1 - > extLength +
( ( ( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) & ~ ( blocksize - 1 ) ) ;
2007-07-19 12:47:43 +04:00
if ( * endnum > ( i + 2 ) )
memmove ( & laarr [ i + 1 ] , & laarr [ i + 2 ] ,
2008-02-08 15:20:36 +03:00
sizeof ( long_ad ) *
( * endnum - ( i + 2 ) ) ) ;
2007-07-19 12:47:43 +04:00
i - - ;
( * endnum ) - - ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
} else if ( ( li - > extLength > > 30 ) = =
( EXT_NOT_RECORDED_ALLOCATED > > 30 ) ) {
udf_free_blocks ( inode - > i_sb , inode ,
li - > extLocation , 0 ,
( ( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) +
blocksize - 1 ) > > blocksize_bits ) ;
li - > extLocation . logicalBlockNum = 0 ;
li - > extLocation . partitionReferenceNum = 0 ;
li - > extLength = ( li - > extLength &
UDF_EXTENT_LENGTH_MASK ) |
EXT_NOT_RECORDED_NOT_ALLOCATED ;
2005-04-17 02:20:36 +04:00
}
}
}
static void udf_update_extents ( struct inode * inode ,
2007-07-19 12:47:43 +04:00
kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
int startnum , int endnum ,
struct extent_position * epos )
2005-04-17 02:20:36 +04:00
{
int start = 0 , i ;
kernel_lb_addr tmploc ;
uint32_t tmplen ;
2007-07-19 12:47:43 +04:00
if ( startnum > endnum ) {
for ( i = 0 ; i < ( startnum - endnum ) ; i + + )
2007-05-08 11:35:14 +04:00
udf_delete_aext ( inode , * epos , laarr [ i ] . extLocation ,
2007-07-19 12:47:43 +04:00
laarr [ i ] . extLength ) ;
} else if ( startnum < endnum ) {
for ( i = 0 ; i < ( endnum - startnum ) ; i + + ) {
2007-05-08 11:35:14 +04:00
udf_insert_aext ( inode , * epos , laarr [ i ] . extLocation ,
2007-07-19 12:47:43 +04:00
laarr [ i ] . extLength ) ;
2007-05-08 11:35:14 +04:00
udf_next_aext ( inode , epos , & laarr [ i ] . extLocation ,
2007-07-19 12:47:43 +04:00
& laarr [ i ] . extLength , 1 ) ;
start + + ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-19 12:47:43 +04:00
for ( i = start ; i < endnum ; i + + ) {
2007-05-08 11:35:14 +04:00
udf_next_aext ( inode , epos , & tmploc , & tmplen , 0 ) ;
udf_write_aext ( inode , epos , laarr [ i ] . extLocation ,
2007-07-19 12:47:43 +04:00
laarr [ i ] . extLength , 1 ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-19 12:47:43 +04:00
struct buffer_head * udf_bread ( struct inode * inode , int block ,
int create , int * err )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
struct buffer_head * bh = NULL ;
2005-04-17 02:20:36 +04:00
bh = udf_getblk ( inode , block , create , err ) ;
if ( ! bh )
return NULL ;
if ( buffer_uptodate ( bh ) )
return bh ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
ll_rw_block ( READ , 1 , & bh ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
wait_on_buffer ( bh ) ;
if ( buffer_uptodate ( bh ) )
return bh ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
brelse ( bh ) ;
* err = - EIO ;
return NULL ;
}
2007-07-19 12:47:43 +04:00
void udf_truncate ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
int offset ;
int err ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
if ( ! ( S_ISREG ( inode - > i_mode ) | | S_ISDIR ( inode - > i_mode ) | |
2007-07-19 12:47:43 +04:00
S_ISLNK ( inode - > i_mode ) ) )
2005-04-17 02:20:36 +04:00
return ;
if ( IS_APPEND ( inode ) | | IS_IMMUTABLE ( inode ) )
return ;
lock_kernel ( ) ;
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
2008-02-08 15:20:36 +03:00
if ( inode - > i_sb - > s_blocksize <
( udf_file_entry_alloc_offset ( inode ) +
inode - > i_size ) ) {
2005-04-17 02:20:36 +04:00
udf_expand_file_adinicb ( inode , inode - > i_size , & err ) ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
inode - > i_size = iinfo - > i_lenAlloc ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
return ;
2008-02-08 15:20:36 +03:00
} else
2005-04-17 02:20:36 +04:00
udf_truncate_extents ( inode ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
offset = inode - > i_size & ( inode - > i_sb - > s_blocksize - 1 ) ;
2008-02-08 15:20:44 +03:00
memset ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr + offset ,
2008-02-08 15:20:42 +03:00
0x00 , inode - > i_sb - > s_blocksize -
2008-02-08 15:20:36 +03:00
offset - udf_file_entry_alloc_offset ( inode ) ) ;
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc = inode - > i_size ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:36 +03:00
block_truncate_page ( inode - > i_mapping , inode - > i_size ,
udf_get_block ) ;
2005-04-17 02:20:36 +04:00
udf_truncate_extents ( inode ) ;
2007-07-16 10:39:47 +04:00
}
2005-04-17 02:20:36 +04:00
inode - > i_mtime = inode - > i_ctime = current_fs_time ( inode - > i_sb ) ;
if ( IS_SYNC ( inode ) )
2007-07-19 12:47:43 +04:00
udf_sync_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
else
mark_inode_dirty ( inode ) ;
unlock_kernel ( ) ;
}
2007-07-19 12:47:43 +04:00
static void __udf_read_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
struct fileEntry * fe ;
uint16_t ident ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
/*
* Set defaults , but the inode is still incomplete !
* Note : get_new_inode ( ) sets the following on a new inode :
* i_sb = sb
* i_no = ino
* i_flags = sb - > s_flags
* i_state = 0
* clean_inode ( ) : zero fills and sets
* i_count = 1
* i_nlink = 1
* i_op = NULL ;
*/
2008-02-08 15:20:44 +03:00
bh = udf_read_ptagged ( inode - > i_sb , iinfo - > i_location , 0 , & ident ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " udf: udf_read_inode(ino %ld) failed !bh \n " ,
2007-07-19 12:47:43 +04:00
inode - > i_ino ) ;
2005-04-17 02:20:36 +04:00
make_bad_inode ( inode ) ;
return ;
}
if ( ident ! = TAG_IDENT_FE & & ident ! = TAG_IDENT_EFE & &
2007-07-19 12:47:43 +04:00
ident ! = TAG_IDENT_USE ) {
2008-02-08 15:20:36 +03:00
printk ( KERN_ERR " udf: udf_read_inode(ino %ld) "
" failed ident=%d \n " , inode - > i_ino , ident ) ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
make_bad_inode ( inode ) ;
return ;
}
fe = ( struct fileEntry * ) bh - > b_data ;
2008-02-08 15:20:41 +03:00
if ( fe - > icbTag . strategyType = = cpu_to_le16 ( 4096 ) ) {
2005-04-17 02:20:36 +04:00
struct buffer_head * ibh = NULL , * nbh = NULL ;
struct indirectEntry * ie ;
2008-02-08 15:20:44 +03:00
ibh = udf_read_ptagged ( inode - > i_sb , iinfo - > i_location , 1 ,
2008-02-08 15:20:36 +03:00
& ident ) ;
2007-07-19 12:47:43 +04:00
if ( ident = = TAG_IDENT_IE ) {
if ( ibh ) {
2005-04-17 02:20:36 +04:00
kernel_lb_addr loc ;
ie = ( struct indirectEntry * ) ibh - > b_data ;
2007-07-16 10:39:47 +04:00
2005-04-17 02:20:36 +04:00
loc = lelb_to_cpu ( ie - > indirectICB . extLocation ) ;
2007-07-16 10:39:47 +04:00
if ( ie - > indirectICB . extLength & &
2008-02-08 15:20:36 +03:00
( nbh = udf_read_ptagged ( inode - > i_sb , loc , 0 ,
& ident ) ) ) {
2007-07-21 15:37:18 +04:00
if ( ident = = TAG_IDENT_FE | |
ident = = TAG_IDENT_EFE ) {
2008-02-08 15:20:44 +03:00
memcpy ( & iinfo - > i_location ,
2008-02-08 15:20:36 +03:00
& loc ,
2007-07-19 12:47:43 +04:00
sizeof ( kernel_lb_addr ) ) ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
brelse ( ibh ) ;
brelse ( nbh ) ;
2005-04-17 02:20:36 +04:00
__udf_read_inode ( inode ) ;
return ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:16 +04:00
brelse ( nbh ) ;
brelse ( ibh ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
} else {
2007-05-08 11:35:16 +04:00
brelse ( ibh ) ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
} else {
2007-05-08 11:35:16 +04:00
brelse ( ibh ) ;
2007-07-21 15:37:18 +04:00
}
2008-02-08 15:20:41 +03:00
} else if ( fe - > icbTag . strategyType ! = cpu_to_le16 ( 4 ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " udf: unsupported strategy type: %d \n " ,
2007-07-19 12:47:43 +04:00
le16_to_cpu ( fe - > icbTag . strategyType ) ) ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
make_bad_inode ( inode ) ;
return ;
}
udf_fill_inode ( inode , bh ) ;
2007-05-08 11:35:21 +04:00
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
}
static void udf_fill_inode ( struct inode * inode , struct buffer_head * bh )
{
struct fileEntry * fe ;
struct extendedFileEntry * efe ;
time_t convtime ;
long convtime_usec ;
int offset ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( inode - > i_sb ) ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
fe = ( struct fileEntry * ) bh - > b_data ;
efe = ( struct extendedFileEntry * ) bh - > b_data ;
2008-02-08 15:20:41 +03:00
if ( fe - > icbTag . strategyType = = cpu_to_le16 ( 4 ) )
2008-02-08 15:20:44 +03:00
iinfo - > i_strat4096 = 0 ;
2008-02-08 15:20:41 +03:00
else /* if (fe->icbTag.strategyType == cpu_to_le16(4096)) */
2008-02-08 15:20:44 +03:00
iinfo - > i_strat4096 = 1 ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type = le16_to_cpu ( fe - > icbTag . flags ) &
2008-02-08 15:20:36 +03:00
ICBTAG_FLAG_AD_MASK ;
2008-02-08 15:20:44 +03:00
iinfo - > i_unique = 0 ;
iinfo - > i_lenEAttr = 0 ;
iinfo - > i_lenExtents = 0 ;
iinfo - > i_lenAlloc = 0 ;
iinfo - > i_next_alloc_block = 0 ;
iinfo - > i_next_alloc_goal = 0 ;
2008-02-08 15:20:41 +03:00
if ( fe - > descTag . tagIdent = = cpu_to_le16 ( TAG_IDENT_EFE ) ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_efe = 1 ;
iinfo - > i_use = 0 ;
2008-02-08 15:20:36 +03:00
if ( udf_alloc_i_data ( inode , inode - > i_sb - > s_blocksize -
sizeof ( struct extendedFileEntry ) ) ) {
2007-07-16 10:39:47 +04:00
make_bad_inode ( inode ) ;
return ;
}
2008-02-08 15:20:44 +03:00
memcpy ( iinfo - > i_ext . i_data ,
2008-02-08 15:20:36 +03:00
bh - > b_data + sizeof ( struct extendedFileEntry ) ,
inode - > i_sb - > s_blocksize -
sizeof ( struct extendedFileEntry ) ) ;
2008-02-08 15:20:41 +03:00
} else if ( fe - > descTag . tagIdent = = cpu_to_le16 ( TAG_IDENT_FE ) ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_efe = 0 ;
iinfo - > i_use = 0 ;
2008-02-08 15:20:36 +03:00
if ( udf_alloc_i_data ( inode , inode - > i_sb - > s_blocksize -
sizeof ( struct fileEntry ) ) ) {
2007-07-16 10:39:47 +04:00
make_bad_inode ( inode ) ;
return ;
}
2008-02-08 15:20:44 +03:00
memcpy ( iinfo - > i_ext . i_data ,
2008-02-08 15:20:42 +03:00
bh - > b_data + sizeof ( struct fileEntry ) ,
2007-07-19 12:47:43 +04:00
inode - > i_sb - > s_blocksize - sizeof ( struct fileEntry ) ) ;
2008-02-08 15:20:41 +03:00
} else if ( fe - > descTag . tagIdent = = cpu_to_le16 ( TAG_IDENT_USE ) ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_efe = 0 ;
iinfo - > i_use = 1 ;
iinfo - > i_lenAlloc = le32_to_cpu (
2008-02-08 15:20:36 +03:00
( ( struct unallocSpaceEntry * ) bh - > b_data ) - >
lengthAllocDescs ) ;
if ( udf_alloc_i_data ( inode , inode - > i_sb - > s_blocksize -
sizeof ( struct unallocSpaceEntry ) ) ) {
2007-07-16 10:39:47 +04:00
make_bad_inode ( inode ) ;
return ;
}
2008-02-08 15:20:44 +03:00
memcpy ( iinfo - > i_ext . i_data ,
2008-02-08 15:20:36 +03:00
bh - > b_data + sizeof ( struct unallocSpaceEntry ) ,
inode - > i_sb - > s_blocksize -
sizeof ( struct unallocSpaceEntry ) ) ;
2005-04-17 02:20:36 +04:00
return ;
}
inode - > i_uid = le32_to_cpu ( fe - > uid ) ;
2007-07-31 11:39:40 +04:00
if ( inode - > i_uid = = - 1 | |
UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_UID_IGNORE ) | |
UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_UID_SET ) )
2006-03-08 08:55:24 +03:00
inode - > i_uid = UDF_SB ( inode - > i_sb ) - > s_uid ;
2005-04-17 02:20:36 +04:00
inode - > i_gid = le32_to_cpu ( fe - > gid ) ;
2007-07-31 11:39:40 +04:00
if ( inode - > i_gid = = - 1 | |
UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_GID_IGNORE ) | |
UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_GID_SET ) )
2006-03-08 08:55:24 +03:00
inode - > i_gid = UDF_SB ( inode - > i_sb ) - > s_gid ;
2005-04-17 02:20:36 +04:00
inode - > i_nlink = le16_to_cpu ( fe - > fileLinkCount ) ;
if ( ! inode - > i_nlink )
inode - > i_nlink = 1 ;
2007-07-16 10:39:47 +04:00
2005-04-17 02:20:36 +04:00
inode - > i_size = le64_to_cpu ( fe - > informationLength ) ;
2008-02-08 15:20:44 +03:00
iinfo - > i_lenExtents = inode - > i_size ;
2005-04-17 02:20:36 +04:00
inode - > i_mode = udf_convert_permissions ( fe ) ;
inode - > i_mode & = ~ UDF_SB ( inode - > i_sb ) - > s_umask ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_efe = = 0 ) {
2005-04-17 02:20:36 +04:00
inode - > i_blocks = le64_to_cpu ( fe - > logicalBlocksRecorded ) < <
2007-07-21 15:37:18 +04:00
( inode - > i_sb - > s_blocksize_bits - 9 ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( fe - > accessTime ) ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_atime . tv_sec = convtime ;
inode - > i_atime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:30 +03:00
inode - > i_atime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( fe - > modificationTime ) ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_mtime . tv_sec = convtime ;
inode - > i_mtime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:30 +03:00
inode - > i_mtime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( fe - > attrTime ) ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_ctime . tv_sec = convtime ;
inode - > i_ctime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:30 +03:00
inode - > i_ctime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
iinfo - > i_unique = le64_to_cpu ( fe - > uniqueID ) ;
iinfo - > i_lenEAttr = le32_to_cpu ( fe - > lengthExtendedAttr ) ;
iinfo - > i_lenAlloc = le32_to_cpu ( fe - > lengthAllocDescs ) ;
offset = sizeof ( struct fileEntry ) + iinfo - > i_lenEAttr ;
2007-07-19 12:47:43 +04:00
} else {
2007-07-16 10:39:47 +04:00
inode - > i_blocks = le64_to_cpu ( efe - > logicalBlocksRecorded ) < <
2007-07-19 12:47:43 +04:00
( inode - > i_sb - > s_blocksize_bits - 9 ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( efe - > accessTime ) ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_atime . tv_sec = convtime ;
inode - > i_atime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:30 +03:00
inode - > i_atime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( efe - > modificationTime ) ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_mtime . tv_sec = convtime ;
inode - > i_mtime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:30 +03:00
inode - > i_mtime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( efe - > createTime ) ) ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_crtime . tv_sec = convtime ;
iinfo - > i_crtime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:44 +03:00
iinfo - > i_crtime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( udf_stamp_to_time ( & convtime , & convtime_usec ,
lets_to_cpu ( efe - > attrTime ) ) ) {
2005-04-17 02:20:36 +04:00
inode - > i_ctime . tv_sec = convtime ;
inode - > i_ctime . tv_nsec = convtime_usec * 1000 ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:30 +03:00
inode - > i_ctime = sbi - > s_record_time ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
iinfo - > i_unique = le64_to_cpu ( efe - > uniqueID ) ;
iinfo - > i_lenEAttr = le32_to_cpu ( efe - > lengthExtendedAttr ) ;
iinfo - > i_lenAlloc = le32_to_cpu ( efe - > lengthAllocDescs ) ;
2008-02-08 15:20:36 +03:00
offset = sizeof ( struct extendedFileEntry ) +
2008-02-08 15:20:44 +03:00
iinfo - > i_lenEAttr ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
switch ( fe - > icbTag . fileType ) {
case ICBTAG_FILE_TYPE_DIRECTORY :
2007-07-21 15:37:18 +04:00
inode - > i_op = & udf_dir_inode_operations ;
inode - > i_fop = & udf_dir_operations ;
inode - > i_mode | = S_IFDIR ;
inc_nlink ( inode ) ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FILE_TYPE_REALTIME :
case ICBTAG_FILE_TYPE_REGULAR :
case ICBTAG_FILE_TYPE_UNDEF :
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
2007-07-21 15:37:18 +04:00
inode - > i_data . a_ops = & udf_adinicb_aops ;
else
inode - > i_data . a_ops = & udf_aops ;
inode - > i_op = & udf_file_inode_operations ;
inode - > i_fop = & udf_file_operations ;
inode - > i_mode | = S_IFREG ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FILE_TYPE_BLOCK :
2007-07-21 15:37:18 +04:00
inode - > i_mode | = S_IFBLK ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FILE_TYPE_CHAR :
2007-07-21 15:37:18 +04:00
inode - > i_mode | = S_IFCHR ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FILE_TYPE_FIFO :
2007-07-21 15:37:18 +04:00
init_special_inode ( inode , inode - > i_mode | S_IFIFO , 0 ) ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FILE_TYPE_SOCKET :
2007-07-21 15:37:18 +04:00
init_special_inode ( inode , inode - > i_mode | S_IFSOCK , 0 ) ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FILE_TYPE_SYMLINK :
2007-07-21 15:37:18 +04:00
inode - > i_data . a_ops = & udf_symlink_aops ;
inode - > i_op = & page_symlink_inode_operations ;
inode - > i_mode = S_IFLNK | S_IRWXUGO ;
break ;
2007-07-19 12:47:43 +04:00
default :
2008-02-08 15:20:36 +03:00
printk ( KERN_ERR " udf: udf_fill_inode(ino %ld) failed unknown "
" file type=%d \n " , inode - > i_ino ,
fe - > icbTag . fileType ) ;
2007-07-21 15:37:18 +04:00
make_bad_inode ( inode ) ;
return ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( S_ISCHR ( inode - > i_mode ) | | S_ISBLK ( inode - > i_mode ) ) {
2008-02-08 15:20:36 +03:00
struct deviceSpec * dsea =
( struct deviceSpec * ) udf_get_extendedattr ( inode , 12 , 1 ) ;
2007-07-19 12:47:43 +04:00
if ( dsea ) {
init_special_inode ( inode , inode - > i_mode ,
2008-02-08 15:20:36 +03:00
MKDEV ( le32_to_cpu ( dsea - > majorDeviceIdent ) ,
le32_to_cpu ( dsea - > minorDeviceIdent ) ) ) ;
2005-04-17 02:20:36 +04:00
/* Developer ID ??? */
2008-02-08 15:20:36 +03:00
} else
2005-04-17 02:20:36 +04:00
make_bad_inode ( inode ) ;
}
}
2007-07-16 10:39:47 +04:00
static int udf_alloc_i_data ( struct inode * inode , size_t size )
{
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
iinfo - > i_ext . i_data = kmalloc ( size , GFP_KERNEL ) ;
2007-07-16 10:39:47 +04:00
2008-02-08 15:20:44 +03:00
if ( ! iinfo - > i_ext . i_data ) {
2008-02-08 15:20:36 +03:00
printk ( KERN_ERR " udf:udf_alloc_i_data (ino %ld) "
" no free memory \n " , inode - > i_ino ) ;
2007-07-16 10:39:47 +04:00
return - ENOMEM ;
}
return 0 ;
}
2007-07-19 12:47:43 +04:00
static mode_t udf_convert_permissions ( struct fileEntry * fe )
2005-04-17 02:20:36 +04:00
{
mode_t mode ;
uint32_t permissions ;
uint32_t flags ;
permissions = le32_to_cpu ( fe - > permissions ) ;
flags = le16_to_cpu ( fe - > icbTag . flags ) ;
2008-02-08 15:20:36 +03:00
mode = ( ( permissions ) & S_IRWXO ) |
( ( permissions > > 2 ) & S_IRWXG ) |
( ( permissions > > 4 ) & S_IRWXU ) |
( ( flags & ICBTAG_FLAG_SETUID ) ? S_ISUID : 0 ) |
( ( flags & ICBTAG_FLAG_SETGID ) ? S_ISGID : 0 ) |
( ( flags & ICBTAG_FLAG_STICKY ) ? S_ISVTX : 0 ) ;
2005-04-17 02:20:36 +04:00
return mode ;
}
/*
* udf_write_inode
*
* PURPOSE
* Write out the specified inode .
*
* DESCRIPTION
* This routine is called whenever an inode is synced .
* Currently this routine is just a placeholder .
*
* HISTORY
* July 1 , 1997 - Andrew E . Mileski
* Written , tested , and released .
*/
2007-07-19 12:47:43 +04:00
int udf_write_inode ( struct inode * inode , int sync )
2005-04-17 02:20:36 +04:00
{
int ret ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
lock_kernel ( ) ;
ret = udf_update_inode ( inode , sync ) ;
unlock_kernel ( ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return ret ;
}
2007-07-19 12:47:43 +04:00
int udf_sync_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
return udf_update_inode ( inode , 1 ) ;
}
2007-07-19 12:47:43 +04:00
static int udf_update_inode ( struct inode * inode , int do_sync )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
struct fileEntry * fe ;
struct extendedFileEntry * efe ;
uint32_t udfperms ;
uint16_t icbflags ;
uint16_t crclen ;
kernel_timestamp cpu_time ;
int err = 0 ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( inode - > i_sb ) ;
2008-02-08 15:20:36 +03:00
unsigned char blocksize_bits = inode - > i_sb - > s_blocksize_bits ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
bh = udf_tread ( inode - > i_sb ,
udf_get_lb_pblock ( inode - > i_sb ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location , 0 ) ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " bread failure \n " ) ;
return - EIO ;
}
memset ( bh - > b_data , 0x00 , inode - > i_sb - > s_blocksize ) ;
fe = ( struct fileEntry * ) bh - > b_data ;
efe = ( struct extendedFileEntry * ) bh - > b_data ;
2008-02-08 15:20:41 +03:00
if ( fe - > descTag . tagIdent = = cpu_to_le16 ( TAG_IDENT_USE ) ) {
2005-04-17 02:20:36 +04:00
struct unallocSpaceEntry * use =
2007-07-21 15:37:18 +04:00
( struct unallocSpaceEntry * ) bh - > b_data ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
use - > lengthAllocDescs = cpu_to_le32 ( iinfo - > i_lenAlloc ) ;
2008-02-08 15:20:36 +03:00
memcpy ( bh - > b_data + sizeof ( struct unallocSpaceEntry ) ,
2008-02-08 15:20:44 +03:00
iinfo - > i_ext . i_data , inode - > i_sb - > s_blocksize -
2008-02-08 15:20:36 +03:00
sizeof ( struct unallocSpaceEntry ) ) ;
crclen = sizeof ( struct unallocSpaceEntry ) +
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc - sizeof ( tag ) ;
2008-02-08 15:20:36 +03:00
use - > descTag . tagLocation = cpu_to_le32 (
2008-02-08 15:20:44 +03:00
iinfo - > i_location .
2008-02-08 15:20:36 +03:00
logicalBlockNum ) ;
2005-04-17 02:20:36 +04:00
use - > descTag . descCRCLength = cpu_to_le16 ( crclen ) ;
2008-02-08 15:20:36 +03:00
use - > descTag . descCRC = cpu_to_le16 ( udf_crc ( ( char * ) use +
sizeof ( tag ) , crclen ,
0 ) ) ;
2008-02-08 15:20:39 +03:00
use - > descTag . tagChecksum = udf_tag_checksum ( & use - > descTag ) ;
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( bh ) ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
2006-03-08 08:55:24 +03:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_UID_FORGET ) )
fe - > uid = cpu_to_le32 ( - 1 ) ;
2007-07-19 12:47:43 +04:00
else
fe - > uid = cpu_to_le32 ( inode - > i_uid ) ;
2005-04-17 02:20:36 +04:00
2006-03-08 08:55:24 +03:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_GID_FORGET ) )
fe - > gid = cpu_to_le32 ( - 1 ) ;
2007-07-19 12:47:43 +04:00
else
fe - > gid = cpu_to_le32 ( inode - > i_gid ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
udfperms = ( ( inode - > i_mode & S_IRWXO ) ) |
( ( inode - > i_mode & S_IRWXG ) < < 2 ) |
( ( inode - > i_mode & S_IRWXU ) < < 4 ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
udfperms | = ( le32_to_cpu ( fe - > permissions ) &
( FE_PERM_O_DELETE | FE_PERM_O_CHATTR |
FE_PERM_G_DELETE | FE_PERM_G_CHATTR |
FE_PERM_U_DELETE | FE_PERM_U_CHATTR ) ) ;
2005-04-17 02:20:36 +04:00
fe - > permissions = cpu_to_le32 ( udfperms ) ;
if ( S_ISDIR ( inode - > i_mode ) )
fe - > fileLinkCount = cpu_to_le16 ( inode - > i_nlink - 1 ) ;
else
fe - > fileLinkCount = cpu_to_le16 ( inode - > i_nlink ) ;
fe - > informationLength = cpu_to_le64 ( inode - > i_size ) ;
2007-07-19 12:47:43 +04:00
if ( S_ISCHR ( inode - > i_mode ) | | S_ISBLK ( inode - > i_mode ) ) {
2005-04-17 02:20:36 +04:00
regid * eid ;
2007-07-21 15:37:18 +04:00
struct deviceSpec * dsea =
( struct deviceSpec * ) udf_get_extendedattr ( inode , 12 , 1 ) ;
2007-07-19 12:47:43 +04:00
if ( ! dsea ) {
2005-04-17 02:20:36 +04:00
dsea = ( struct deviceSpec * )
2007-07-21 15:37:18 +04:00
udf_add_extendedattr ( inode ,
sizeof ( struct deviceSpec ) +
sizeof ( regid ) , 12 , 0x3 ) ;
2005-04-17 02:20:36 +04:00
dsea - > attrType = cpu_to_le32 ( 12 ) ;
dsea - > attrSubtype = 1 ;
2008-02-08 15:20:36 +03:00
dsea - > attrLength = cpu_to_le32 (
sizeof ( struct deviceSpec ) +
sizeof ( regid ) ) ;
2005-04-17 02:20:36 +04:00
dsea - > impUseLength = cpu_to_le32 ( sizeof ( regid ) ) ;
}
2007-07-21 15:37:18 +04:00
eid = ( regid * ) dsea - > impUse ;
2005-04-17 02:20:36 +04:00
memset ( eid , 0 , sizeof ( regid ) ) ;
strcpy ( eid - > ident , UDF_ID_DEVELOPER ) ;
eid - > identSuffix [ 0 ] = UDF_OS_CLASS_UNIX ;
eid - > identSuffix [ 1 ] = UDF_OS_ID_LINUX ;
dsea - > majorDeviceIdent = cpu_to_le32 ( imajor ( inode ) ) ;
dsea - > minorDeviceIdent = cpu_to_le32 ( iminor ( inode ) ) ;
}
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_efe = = 0 ) {
2008-02-08 15:20:42 +03:00
memcpy ( bh - > b_data + sizeof ( struct fileEntry ) ,
2008-02-08 15:20:44 +03:00
iinfo - > i_ext . i_data ,
2007-07-19 12:47:43 +04:00
inode - > i_sb - > s_blocksize - sizeof ( struct fileEntry ) ) ;
2007-07-21 15:37:18 +04:00
fe - > logicalBlocksRecorded = cpu_to_le64 (
2008-02-08 15:20:36 +03:00
( inode - > i_blocks + ( 1 < < ( blocksize_bits - 9 ) ) - 1 ) > >
( blocksize_bits - 9 ) ) ;
2005-04-17 02:20:36 +04:00
if ( udf_time_to_stamp ( & cpu_time , inode - > i_atime ) )
fe - > accessTime = cpu_to_lets ( cpu_time ) ;
if ( udf_time_to_stamp ( & cpu_time , inode - > i_mtime ) )
fe - > modificationTime = cpu_to_lets ( cpu_time ) ;
if ( udf_time_to_stamp ( & cpu_time , inode - > i_ctime ) )
fe - > attrTime = cpu_to_lets ( cpu_time ) ;
memset ( & ( fe - > impIdent ) , 0 , sizeof ( regid ) ) ;
strcpy ( fe - > impIdent . ident , UDF_ID_DEVELOPER ) ;
fe - > impIdent . identSuffix [ 0 ] = UDF_OS_CLASS_UNIX ;
fe - > impIdent . identSuffix [ 1 ] = UDF_OS_ID_LINUX ;
2008-02-08 15:20:44 +03:00
fe - > uniqueID = cpu_to_le64 ( iinfo - > i_unique ) ;
fe - > lengthExtendedAttr = cpu_to_le32 ( iinfo - > i_lenEAttr ) ;
fe - > lengthAllocDescs = cpu_to_le32 ( iinfo - > i_lenAlloc ) ;
2005-04-17 02:20:36 +04:00
fe - > descTag . tagIdent = cpu_to_le16 ( TAG_IDENT_FE ) ;
crclen = sizeof ( struct fileEntry ) ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:36 +03:00
memcpy ( bh - > b_data + sizeof ( struct extendedFileEntry ) ,
2008-02-08 15:20:44 +03:00
iinfo - > i_ext . i_data ,
2008-02-08 15:20:36 +03:00
inode - > i_sb - > s_blocksize -
sizeof ( struct extendedFileEntry ) ) ;
2005-04-17 02:20:36 +04:00
efe - > objectSize = cpu_to_le64 ( inode - > i_size ) ;
2007-07-21 15:37:18 +04:00
efe - > logicalBlocksRecorded = cpu_to_le64 (
2008-02-08 15:20:36 +03:00
( inode - > i_blocks + ( 1 < < ( blocksize_bits - 9 ) ) - 1 ) > >
( blocksize_bits - 9 ) ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_crtime . tv_sec > inode - > i_atime . tv_sec | |
( iinfo - > i_crtime . tv_sec = = inode - > i_atime . tv_sec & &
iinfo - > i_crtime . tv_nsec > inode - > i_atime . tv_nsec ) )
iinfo - > i_crtime = inode - > i_atime ;
2008-02-08 15:20:36 +03:00
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_crtime . tv_sec > inode - > i_mtime . tv_sec | |
( iinfo - > i_crtime . tv_sec = = inode - > i_mtime . tv_sec & &
iinfo - > i_crtime . tv_nsec > inode - > i_mtime . tv_nsec ) )
iinfo - > i_crtime = inode - > i_mtime ;
2008-02-08 15:20:36 +03:00
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_crtime . tv_sec > inode - > i_ctime . tv_sec | |
( iinfo - > i_crtime . tv_sec = = inode - > i_ctime . tv_sec & &
iinfo - > i_crtime . tv_nsec > inode - > i_ctime . tv_nsec ) )
iinfo - > i_crtime = inode - > i_ctime ;
2005-04-17 02:20:36 +04:00
if ( udf_time_to_stamp ( & cpu_time , inode - > i_atime ) )
efe - > accessTime = cpu_to_lets ( cpu_time ) ;
if ( udf_time_to_stamp ( & cpu_time , inode - > i_mtime ) )
efe - > modificationTime = cpu_to_lets ( cpu_time ) ;
2008-02-08 15:20:44 +03:00
if ( udf_time_to_stamp ( & cpu_time , iinfo - > i_crtime ) )
2005-04-17 02:20:36 +04:00
efe - > createTime = cpu_to_lets ( cpu_time ) ;
if ( udf_time_to_stamp ( & cpu_time , inode - > i_ctime ) )
efe - > attrTime = cpu_to_lets ( cpu_time ) ;
memset ( & ( efe - > impIdent ) , 0 , sizeof ( regid ) ) ;
strcpy ( efe - > impIdent . ident , UDF_ID_DEVELOPER ) ;
efe - > impIdent . identSuffix [ 0 ] = UDF_OS_CLASS_UNIX ;
efe - > impIdent . identSuffix [ 1 ] = UDF_OS_ID_LINUX ;
2008-02-08 15:20:44 +03:00
efe - > uniqueID = cpu_to_le64 ( iinfo - > i_unique ) ;
efe - > lengthExtendedAttr = cpu_to_le32 ( iinfo - > i_lenEAttr ) ;
efe - > lengthAllocDescs = cpu_to_le32 ( iinfo - > i_lenAlloc ) ;
2005-04-17 02:20:36 +04:00
efe - > descTag . tagIdent = cpu_to_le16 ( TAG_IDENT_EFE ) ;
crclen = sizeof ( struct extendedFileEntry ) ;
}
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_strat4096 ) {
2005-04-17 02:20:36 +04:00
fe - > icbTag . strategyType = cpu_to_le16 ( 4096 ) ;
fe - > icbTag . strategyParameter = cpu_to_le16 ( 1 ) ;
fe - > icbTag . numEntries = cpu_to_le16 ( 2 ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
fe - > icbTag . strategyType = cpu_to_le16 ( 4 ) ;
fe - > icbTag . numEntries = cpu_to_le16 ( 1 ) ;
}
if ( S_ISDIR ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_DIRECTORY ;
else if ( S_ISREG ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_REGULAR ;
else if ( S_ISLNK ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_SYMLINK ;
else if ( S_ISBLK ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_BLOCK ;
else if ( S_ISCHR ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_CHAR ;
else if ( S_ISFIFO ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_FIFO ;
else if ( S_ISSOCK ( inode - > i_mode ) )
fe - > icbTag . fileType = ICBTAG_FILE_TYPE_SOCKET ;
2008-02-08 15:20:44 +03:00
icbflags = iinfo - > i_alloc_type |
2007-07-21 15:37:18 +04:00
( ( inode - > i_mode & S_ISUID ) ? ICBTAG_FLAG_SETUID : 0 ) |
( ( inode - > i_mode & S_ISGID ) ? ICBTAG_FLAG_SETGID : 0 ) |
( ( inode - > i_mode & S_ISVTX ) ? ICBTAG_FLAG_STICKY : 0 ) |
( le16_to_cpu ( fe - > icbTag . flags ) &
~ ( ICBTAG_FLAG_AD_MASK | ICBTAG_FLAG_SETUID |
ICBTAG_FLAG_SETGID | ICBTAG_FLAG_STICKY ) ) ;
2005-04-17 02:20:36 +04:00
fe - > icbTag . flags = cpu_to_le16 ( icbflags ) ;
2008-02-08 15:20:30 +03:00
if ( sbi - > s_udfrev > = 0x0200 )
2005-04-17 02:20:36 +04:00
fe - > descTag . descVersion = cpu_to_le16 ( 3 ) ;
else
fe - > descTag . descVersion = cpu_to_le16 ( 2 ) ;
2008-02-08 15:20:30 +03:00
fe - > descTag . tagSerialNum = cpu_to_le16 ( sbi - > s_serial_number ) ;
2008-02-08 15:20:36 +03:00
fe - > descTag . tagLocation = cpu_to_le32 (
2008-02-08 15:20:44 +03:00
iinfo - > i_location . logicalBlockNum ) ;
crclen + = iinfo - > i_lenEAttr + iinfo - > i_lenAlloc -
2008-02-08 15:20:42 +03:00
sizeof ( tag ) ;
2005-04-17 02:20:36 +04:00
fe - > descTag . descCRCLength = cpu_to_le16 ( crclen ) ;
2008-02-08 15:20:36 +03:00
fe - > descTag . descCRC = cpu_to_le16 ( udf_crc ( ( char * ) fe + sizeof ( tag ) ,
crclen , 0 ) ) ;
2008-02-08 15:20:39 +03:00
fe - > descTag . tagChecksum = udf_tag_checksum ( & fe - > descTag ) ;
2005-04-17 02:20:36 +04:00
/* write the data blocks */
mark_buffer_dirty ( bh ) ;
2007-07-19 12:47:43 +04:00
if ( do_sync ) {
2005-04-17 02:20:36 +04:00
sync_dirty_buffer ( bh ) ;
2007-07-19 12:47:43 +04:00
if ( buffer_req ( bh ) & & ! buffer_uptodate ( bh ) ) {
2008-02-08 15:20:36 +03:00
printk ( KERN_WARNING " IO error syncing udf inode "
" [%s:%08lx] \n " , inode - > i_sb - > s_id ,
inode - > i_ino ) ;
2005-04-17 02:20:36 +04:00
err = - EIO ;
}
}
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return err ;
}
2007-07-19 12:47:43 +04:00
struct inode * udf_iget ( struct super_block * sb , kernel_lb_addr ino )
2005-04-17 02:20:36 +04:00
{
unsigned long block = udf_get_lb_pblock ( sb , ino , 0 ) ;
struct inode * inode = iget_locked ( sb , block ) ;
if ( ! inode )
return NULL ;
if ( inode - > i_state & I_NEW ) {
2008-02-08 15:20:42 +03:00
memcpy ( & UDF_I ( inode ) - > i_location , & ino , sizeof ( kernel_lb_addr ) ) ;
2005-04-17 02:20:36 +04:00
__udf_read_inode ( inode ) ;
unlock_new_inode ( inode ) ;
}
if ( is_bad_inode ( inode ) )
goto out_iput ;
2008-02-08 15:20:36 +03:00
if ( ino . logicalBlockNum > = UDF_SB ( sb ) - >
s_partmaps [ ino . partitionReferenceNum ] . s_partition_len ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " block=%d, partition=%d out of range \n " ,
2007-07-19 12:47:43 +04:00
ino . logicalBlockNum , ino . partitionReferenceNum ) ;
2005-04-17 02:20:36 +04:00
make_bad_inode ( inode ) ;
goto out_iput ;
}
return inode ;
2007-07-21 15:37:18 +04:00
out_iput :
2005-04-17 02:20:36 +04:00
iput ( inode ) ;
return NULL ;
}
2008-02-08 15:20:36 +03:00
int8_t udf_add_aext ( struct inode * inode , struct extent_position * epos ,
2007-07-19 12:47:43 +04:00
kernel_lb_addr eloc , uint32_t elen , int inc )
2005-04-17 02:20:36 +04:00
{
int adsize ;
short_ad * sad = NULL ;
long_ad * lad = NULL ;
struct allocExtDesc * aed ;
int8_t etype ;
uint8_t * ptr ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
if ( ! epos - > bh )
2008-02-08 15:20:44 +03:00
ptr = iinfo - > i_ext . i_data + epos - > offset -
2008-02-08 15:20:36 +03:00
udf_file_entry_alloc_offset ( inode ) +
2008-02-08 15:20:44 +03:00
iinfo - > i_lenEAttr ;
2005-04-17 02:20:36 +04:00
else
2007-05-08 11:35:14 +04:00
ptr = epos - > bh - > b_data + epos - > offset ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2005-04-17 02:20:36 +04:00
adsize = sizeof ( short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2005-04-17 02:20:36 +04:00
adsize = sizeof ( long_ad ) ;
else
return - 1 ;
2007-07-19 12:47:43 +04:00
if ( epos - > offset + ( 2 * adsize ) > inode - > i_sb - > s_blocksize ) {
2005-04-17 02:20:36 +04:00
char * sptr , * dptr ;
struct buffer_head * nbh ;
int err , loffset ;
2007-05-08 11:35:14 +04:00
kernel_lb_addr obloc = epos - > block ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
epos - > block . logicalBlockNum = udf_new_block ( inode - > i_sb , NULL ,
obloc . partitionReferenceNum ,
obloc . logicalBlockNum , & err ) ;
if ( ! epos - > block . logicalBlockNum )
2005-04-17 02:20:36 +04:00
return - 1 ;
2008-02-08 15:20:36 +03:00
nbh = udf_tgetblk ( inode - > i_sb , udf_get_lb_pblock ( inode - > i_sb ,
epos - > block ,
0 ) ) ;
if ( ! nbh )
2005-04-17 02:20:36 +04:00
return - 1 ;
lock_buffer ( nbh ) ;
memset ( nbh - > b_data , 0x00 , inode - > i_sb - > s_blocksize ) ;
set_buffer_uptodate ( nbh ) ;
unlock_buffer ( nbh ) ;
mark_buffer_dirty_inode ( nbh , inode ) ;
aed = ( struct allocExtDesc * ) ( nbh - > b_data ) ;
if ( ! UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) )
2008-02-08 15:20:36 +03:00
aed - > previousAllocExtLocation =
cpu_to_le32 ( obloc . logicalBlockNum ) ;
2007-07-19 12:47:43 +04:00
if ( epos - > offset + adsize > inode - > i_sb - > s_blocksize ) {
2007-05-08 11:35:14 +04:00
loffset = epos - > offset ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs = cpu_to_le32 ( adsize ) ;
sptr = ptr - adsize ;
dptr = nbh - > b_data + sizeof ( struct allocExtDesc ) ;
memcpy ( dptr , sptr , adsize ) ;
2007-05-08 11:35:14 +04:00
epos - > offset = sizeof ( struct allocExtDesc ) + adsize ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:14 +04:00
loffset = epos - > offset + adsize ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs = cpu_to_le32 ( 0 ) ;
sptr = ptr ;
2007-05-08 11:35:14 +04:00
epos - > offset = sizeof ( struct allocExtDesc ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( epos - > bh ) {
2007-05-08 11:35:14 +04:00
aed = ( struct allocExtDesc * ) epos - > bh - > b_data ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs =
2008-02-08 15:20:36 +03:00
cpu_to_le32 ( le32_to_cpu (
aed - > lengthAllocDescs ) + adsize ) ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc + = adsize ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
}
}
2008-02-08 15:20:30 +03:00
if ( UDF_SB ( inode - > i_sb ) - > s_udfrev > = 0x0200 )
2005-04-17 02:20:36 +04:00
udf_new_tag ( nbh - > b_data , TAG_IDENT_AED , 3 , 1 ,
2007-07-19 12:47:43 +04:00
epos - > block . logicalBlockNum , sizeof ( tag ) ) ;
2005-04-17 02:20:36 +04:00
else
udf_new_tag ( nbh - > b_data , TAG_IDENT_AED , 2 , 1 ,
2007-07-19 12:47:43 +04:00
epos - > block . logicalBlockNum , sizeof ( tag ) ) ;
2008-02-08 15:20:44 +03:00
switch ( iinfo - > i_alloc_type ) {
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_SHORT :
2007-07-21 15:37:18 +04:00
sad = ( short_ad * ) sptr ;
sad - > extLength = cpu_to_le32 ( EXT_NEXT_EXTENT_ALLOCDECS |
inode - > i_sb - > s_blocksize ) ;
2008-02-08 15:20:36 +03:00
sad - > extPosition =
cpu_to_le32 ( epos - > block . logicalBlockNum ) ;
2007-07-21 15:37:18 +04:00
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_LONG :
2007-07-21 15:37:18 +04:00
lad = ( long_ad * ) sptr ;
lad - > extLength = cpu_to_le32 ( EXT_NEXT_EXTENT_ALLOCDECS |
inode - > i_sb - > s_blocksize ) ;
lad - > extLocation = cpu_to_lelb ( epos - > block ) ;
memset ( lad - > impUse , 0x00 , sizeof ( lad - > impUse ) ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( epos - > bh ) {
2007-07-21 15:37:18 +04:00
if ( ! UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) | |
2008-02-08 15:20:30 +03:00
UDF_SB ( inode - > i_sb ) - > s_udfrev > = 0x0201 )
2007-05-08 11:35:14 +04:00
udf_update_tag ( epos - > bh - > b_data , loffset ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:36 +03:00
udf_update_tag ( epos - > bh - > b_data ,
sizeof ( struct allocExtDesc ) ) ;
2007-05-08 11:35:14 +04:00
mark_buffer_dirty_inode ( epos - > bh , inode ) ;
2007-05-08 11:35:16 +04:00
brelse ( epos - > bh ) ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2007-07-21 15:37:18 +04:00
}
2007-05-08 11:35:14 +04:00
epos - > bh = nbh ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:35:14 +04:00
etype = udf_write_aext ( inode , epos , eloc , elen , inc ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ! epos - > bh ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc + = adsize ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:14 +04:00
aed = ( struct allocExtDesc * ) epos - > bh - > b_data ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs =
2008-02-08 15:20:36 +03:00
cpu_to_le32 ( le32_to_cpu ( aed - > lengthAllocDescs ) +
adsize ) ;
if ( ! UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) | |
UDF_SB ( inode - > i_sb ) - > s_udfrev > = 0x0201 )
udf_update_tag ( epos - > bh - > b_data ,
epos - > offset + ( inc ? 0 : adsize ) ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:36 +03:00
udf_update_tag ( epos - > bh - > b_data ,
sizeof ( struct allocExtDesc ) ) ;
2007-05-08 11:35:14 +04:00
mark_buffer_dirty_inode ( epos - > bh , inode ) ;
2005-04-17 02:20:36 +04:00
}
return etype ;
}
2008-02-08 15:20:36 +03:00
int8_t udf_write_aext ( struct inode * inode , struct extent_position * epos ,
2007-07-19 12:47:43 +04:00
kernel_lb_addr eloc , uint32_t elen , int inc )
2005-04-17 02:20:36 +04:00
{
int adsize ;
uint8_t * ptr ;
2007-07-21 15:37:18 +04:00
short_ad * sad ;
long_ad * lad ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
if ( ! epos - > bh )
2008-02-08 15:20:44 +03:00
ptr = iinfo - > i_ext . i_data + epos - > offset -
2008-02-08 15:20:36 +03:00
udf_file_entry_alloc_offset ( inode ) +
2008-02-08 15:20:44 +03:00
iinfo - > i_lenEAttr ;
2005-04-17 02:20:36 +04:00
else
2007-05-08 11:35:14 +04:00
ptr = epos - > bh - > b_data + epos - > offset ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
switch ( iinfo - > i_alloc_type ) {
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_SHORT :
2007-07-21 15:37:18 +04:00
sad = ( short_ad * ) ptr ;
sad - > extLength = cpu_to_le32 ( elen ) ;
sad - > extPosition = cpu_to_le32 ( eloc . logicalBlockNum ) ;
adsize = sizeof ( short_ad ) ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_LONG :
2007-07-21 15:37:18 +04:00
lad = ( long_ad * ) ptr ;
lad - > extLength = cpu_to_le32 ( elen ) ;
lad - > extLocation = cpu_to_lelb ( eloc ) ;
memset ( lad - > impUse , 0x00 , sizeof ( lad - > impUse ) ) ;
adsize = sizeof ( long_ad ) ;
break ;
2007-07-19 12:47:43 +04:00
default :
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( epos - > bh ) {
2007-07-21 15:37:18 +04:00
if ( ! UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) | |
2008-02-08 15:20:30 +03:00
UDF_SB ( inode - > i_sb ) - > s_udfrev > = 0x0201 ) {
2008-02-08 15:20:36 +03:00
struct allocExtDesc * aed =
( struct allocExtDesc * ) epos - > bh - > b_data ;
2007-05-08 11:35:14 +04:00
udf_update_tag ( epos - > bh - > b_data ,
2008-02-08 15:20:36 +03:00
le32_to_cpu ( aed - > lengthAllocDescs ) +
sizeof ( struct allocExtDesc ) ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:35:14 +04:00
mark_buffer_dirty_inode ( epos - > bh , inode ) ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
if ( inc )
2007-05-08 11:35:14 +04:00
epos - > offset + = adsize ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return ( elen > > 30 ) ;
}
2008-02-08 15:20:36 +03:00
int8_t udf_next_aext ( struct inode * inode , struct extent_position * epos ,
kernel_lb_addr * eloc , uint32_t * elen , int inc )
2005-04-17 02:20:36 +04:00
{
int8_t etype ;
2007-05-08 11:35:14 +04:00
while ( ( etype = udf_current_aext ( inode , epos , eloc , elen , inc ) ) = =
2007-07-19 12:47:43 +04:00
( EXT_NEXT_EXTENT_ALLOCDECS > > 30 ) ) {
2008-02-08 15:20:36 +03:00
int block ;
2007-05-08 11:35:14 +04:00
epos - > block = * eloc ;
epos - > offset = sizeof ( struct allocExtDesc ) ;
2007-05-08 11:35:16 +04:00
brelse ( epos - > bh ) ;
2008-02-08 15:20:36 +03:00
block = udf_get_lb_pblock ( inode - > i_sb , epos - > block , 0 ) ;
epos - > bh = udf_tread ( inode - > i_sb , block ) ;
if ( ! epos - > bh ) {
udf_debug ( " reading block %d failed! \n " , block ) ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
}
return etype ;
}
2008-02-08 15:20:36 +03:00
int8_t udf_current_aext ( struct inode * inode , struct extent_position * epos ,
kernel_lb_addr * eloc , uint32_t * elen , int inc )
2005-04-17 02:20:36 +04:00
{
int alen ;
int8_t etype ;
uint8_t * ptr ;
2007-07-21 15:37:18 +04:00
short_ad * sad ;
long_ad * lad ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2007-07-21 15:37:18 +04:00
2007-07-19 12:47:43 +04:00
if ( ! epos - > bh ) {
2007-05-08 11:35:14 +04:00
if ( ! epos - > offset )
epos - > offset = udf_file_entry_alloc_offset ( inode ) ;
2008-02-08 15:20:44 +03:00
ptr = iinfo - > i_ext . i_data + epos - > offset -
2008-02-08 15:20:36 +03:00
udf_file_entry_alloc_offset ( inode ) +
2008-02-08 15:20:44 +03:00
iinfo - > i_lenEAttr ;
2008-02-08 15:20:36 +03:00
alen = udf_file_entry_alloc_offset ( inode ) +
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:14 +04:00
if ( ! epos - > offset )
epos - > offset = sizeof ( struct allocExtDesc ) ;
ptr = epos - > bh - > b_data + epos - > offset ;
2007-07-21 15:37:18 +04:00
alen = sizeof ( struct allocExtDesc ) +
2008-02-08 15:20:36 +03:00
le32_to_cpu ( ( ( struct allocExtDesc * ) epos - > bh - > b_data ) - >
lengthAllocDescs ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
switch ( iinfo - > i_alloc_type ) {
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_SHORT :
2008-02-08 15:20:36 +03:00
sad = udf_get_fileshortad ( ptr , alen , & epos - > offset , inc ) ;
if ( ! sad )
2007-07-21 15:37:18 +04:00
return - 1 ;
etype = le32_to_cpu ( sad - > extLength ) > > 30 ;
eloc - > logicalBlockNum = le32_to_cpu ( sad - > extPosition ) ;
2008-02-08 15:20:36 +03:00
eloc - > partitionReferenceNum =
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ;
2007-07-21 15:37:18 +04:00
* elen = le32_to_cpu ( sad - > extLength ) & UDF_EXTENT_LENGTH_MASK ;
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_LONG :
2008-02-08 15:20:36 +03:00
lad = udf_get_filelongad ( ptr , alen , & epos - > offset , inc ) ;
if ( ! lad )
2005-04-17 02:20:36 +04:00
return - 1 ;
2007-07-21 15:37:18 +04:00
etype = le32_to_cpu ( lad - > extLength ) > > 30 ;
* eloc = lelb_to_cpu ( lad - > extLocation ) ;
* elen = le32_to_cpu ( lad - > extLength ) & UDF_EXTENT_LENGTH_MASK ;
break ;
default :
2008-02-08 15:20:36 +03:00
udf_debug ( " alloc_type = %d unsupported \n " ,
2008-02-08 15:20:44 +03:00
iinfo - > i_alloc_type ) ;
2007-07-21 15:37:18 +04:00
return - 1 ;
2005-04-17 02:20:36 +04:00
}
return etype ;
}
2007-07-21 15:37:18 +04:00
static int8_t udf_insert_aext ( struct inode * inode , struct extent_position epos ,
kernel_lb_addr neloc , uint32_t nelen )
2005-04-17 02:20:36 +04:00
{
kernel_lb_addr oeloc ;
uint32_t oelen ;
int8_t etype ;
2007-05-08 11:35:14 +04:00
if ( epos . bh )
2007-05-08 11:35:16 +04:00
get_bh ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
while ( ( etype = udf_next_aext ( inode , & epos , & oeloc , & oelen , 0 ) ) ! = - 1 ) {
2007-05-08 11:35:14 +04:00
udf_write_aext ( inode , & epos , neloc , nelen , 1 ) ;
2005-04-17 02:20:36 +04:00
neloc = oeloc ;
nelen = ( etype < < 30 ) | oelen ;
}
2007-05-08 11:35:14 +04:00
udf_add_aext ( inode , & epos , neloc , nelen , 1 ) ;
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return ( nelen > > 30 ) ;
}
2008-02-08 15:20:36 +03:00
int8_t udf_delete_aext ( struct inode * inode , struct extent_position epos ,
2007-07-19 12:47:43 +04:00
kernel_lb_addr eloc , uint32_t elen )
2005-04-17 02:20:36 +04:00
{
2007-05-08 11:35:14 +04:00
struct extent_position oepos ;
int adsize ;
2005-04-17 02:20:36 +04:00
int8_t etype ;
struct allocExtDesc * aed ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( epos . bh ) {
2007-05-08 11:35:16 +04:00
get_bh ( epos . bh ) ;
get_bh ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2005-04-17 02:20:36 +04:00
adsize = sizeof ( short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2005-04-17 02:20:36 +04:00
adsize = sizeof ( long_ad ) ;
else
adsize = 0 ;
2007-05-08 11:35:14 +04:00
oepos = epos ;
if ( udf_next_aext ( inode , & epos , & eloc , & elen , 1 ) = = - 1 )
2005-04-17 02:20:36 +04:00
return - 1 ;
2007-07-19 12:47:43 +04:00
while ( ( etype = udf_next_aext ( inode , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2007-05-08 11:35:14 +04:00
udf_write_aext ( inode , & oepos , eloc , ( etype < < 30 ) | elen , 1 ) ;
2007-07-19 12:47:43 +04:00
if ( oepos . bh ! = epos . bh ) {
2007-05-08 11:35:14 +04:00
oepos . block = epos . block ;
2007-05-08 11:35:16 +04:00
brelse ( oepos . bh ) ;
get_bh ( epos . bh ) ;
2007-05-08 11:35:14 +04:00
oepos . bh = epos . bh ;
oepos . offset = epos . offset - adsize ;
2005-04-17 02:20:36 +04:00
}
}
memset ( & eloc , 0x00 , sizeof ( kernel_lb_addr ) ) ;
elen = 0 ;
2007-07-19 12:47:43 +04:00
if ( epos . bh ! = oepos . bh ) {
2007-05-08 11:35:14 +04:00
udf_free_blocks ( inode - > i_sb , inode , epos . block , 0 , 1 ) ;
udf_write_aext ( inode , & oepos , eloc , elen , 1 ) ;
udf_write_aext ( inode , & oepos , eloc , elen , 1 ) ;
2007-07-19 12:47:43 +04:00
if ( ! oepos . bh ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc - = ( adsize * 2 ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:14 +04:00
aed = ( struct allocExtDesc * ) oepos . bh - > b_data ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs =
2008-02-08 15:20:36 +03:00
cpu_to_le32 ( le32_to_cpu ( aed - > lengthAllocDescs ) -
( 2 * adsize ) ) ;
2007-07-21 15:37:18 +04:00
if ( ! UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) | |
2008-02-08 15:20:30 +03:00
UDF_SB ( inode - > i_sb ) - > s_udfrev > = 0x0201 )
2008-02-08 15:20:36 +03:00
udf_update_tag ( oepos . bh - > b_data ,
oepos . offset - ( 2 * adsize ) ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:36 +03:00
udf_update_tag ( oepos . bh - > b_data ,
sizeof ( struct allocExtDesc ) ) ;
2007-05-08 11:35:14 +04:00
mark_buffer_dirty_inode ( oepos . bh , inode ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:14 +04:00
udf_write_aext ( inode , & oepos , eloc , elen , 1 ) ;
2007-07-19 12:47:43 +04:00
if ( ! oepos . bh ) {
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc - = adsize ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2007-07-19 12:47:43 +04:00
} else {
2007-05-08 11:35:14 +04:00
aed = ( struct allocExtDesc * ) oepos . bh - > b_data ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs =
2008-02-08 15:20:36 +03:00
cpu_to_le32 ( le32_to_cpu ( aed - > lengthAllocDescs ) -
adsize ) ;
2007-07-21 15:37:18 +04:00
if ( ! UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_STRICT ) | |
2008-02-08 15:20:30 +03:00
UDF_SB ( inode - > i_sb ) - > s_udfrev > = 0x0201 )
2008-02-08 15:20:36 +03:00
udf_update_tag ( oepos . bh - > b_data ,
epos . offset - adsize ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:36 +03:00
udf_update_tag ( oepos . bh - > b_data ,
sizeof ( struct allocExtDesc ) ) ;
2007-05-08 11:35:14 +04:00
mark_buffer_dirty_inode ( oepos . bh , inode ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-16 10:39:47 +04:00
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
brelse ( oepos . bh ) ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return ( elen > > 30 ) ;
}
2008-02-08 15:20:36 +03:00
int8_t inode_bmap ( struct inode * inode , sector_t block ,
struct extent_position * pos , kernel_lb_addr * eloc ,
uint32_t * elen , sector_t * offset )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:36 +03:00
unsigned char blocksize_bits = inode - > i_sb - > s_blocksize_bits ;
2007-07-19 12:47:43 +04:00
loff_t lbcount = 0 , bcount =
2008-02-08 15:20:36 +03:00
( loff_t ) block < < blocksize_bits ;
2005-04-17 02:20:36 +04:00
int8_t etype ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( block < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " udf: inode_bmap: block < 0 \n " ) ;
return - 1 ;
}
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2007-05-08 11:35:14 +04:00
pos - > offset = 0 ;
2008-02-08 15:20:44 +03:00
pos - > block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
pos - > bh = NULL ;
2005-04-17 02:20:36 +04:00
* elen = 0 ;
2007-07-19 12:47:43 +04:00
do {
2008-02-08 15:20:36 +03:00
etype = udf_next_aext ( inode , pos , eloc , elen , 1 ) ;
if ( etype = = - 1 ) {
* offset = ( bcount - lbcount ) > > blocksize_bits ;
2008-02-08 15:20:44 +03:00
iinfo - > i_lenExtents = lbcount ;
2005-04-17 02:20:36 +04:00
return - 1 ;
}
lbcount + = * elen ;
} while ( lbcount < = bcount ) ;
2008-02-08 15:20:36 +03:00
* offset = ( bcount + * elen - lbcount ) > > blocksize_bits ;
2005-04-17 02:20:36 +04:00
return etype ;
}
2007-05-08 11:35:13 +04:00
long udf_block_map ( struct inode * inode , sector_t block )
2005-04-17 02:20:36 +04:00
{
2007-05-08 11:35:14 +04:00
kernel_lb_addr eloc ;
uint32_t elen ;
2007-05-08 11:35:13 +04:00
sector_t offset ;
2007-07-21 15:37:18 +04:00
struct extent_position epos = { } ;
2005-04-17 02:20:36 +04:00
int ret ;
lock_kernel ( ) ;
2008-02-08 15:20:36 +03:00
if ( inode_bmap ( inode , block , & epos , & eloc , & elen , & offset ) = =
( EXT_RECORDED_ALLOCATED > > 30 ) )
2007-05-08 11:35:13 +04:00
ret = udf_get_lb_pblock ( inode - > i_sb , eloc , offset ) ;
2005-04-17 02:20:36 +04:00
else
ret = 0 ;
unlock_kernel ( ) ;
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
if ( UDF_QUERY_FLAG ( inode - > i_sb , UDF_FLAG_VARCONV ) )
return udf_fixed_to_variable ( ret ) ;
else
return ret ;
}