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/module.h>
# include <linux/pagemap.h>
# include <linux/buffer_head.h>
# include <linux/writeback.h>
# include <linux/slab.h>
2008-04-17 11:47:48 +04:00
# include <linux/crc-itu-t.h>
2011-10-03 09:02:59 +04:00
# include <linux/mpage.h>
2013-05-08 03:19:08 +04:00
# include <linux/aio.h>
2005-04-17 02:20:36 +04:00
# 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
2011-07-26 11:18:29 +04:00
static umode_t udf_convert_permissions ( struct fileEntry * ) ;
2005-04-17 02:20:36 +04:00
static int udf_update_inode ( struct inode * , int ) ;
2010-10-20 19:42:44 +04:00
static int udf_sync_inode ( struct inode * inode ) ;
2007-07-16 10:39:47 +04:00
static int udf_alloc_i_data ( struct inode * inode , size_t size ) ;
2011-12-10 04:43:33 +04:00
static sector_t inode_getblk ( struct inode * , sector_t , int * , int * ) ;
2007-05-08 11:35:14 +04:00
static int8_t udf_insert_aext ( struct inode * , struct extent_position ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr , uint32_t ) ;
2005-04-17 02:20:36 +04:00
static void udf_split_extents ( struct inode * , int * , int , int ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad [ EXTENT_MERGE_SIZE ] , int * ) ;
2005-04-17 02:20:36 +04:00
static void udf_prealloc_extents ( struct inode * , int , int ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad [ EXTENT_MERGE_SIZE ] , int * ) ;
2005-04-17 02:20:36 +04:00
static void udf_merge_extents ( struct inode * ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad [ EXTENT_MERGE_SIZE ] , int * ) ;
2005-04-17 02:20:36 +04:00
static void udf_update_extents ( struct inode * ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad [ EXTENT_MERGE_SIZE ] , int , int ,
2007-07-19 12:47:43 +04:00
struct extent_position * ) ;
2005-04-17 02:20:36 +04:00
static int udf_get_block ( struct inode * , sector_t , struct buffer_head * , int ) ;
2013-01-19 06:17:14 +04:00
static void __udf_clear_extent_cache ( struct inode * inode )
{
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
if ( iinfo - > cached_extent . lstart ! = - 1 ) {
brelse ( iinfo - > cached_extent . epos . bh ) ;
iinfo - > cached_extent . lstart = - 1 ;
}
}
/* Invalidate extent cache */
static void udf_clear_extent_cache ( struct inode * inode )
{
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
spin_lock ( & iinfo - > i_extent_cache_lock ) ;
__udf_clear_extent_cache ( inode ) ;
spin_unlock ( & iinfo - > i_extent_cache_lock ) ;
}
/* Return contents of extent cache */
static int udf_read_extent_cache ( struct inode * inode , loff_t bcount ,
loff_t * lbcount , struct extent_position * pos )
{
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
int ret = 0 ;
spin_lock ( & iinfo - > i_extent_cache_lock ) ;
if ( ( iinfo - > cached_extent . lstart < = bcount ) & &
( iinfo - > cached_extent . lstart ! = - 1 ) ) {
/* Cache hit */
* lbcount = iinfo - > cached_extent . lstart ;
memcpy ( pos , & iinfo - > cached_extent . epos ,
sizeof ( struct extent_position ) ) ;
if ( pos - > bh )
get_bh ( pos - > bh ) ;
ret = 1 ;
}
spin_unlock ( & iinfo - > i_extent_cache_lock ) ;
return ret ;
}
/* Add extent to extent cache */
static void udf_update_extent_cache ( struct inode * inode , loff_t estart ,
struct extent_position * pos , int next_epos )
{
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
spin_lock ( & iinfo - > i_extent_cache_lock ) ;
/* Invalidate previously cached extent */
__udf_clear_extent_cache ( inode ) ;
if ( pos - > bh )
get_bh ( pos - > bh ) ;
memcpy ( & iinfo - > cached_extent . epos , pos ,
sizeof ( struct extent_position ) ) ;
iinfo - > cached_extent . lstart = estart ;
if ( next_epos )
switch ( iinfo - > i_alloc_type ) {
case ICBTAG_FLAG_AD_SHORT :
iinfo - > cached_extent . epos . offset - =
sizeof ( struct short_ad ) ;
break ;
case ICBTAG_FLAG_AD_LONG :
iinfo - > cached_extent . epos . offset - =
sizeof ( struct long_ad ) ;
}
spin_unlock ( & iinfo - > i_extent_cache_lock ) ;
}
2008-02-22 14:38:48 +03:00
2010-06-07 08:43:39 +04:00
void udf_evict_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2009-12-03 15:39:28 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2010-06-07 08:43:39 +04:00
int want_delete = 0 ;
if ( ! inode - > i_nlink & & ! is_bad_inode ( inode ) ) {
want_delete = 1 ;
2010-10-22 02:30:26 +04:00
udf_setsize ( inode , 0 ) ;
2010-06-07 08:43:39 +04:00
udf_update_inode ( inode , IS_SYNC ( inode ) ) ;
2014-04-04 01:47:49 +04:00
}
truncate_inode_pages_final ( & inode - > i_data ) ;
2010-06-07 08:43:39 +04:00
invalidate_inode_buffers ( inode ) ;
2012-05-03 16:48:02 +04:00
clear_inode ( inode ) ;
2009-12-03 15:39:28 +03:00
if ( iinfo - > i_alloc_type ! = ICBTAG_FLAG_AD_IN_ICB & &
inode - > i_size ! = iinfo - > i_lenExtents ) {
2011-10-10 12:08:05 +04:00
udf_warn ( inode - > i_sb , " Inode %lu (mode %o) has inode size %llu different from extent length %llu. Filesystem need not be standards compliant. \n " ,
inode - > i_ino , inode - > i_mode ,
( unsigned long long ) inode - > i_size ,
( unsigned long long ) iinfo - > i_lenExtents ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:44 +03:00
kfree ( iinfo - > i_ext . i_data ) ;
iinfo - > i_ext . i_data = NULL ;
2013-01-19 06:17:14 +04:00
udf_clear_extent_cache ( inode ) ;
2010-06-07 08:43:39 +04:00
if ( want_delete ) {
udf_free_inode ( inode ) ;
}
2005-04-17 02:20:36 +04:00
}
2012-09-05 20:44:31 +04:00
static void udf_write_failed ( struct address_space * mapping , loff_t to )
{
struct inode * inode = mapping - > host ;
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
loff_t isize = inode - > i_size ;
if ( to > isize ) {
2013-09-13 02:13:56 +04:00
truncate_pagecache ( inode , isize ) ;
2012-09-05 20:44:31 +04:00
if ( iinfo - > i_alloc_type ! = ICBTAG_FLAG_AD_IN_ICB ) {
down_write ( & iinfo - > i_data_sem ) ;
2013-01-19 06:17:14 +04:00
udf_clear_extent_cache ( inode ) ;
2012-09-05 20:44:31 +04:00
udf_truncate_extents ( inode ) ;
up_write ( & iinfo - > i_data_sem ) ;
}
}
}
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 ) ;
}
2012-08-31 20:49:07 +04:00
static int udf_writepages ( struct address_space * mapping ,
struct writeback_control * wbc )
{
return mpage_writepages ( mapping , wbc , udf_get_block ) ;
}
2005-04-17 02:20:36 +04:00
static int udf_readpage ( struct file * file , struct page * page )
{
2011-10-03 09:02:59 +04:00
return mpage_readpage ( page , udf_get_block ) ;
}
static int udf_readpages ( struct file * file , struct address_space * mapping ,
struct list_head * pages , unsigned nr_pages )
{
return mpage_readpages ( mapping , pages , nr_pages , udf_get_block ) ;
2005-04-17 02:20:36 +04:00
}
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
{
2010-06-04 13:29:58 +04:00
int ret ;
ret = block_write_begin ( mapping , pos , len , flags , pagep , udf_get_block ) ;
2012-09-05 20:44:31 +04:00
if ( unlikely ( ret ) )
udf_write_failed ( mapping , pos + len ) ;
return ret ;
}
2010-06-04 13:29:58 +04:00
2012-09-05 20:44:31 +04:00
static ssize_t udf_direct_IO ( int rw , struct kiocb * iocb ,
2014-03-05 06:27:34 +04:00
struct iov_iter * iter ,
loff_t offset )
2012-09-05 20:44:31 +04:00
{
struct file * file = iocb - > ki_filp ;
struct address_space * mapping = file - > f_mapping ;
struct inode * inode = mapping - > host ;
2014-03-05 07:38:00 +04:00
size_t count = iov_iter_count ( iter ) ;
2012-09-05 20:44:31 +04:00
ssize_t ret ;
2014-03-05 10:33:16 +04:00
ret = blockdev_direct_IO ( rw , iocb , inode , iter , offset , udf_get_block ) ;
2012-09-05 20:44:31 +04:00
if ( unlikely ( ret < 0 & & ( rw & WRITE ) ) )
2014-03-05 07:38:00 +04:00
udf_write_failed ( mapping , offset + count ) ;
2010-06-04 13:29:58 +04:00
return ret ;
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 ,
2011-10-03 09:02:59 +04:00
. readpages = udf_readpages ,
2007-07-21 15:37:18 +04:00
. writepage = udf_writepage ,
2012-08-31 20:49:07 +04:00
. writepages = udf_writepages ,
2012-09-05 20:44:31 +04:00
. write_begin = udf_write_begin ,
. write_end = generic_write_end ,
. direct_IO = udf_direct_IO ,
2007-07-21 15:37:18 +04:00
. bmap = udf_bmap ,
2005-04-17 02:20:36 +04:00
} ;
2011-12-10 05:30:48 +04:00
/*
* Expand file stored in ICB to a normal one - block - file
*
* This function requires i_data_sem for writing and releases it .
* This function requires i_mutex held
*/
2010-10-22 02:30:26 +04:00
int udf_expand_file_adinicb ( struct inode * inode )
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 ) ;
2010-10-22 02:30:26 +04:00
int err ;
2005-04-17 02:20:36 +04:00
struct writeback_control udf_wbc = {
. sync_mode = WB_SYNC_NONE ,
. nr_to_write = 1 ,
} ;
2014-02-18 15:00:21 +04:00
WARN_ON_ONCE ( ! mutex_is_locked ( & inode - > i_mutex ) ) ;
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 ;
2010-10-22 02:30:26 +04:00
/* from now on we have normal address_space methods */
inode - > i_data . a_ops = & udf_aops ;
2011-12-10 05:30:48 +04:00
up_write ( & iinfo - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( inode ) ;
2010-10-22 02:30:26 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2011-12-10 05:30:48 +04:00
/*
* Release i_data_sem so that we can lock a page - page lock ranks
* above i_data_sem . i_mutex still protects us against file changes .
*/
up_write ( & iinfo - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
2010-10-22 02:30:26 +04:00
page = find_or_create_page ( inode - > i_mapping , 0 , GFP_NOFS ) ;
if ( ! page )
return - ENOMEM ;
2005-05-01 19:59:01 +04:00
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 ) ;
}
2011-12-10 05:30:48 +04:00
down_write ( & iinfo - > i_data_sem ) ;
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 ;
2010-10-22 02:30:26 +04:00
/* from now on we have normal address_space methods */
inode - > i_data . a_ops = & udf_aops ;
2011-12-10 05:30:48 +04:00
up_write ( & iinfo - > i_data_sem ) ;
2010-10-22 02:30:26 +04:00
err = inode - > i_data . a_ops - > writepage ( page , & udf_wbc ) ;
if ( err ) {
/* Restore everything back so that we don't lose data... */
lock_page ( page ) ;
kaddr = kmap ( page ) ;
2011-12-10 05:30:48 +04:00
down_write ( & iinfo - > i_data_sem ) ;
2010-10-22 02:30:26 +04:00
memcpy ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr , kaddr ,
inode - > i_size ) ;
kunmap ( page ) ;
unlock_page ( page ) ;
iinfo - > i_alloc_type = ICBTAG_FLAG_AD_IN_ICB ;
inode - > i_data . a_ops = & udf_adinicb_aops ;
2011-12-10 05:30:48 +04:00
up_write ( & iinfo - > i_data_sem ) ;
2010-10-22 02:30:26 +04:00
}
2005-04-17 02:20:36 +04:00
page_cache_release ( page ) ;
mark_inode_dirty ( inode ) ;
2010-10-22 02:30:26 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
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 ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
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 ;
2008-02-08 15:20:50 +03:00
loff_t f_pos = udf_ext0_offset ( inode ) ;
int size = udf_ext0_offset ( inode ) + inode - > i_size ;
2005-04-17 02:20:36 +04:00
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 =
2008-02-08 15:20:50 +03:00
f_pos & ( inode - > i_sb - > s_blocksize - 1 ) ;
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 ;
2008-02-08 15:20:50 +03: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 ;
2009-12-03 15:39:28 +03:00
iinfo - > i_lenExtents = inode - > i_size ;
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 ) ;
2009-12-03 15:39:28 +03:00
udf_add_aext ( inode , & epos , & eloc , inode - > i_size , 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 ;
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 ;
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2010-11-16 20:40:47 +03:00
down_write ( & iinfo - > i_data_sem ) ;
2008-02-08 15:20:44 +03:00
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
}
2013-01-19 06:17:14 +04:00
udf_clear_extent_cache ( inode ) ;
2011-12-10 04:43:33 +04:00
phys = inode_getblk ( inode , block , & err , & new ) ;
if ( ! phys )
2005-04-17 02:20:36 +04:00
goto abort ;
if ( new )
set_buffer_new ( bh_result ) ;
map_bh ( bh_result , inode - > i_sb , phys ) ;
2007-07-21 15:37:18 +04:00
abort :
2010-11-16 20:40:47 +03:00
up_write ( & iinfo - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
return err ;
}
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 */
2010-10-22 02:30:26 +04:00
static int udf_do_extend_file ( struct inode * inode ,
struct extent_position * last_pos ,
struct 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 ;
2008-10-15 14:28:03 +04:00
struct 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 ;
2010-10-22 02:30:26 +04:00
int err ;
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 ) {
2008-10-15 14:29:03 +04:00
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
2008-10-15 14:29:03 +04:00
udf_write_aext ( inode , last_pos , & last_ext - > extLocation ,
2008-02-08 15:20:36 +03:00
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 ;
2010-10-22 02:30:26 +04:00
err = udf_add_aext ( inode , last_pos , & last_ext - > extLocation ,
last_ext - > extLength , 1 ) ;
if ( err )
return err ;
2007-05-08 11:35:21 +04:00
count + + ;
}
if ( blocks ) {
last_ext - > extLength = EXT_NOT_RECORDED_NOT_ALLOCATED |
2007-07-21 15:37:18 +04:00
( blocks < < sb - > s_blocksize_bits ) ;
2010-10-22 02:30:26 +04:00
err = udf_add_aext ( inode , last_pos , & last_ext - > extLocation ,
last_ext - > extLength , 1 ) ;
if ( err )
return err ;
2007-05-08 11:35:21 +04:00
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 ) {
2010-10-22 02:30:26 +04:00
err = udf_add_aext ( inode , last_pos , & prealloc_loc ,
prealloc_len , 1 ) ;
if ( err )
return err ;
2007-05-08 11:35:21 +04:00
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 )
2008-10-15 14:28:03 +04:00
last_pos - > offset - = sizeof ( struct short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2008-10-15 14:28:03 +04:00
last_pos - > offset - = sizeof ( struct long_ad ) ;
2007-05-08 11:35:21 +04:00
else
2010-10-22 02:30:26 +04:00
return - EIO ;
2007-07-21 15:37:18 +04:00
2007-05-08 11:35:21 +04:00
return count ;
}
2010-10-22 02:30:26 +04:00
static int udf_extend_file ( struct inode * inode , loff_t newsize )
{
struct extent_position epos ;
struct kernel_lb_addr eloc ;
uint32_t elen ;
int8_t etype ;
struct super_block * sb = inode - > i_sb ;
sector_t first_block = newsize > > sb - > s_blocksize_bits , offset ;
int adsize ;
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
struct kernel_long_ad extent ;
int err ;
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
adsize = sizeof ( struct short_ad ) ;
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
adsize = sizeof ( struct long_ad ) ;
else
BUG ( ) ;
etype = inode_bmap ( inode , first_block , & epos , & eloc , & elen , & offset ) ;
/* File has extent covering the new size (could happen when extending
* inside a block ) ? */
if ( etype ! = - 1 )
return 0 ;
if ( newsize & ( sb - > s_blocksize - 1 ) )
offset + + ;
/* Extended file just to the boundary of the last file block? */
if ( offset = = 0 )
return 0 ;
/* Truncate is extending the file by 'offset' blocks */
if ( ( ! epos . bh & & epos . offset = = udf_file_entry_alloc_offset ( inode ) ) | |
( epos . bh & & epos . offset = = sizeof ( struct allocExtDesc ) ) ) {
/* File has no extents at all or has empty last
* indirect extent ! Create a fake extent . . . */
extent . extLocation . logicalBlockNum = 0 ;
extent . extLocation . partitionReferenceNum = 0 ;
extent . extLength = EXT_NOT_RECORDED_NOT_ALLOCATED ;
} else {
epos . offset - = adsize ;
etype = udf_next_aext ( inode , & epos , & extent . extLocation ,
& extent . extLength , 0 ) ;
extent . extLength | = etype < < 30 ;
}
err = udf_do_extend_file ( inode , & epos , & extent , offset ) ;
if ( err < 0 )
goto out ;
err = 0 ;
iinfo - > i_lenExtents = newsize ;
out :
brelse ( epos . bh ) ;
return err ;
}
2011-12-10 04:43:33 +04:00
static sector_t inode_getblk ( struct inode * inode , sector_t block ,
int * err , int * new )
2005-04-17 02:20:36 +04:00
{
2008-10-15 14:28:03 +04:00
struct 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 ;
2008-10-15 14:28:03 +04:00
struct 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 ;
2012-10-09 19:09:12 +04:00
bool isBeyondEOF ;
2005-04-17 02:20:36 +04:00
2011-12-10 04:43:33 +04:00
* err = 0 ;
* new = 0 ;
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 ) ) ;
2010-10-22 02:30:26 +04:00
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 ) ;
2008-10-15 14:29:03 +04:00
newblock = udf_get_lb_pblock ( inode - > i_sb , & eloc , offset ) ;
2011-12-10 04:43:33 +04:00
return newblock ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:35:21 +04:00
/* 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 ;
2012-10-09 19:09:12 +04:00
isBeyondEOF = 1 ;
2007-05-08 11:35:21 +04:00
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 ,
2008-10-15 14:28:03 +04:00
sizeof ( struct kernel_lb_addr ) ) ;
2007-05-08 11:35:21 +04:00
laarr [ 0 ] . extLength = EXT_NOT_RECORDED_NOT_ALLOCATED ;
2010-10-22 02:30:26 +04:00
/* Will udf_do_extend_file() create real extent from
2008-02-08 15:20:36 +03:00
a fake one ? */
2007-05-08 11:35:21 +04:00
startnum = ( offset > 0 ) ;
}
/* Create extents for the hole between EOF and offset */
2010-10-22 02:30:26 +04:00
ret = udf_do_extend_file ( inode , & prev_epos , laarr , offset ) ;
if ( ret < 0 ) {
2007-05-08 11:35:21 +04:00
brelse ( prev_epos . bh ) ;
brelse ( cur_epos . bh ) ;
brelse ( next_epos . bh ) ;
2010-10-22 02:30:26 +04:00
* err = ret ;
2011-12-10 04:43:33 +04:00
return 0 ;
2007-05-08 11:35:21 +04:00
}
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 ,
2008-10-15 14:28:03 +04:00
sizeof ( struct kernel_lb_addr ) ) ;
2007-07-19 12:47:43 +04:00
count + + ;
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 {
2012-10-09 19:09:12 +04:00
isBeyondEOF = 0 ;
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 ) ;
2012-10-09 19:08:56 +04:00
brelse ( cur_epos . bh ) ;
brelse ( next_epos . bh ) ;
2005-04-17 02:20:36 +04:00
* err = - ENOSPC ;
2011-12-10 04:43:33 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2012-10-09 19:09:12 +04:00
if ( isBeyondEOF )
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
2009-07-16 20:02:25 +04:00
/* We preallocate blocks only for regular files. It also makes sense
* for directories but there ' s a problem when to drop the
* preallocation . We might use some delayed work for that but I feel
* it ' s overengineering for a filesystem like UDF . */
if ( S_ISREG ( inode - > i_mode ) )
udf_prealloc_extents ( inode , c , lastblock , laarr , & endnum ) ;
2005-04-17 02:20:36 +04:00
# 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 ) ;
2012-10-09 19:08:56 +04:00
brelse ( cur_epos . bh ) ;
brelse ( next_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 ) ;
2011-12-10 04:43:33 +04:00
if ( ! newblock ) {
* err = - EIO ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
* 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
2011-12-10 04:43:33 +04:00
return newblock ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
static void udf_split_extents ( struct inode * inode , int * c , int offset ,
int newblocknum ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
2007-07-19 12:47:43 +04:00
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 ,
2008-10-15 14:29:03 +04:00
& laarr [ curr ] . extLocation ,
2008-02-08 15:20:36 +03:00
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 ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
2007-07-19 12:47:43 +04:00
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 ] ,
2008-10-15 14:28:03 +04:00
sizeof ( struct long_ad ) * ( * endnum - ( c + 1 ) ) ) ;
2007-07-19 12:47:43 +04:00
( * 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 ] ,
2008-10-15 14:28:03 +04:00
sizeof ( struct long_ad ) *
2008-02-08 15:20:36 +03:00
( * 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 ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
2007-07-19 12:47:43 +04:00
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-10-15 14:28:03 +04:00
struct kernel_long_ad * li /*l[i]*/ = & laarr [ i ] ;
struct kernel_long_ad * lip1 /*l[i plus 1]*/ = & laarr [ i + 1 ] ;
2008-02-08 15:20:36 +03:00
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 ] ,
2008-10-15 14:28:03 +04:00
sizeof ( struct long_ad ) *
2008-02-08 15:20:36 +03:00
( * 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 ) ) ) {
2008-10-15 14:29:03 +04:00
udf_free_blocks ( inode - > i_sb , inode , & li - > extLocation , 0 ,
2008-02-08 15:20:36 +03:00
( ( 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-10-15 14:28:03 +04:00
sizeof ( struct long_ad ) *
2008-02-08 15:20:36 +03:00
( * 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 ,
2008-10-15 14:29:03 +04:00
& li - > extLocation , 0 ,
2008-02-08 15:20:36 +03:00
( ( 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 ,
2008-10-15 14:28:03 +04:00
struct kernel_long_ad laarr [ EXTENT_MERGE_SIZE ] ,
2007-07-19 12:47:43 +04:00
int startnum , int endnum ,
struct extent_position * epos )
2005-04-17 02:20:36 +04:00
{
int start = 0 , i ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr tmploc ;
2005-04-17 02:20:36 +04:00
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 ) ;
2008-10-15 14:29:03 +04:00
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 ;
}
2010-10-22 02:30:26 +04:00
int udf_setsize ( struct inode * inode , loff_t newsize )
2005-04-17 02:20:36 +04:00
{
int err ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2010-10-22 02:30:26 +04:00
int bsize = 1 < < inode - > i_blkbits ;
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 ) ) )
2010-10-22 02:30:26 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( IS_APPEND ( inode ) | | IS_IMMUTABLE ( inode ) )
2010-10-22 02:30:26 +04:00
return - EPERM ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2010-10-22 02:30:26 +04:00
if ( newsize > inode - > i_size ) {
2010-11-16 20:40:47 +03:00
down_write ( & iinfo - > i_data_sem ) ;
2010-10-22 02:30:26 +04:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
if ( bsize <
( udf_file_entry_alloc_offset ( inode ) + newsize ) ) {
err = udf_expand_file_adinicb ( inode ) ;
2011-12-10 05:30:48 +04:00
if ( err )
2010-10-22 02:30:26 +04:00
return err ;
2011-12-10 05:30:48 +04:00
down_write ( & iinfo - > i_data_sem ) ;
2012-07-23 20:39:29 +04:00
} else {
2010-10-22 02:30:26 +04:00
iinfo - > i_lenAlloc = newsize ;
2012-07-23 20:39:29 +04:00
goto set_size ;
}
2010-10-22 02:30:26 +04:00
}
err = udf_extend_file ( inode , newsize ) ;
if ( err ) {
up_write ( & iinfo - > i_data_sem ) ;
return err ;
2005-04-17 02:20:36 +04:00
}
2012-07-23 20:39:29 +04:00
set_size :
2010-10-22 02:30:26 +04:00
truncate_setsize ( inode , newsize ) ;
2010-11-16 20:40:47 +03:00
up_write ( & iinfo - > i_data_sem ) ;
2007-07-19 12:47:43 +04:00
} else {
2010-10-22 02:30:26 +04:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
down_write ( & iinfo - > i_data_sem ) ;
2013-01-19 06:17:14 +04:00
udf_clear_extent_cache ( inode ) ;
2010-10-22 02:30:26 +04:00
memset ( iinfo - > i_ext . i_data + iinfo - > i_lenEAttr + newsize ,
0x00 , bsize - newsize -
udf_file_entry_alloc_offset ( inode ) ) ;
iinfo - > i_lenAlloc = newsize ;
truncate_setsize ( inode , newsize ) ;
up_write ( & iinfo - > i_data_sem ) ;
goto update_time ;
}
err = block_truncate_page ( inode - > i_mapping , newsize ,
udf_get_block ) ;
if ( err )
return err ;
2010-11-16 20:40:47 +03:00
down_write ( & iinfo - > i_data_sem ) ;
2013-01-19 06:17:14 +04:00
udf_clear_extent_cache ( inode ) ;
2010-10-22 02:30:26 +04:00
truncate_setsize ( inode , newsize ) ;
2005-04-17 02:20:36 +04:00
udf_truncate_extents ( inode ) ;
2010-11-16 20:40:47 +03:00
up_write ( & iinfo - > i_data_sem ) ;
2007-07-16 10:39:47 +04:00
}
2010-10-22 02:30:26 +04:00
update_time :
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 ) ;
2010-10-22 02:30:26 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2014-09-04 16:06:55 +04:00
/*
* Maximum length of linked list formed by ICB hierarchy . The chosen number is
* arbitrary - just that we hopefully don ' t limit any real use of rewritten
* inode on write - once media but avoid looping for too long on corrupted media .
*/
# define UDF_MAX_ICB_NESTING 1024
2014-09-04 18:15:51 +04:00
static int udf_read_inode ( struct inode * inode )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
struct fileEntry * fe ;
2014-09-04 15:32:50 +04:00
struct extendedFileEntry * efe ;
2005-04-17 02:20:36 +04:00
uint16_t ident ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( inode ) ;
2014-09-04 15:32:50 +04:00
struct udf_sb_info * sbi = UDF_SB ( inode - > i_sb ) ;
2014-09-04 18:15:51 +04:00
struct kernel_lb_addr * iloc = & iinfo - > i_location ;
2014-09-04 15:32:50 +04:00
unsigned int link_count ;
2014-09-04 16:06:55 +04:00
unsigned int indirections = 0 ;
2014-09-04 18:15:51 +04:00
int ret = - EIO ;
2005-04-17 02:20:36 +04:00
2014-09-04 16:06:55 +04:00
reread :
2014-09-04 18:15:51 +04:00
if ( iloc - > logicalBlockNum > =
sbi - > s_partmaps [ iloc - > partitionReferenceNum ] . s_partition_len ) {
udf_debug ( " block=%d, partition=%d out of range \n " ,
iloc - > logicalBlockNum , iloc - > partitionReferenceNum ) ;
return - EIO ;
}
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 ;
*/
2014-09-04 18:15:51 +04:00
bh = udf_read_ptagged ( inode - > i_sb , iloc , 0 , & ident ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2011-10-10 12:08:05 +04:00
udf_err ( inode - > i_sb , " (ino %ld) failed !bh \n " , inode - > i_ino ) ;
2014-09-04 18:15:51 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
if ( ident ! = TAG_IDENT_FE & & ident ! = TAG_IDENT_EFE & &
2007-07-19 12:47:43 +04:00
ident ! = TAG_IDENT_USE ) {
2011-10-10 12:08:05 +04:00
udf_err ( inode - > i_sb , " (ino %ld) failed ident=%d \n " ,
inode - > i_ino , ident ) ;
2014-09-04 18:15:51 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
fe = ( struct fileEntry * ) bh - > b_data ;
2014-09-04 15:32:50 +04:00
efe = ( struct extendedFileEntry * ) bh - > b_data ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:41 +03:00
if ( fe - > icbTag . strategyType = = cpu_to_le16 ( 4096 ) ) {
2008-01-31 00:03:58 +03:00
struct buffer_head * ibh ;
2005-04-17 02:20:36 +04:00
2014-09-04 18:15:51 +04:00
ibh = udf_read_ptagged ( inode - > i_sb , iloc , 1 , & ident ) ;
2008-01-31 00:03:58 +03:00
if ( ident = = TAG_IDENT_IE & & ibh ) {
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr loc ;
2008-01-31 00:03:58 +03:00
struct indirectEntry * ie ;
ie = ( struct indirectEntry * ) ibh - > b_data ;
loc = lelb_to_cpu ( ie - > indirectICB . extLocation ) ;
2014-09-04 16:06:55 +04:00
if ( ie - > indirectICB . extLength ) {
brelse ( ibh ) ;
memcpy ( & iinfo - > i_location , & loc ,
sizeof ( struct kernel_lb_addr ) ) ;
if ( + + indirections > UDF_MAX_ICB_NESTING ) {
udf_err ( inode - > i_sb ,
" too many ICBs in ICB hierarchy "
" (max %d supported) \n " ,
UDF_MAX_ICB_NESTING ) ;
2014-09-04 18:15:51 +04:00
goto out ;
2007-07-21 15:37:18 +04:00
}
2014-09-04 18:15:51 +04:00
brelse ( bh ) ;
2014-09-04 16:06:55 +04:00
goto reread ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
}
2008-01-31 00:03:58 +03:00
brelse ( ibh ) ;
2008-02-08 15:20:41 +03:00
} else if ( fe - > icbTag . strategyType ! = cpu_to_le16 ( 4 ) ) {
2011-10-10 12:08:05 +04:00
udf_err ( inode - > i_sb , " unsupported strategy type: %d \n " ,
le16_to_cpu ( fe - > icbTag . strategyType ) ) ;
2014-09-04 18:15:51 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
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 ;
2014-09-04 18:15:51 +04:00
ret = udf_alloc_i_data ( inode , inode - > i_sb - > s_blocksize -
sizeof ( struct extendedFileEntry ) ) ;
if ( ret )
goto out ;
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 ;
2014-09-04 18:15:51 +04:00
ret = udf_alloc_i_data ( inode , inode - > i_sb - > s_blocksize -
sizeof ( struct fileEntry ) ) ;
if ( ret )
goto out ;
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 ) ;
2014-09-04 18:15:51 +04:00
ret = udf_alloc_i_data ( inode , inode - > i_sb - > s_blocksize -
sizeof ( struct unallocSpaceEntry ) ) ;
if ( ret )
goto out ;
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 ) ) ;
2014-09-04 18:15:51 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2014-09-04 18:15:51 +04:00
ret = - EIO ;
2010-10-21 00:17:28 +04:00
read_lock ( & sbi - > s_cred_lock ) ;
2012-02-11 00:20:35 +04:00
i_uid_write ( inode , le32_to_cpu ( fe - > uid ) ) ;
if ( ! uid_valid ( inode - > i_uid ) | |
2007-07-31 11:39:40 +04:00
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
2012-02-11 00:20:35 +04:00
i_gid_write ( inode , le32_to_cpu ( fe - > gid ) ) ;
if ( ! gid_valid ( inode - > i_gid ) | |
2007-07-31 11:39:40 +04:00
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
2008-11-16 22:52:19 +03:00
if ( fe - > icbTag . fileType ! = ICBTAG_FILE_TYPE_DIRECTORY & &
2008-12-02 15:40:11 +03:00
sbi - > s_fmode ! = UDF_INVALID_MODE )
2008-11-16 22:52:19 +03:00
inode - > i_mode = sbi - > s_fmode ;
else if ( fe - > icbTag . fileType = = ICBTAG_FILE_TYPE_DIRECTORY & &
2008-12-02 15:40:11 +03:00
sbi - > s_dmode ! = UDF_INVALID_MODE )
2008-11-16 22:52:19 +03:00
inode - > i_mode = sbi - > s_dmode ;
else
inode - > i_mode = udf_convert_permissions ( fe ) ;
inode - > i_mode & = ~ sbi - > s_umask ;
2010-10-21 00:17:28 +04:00
read_unlock ( & sbi - > s_cred_lock ) ;
2011-10-28 16:13:29 +04:00
link_count = le16_to_cpu ( fe - > fileLinkCount ) ;
if ( ! link_count )
link_count = 1 ;
set_nlink ( inode , link_count ) ;
2010-10-21 00:17:28 +04:00
inode - > i_size = le64_to_cpu ( fe - > informationLength ) ;
iinfo - > i_lenExtents = inode - > i_size ;
2005-04-17 02:20:36 +04:00
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
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & inode - > i_atime , fe - > accessTime ) )
2008-02-28 00:50:14 +03:00
inode - > i_atime = sbi - > s_record_time ;
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & inode - > i_mtime ,
fe - > modificationTime ) )
2008-02-28 00:50:14 +03:00
inode - > i_mtime = sbi - > s_record_time ;
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & inode - > i_ctime , fe - > attrTime ) )
2008-02-28 00:50:14 +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 ) ;
2012-02-14 09:28:42 +04:00
iinfo - > i_checkpoint = le32_to_cpu ( fe - > checkpoint ) ;
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
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & inode - > i_atime , efe - > accessTime ) )
2008-02-28 00:50:14 +03:00
inode - > i_atime = sbi - > s_record_time ;
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & inode - > i_mtime ,
efe - > modificationTime ) )
2008-02-28 00:50:14 +03:00
inode - > i_mtime = sbi - > s_record_time ;
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & iinfo - > i_crtime , efe - > createTime ) )
2008-02-28 00:50:14 +03:00
iinfo - > i_crtime = sbi - > s_record_time ;
2008-02-10 13:25:31 +03:00
if ( ! udf_disk_stamp_to_time ( & inode - > i_ctime , efe - > attrTime ) )
2008-02-28 00:50:14 +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 ) ;
2012-02-14 09:28:42 +04:00
iinfo - > i_checkpoint = le32_to_cpu ( efe - > checkpoint ) ;
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-04-08 03:17:52 +04:00
case ICBTAG_FILE_TYPE_VAT20 :
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 ;
2010-03-29 11:05:21 +04:00
inode - > i_op = & udf_symlink_inode_operations ;
2007-07-21 15:37:18 +04:00
inode - > i_mode = S_IFLNK | S_IRWXUGO ;
break ;
2008-04-08 22:37:21 +04:00
case ICBTAG_FILE_TYPE_MAIN :
udf_debug ( " METADATA FILE----- \n " ) ;
break ;
case ICBTAG_FILE_TYPE_MIRROR :
udf_debug ( " METADATA MIRROR FILE----- \n " ) ;
break ;
case ICBTAG_FILE_TYPE_BITMAP :
udf_debug ( " METADATA BITMAP FILE----- \n " ) ;
break ;
2007-07-19 12:47:43 +04:00
default :
2011-10-10 12:08:05 +04:00
udf_err ( inode - > i_sb , " (ino %ld) failed unknown file type=%d \n " ,
inode - > i_ino , fe - > icbTag . fileType ) ;
2014-09-04 18:15:51 +04:00
goto out ;
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
2014-09-04 18:15:51 +04:00
goto out ;
2005-04-17 02:20:36 +04:00
}
2014-09-04 18:15:51 +04:00
ret = 0 ;
out :
2014-09-04 15:32:50 +04:00
brelse ( bh ) ;
2014-09-04 18:15:51 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
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 ) {
2011-10-10 12:08:05 +04:00
udf_err ( inode - > i_sb , " (ino %ld) no free memory \n " ,
inode - > i_ino ) ;
2007-07-16 10:39:47 +04:00
return - ENOMEM ;
}
return 0 ;
}
2011-07-26 11:18:29 +04:00
static umode_t udf_convert_permissions ( struct fileEntry * fe )
2005-04-17 02:20:36 +04:00
{
2011-07-26 11:18:29 +04:00
umode_t mode ;
2005-04-17 02:20:36 +04:00
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 ;
}
2010-03-05 11:21:37 +03:00
int udf_write_inode ( struct inode * inode , struct writeback_control * wbc )
2005-04-17 02:20:36 +04:00
{
2010-10-20 19:42:44 +04:00
return udf_update_inode ( inode , wbc - > sync_mode = = WB_SYNC_ALL ) ;
2005-04-17 02:20:36 +04:00
}
2010-10-20 19:42:44 +04:00
static 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 ;
2012-02-16 21:53:53 +04:00
uint64_t lb_recorded ;
2005-04-17 02:20:36 +04:00
uint32_t udfperms ;
uint16_t icbflags ;
uint16_t crclen ;
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
2010-01-08 18:52:59 +03:00
bh = udf_tgetblk ( inode - > i_sb ,
udf_get_lb_pblock ( inode - > i_sb , & iinfo - > i_location , 0 ) ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2010-01-08 18:46:29 +03:00
udf_debug ( " getblk failure \n " ) ;
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2010-01-08 18:46:29 +03:00
lock_buffer ( bh ) ;
memset ( bh - > b_data , 0 , inode - > i_sb - > s_blocksize ) ;
2005-04-17 02:20:36 +04:00
fe = ( struct fileEntry * ) bh - > b_data ;
efe = ( struct extendedFileEntry * ) bh - > b_data ;
2010-01-08 18:46:29 +03:00
if ( iinfo - > i_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 ) ) ;
2010-01-08 18:46:29 +03:00
use - > descTag . tagIdent = cpu_to_le16 ( TAG_IDENT_USE ) ;
use - > descTag . tagLocation =
cpu_to_le32 ( iinfo - > i_location . logicalBlockNum ) ;
2008-02-08 15:20:36 +03:00
crclen = sizeof ( struct unallocSpaceEntry ) +
2008-10-15 14:28:03 +04:00
iinfo - > i_lenAlloc - sizeof ( struct tag ) ;
2005-04-17 02:20:36 +04:00
use - > descTag . descCRCLength = cpu_to_le16 ( crclen ) ;
2008-04-17 11:47:48 +04:00
use - > descTag . descCRC = cpu_to_le16 ( crc_itu_t ( 0 , ( char * ) use +
2008-10-15 14:28:03 +04:00
sizeof ( struct tag ) ,
2008-04-17 11:47:48 +04:00
crclen ) ) ;
2008-02-08 15:20:39 +03:00
use - > descTag . tagChecksum = udf_tag_checksum ( & use - > descTag ) ;
2005-04-17 02:20:36 +04:00
2010-01-08 18:46:29 +03:00
goto out ;
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_UID_FORGET ) )
fe - > uid = cpu_to_le32 ( - 1 ) ;
2007-07-19 12:47:43 +04:00
else
2012-02-11 00:20:35 +04:00
fe - > uid = cpu_to_le32 ( i_uid_read ( inode ) ) ;
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
2012-02-11 00:20:35 +04:00
fe - > gid = cpu_to_le32 ( i_gid_read ( inode ) ) ;
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 ) ;
2014-09-04 13:47:51 +04:00
if ( S_ISDIR ( inode - > i_mode ) & & inode - > i_nlink > 0 )
2005-04-17 02:20:36 +04:00
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 ) ) {
2008-10-15 14:28:03 +04:00
struct 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 ) +
2008-10-15 14:28:03 +04:00
sizeof ( struct 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 ) +
2008-10-15 14:28:03 +04:00
sizeof ( struct regid ) ) ;
dsea - > impUseLength = cpu_to_le32 ( sizeof ( struct regid ) ) ;
2005-04-17 02:20:36 +04:00
}
2008-10-15 14:28:03 +04:00
eid = ( struct regid * ) dsea - > impUse ;
memset ( eid , 0 , sizeof ( struct regid ) ) ;
2005-04-17 02:20:36 +04:00
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 ) ) ;
}
2012-02-16 21:53:53 +04:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB )
lb_recorded = 0 ; /* No extents => no blocks! */
else
lb_recorded =
( inode - > i_blocks + ( 1 < < ( blocksize_bits - 9 ) ) - 1 ) > >
( blocksize_bits - 9 ) ;
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 ) ) ;
2012-02-16 21:53:53 +04:00
fe - > logicalBlocksRecorded = cpu_to_le64 ( lb_recorded ) ;
2005-04-17 02:20:36 +04:00
2008-02-10 13:25:31 +03:00
udf_time_to_disk_stamp ( & fe - > accessTime , inode - > i_atime ) ;
udf_time_to_disk_stamp ( & fe - > modificationTime , inode - > i_mtime ) ;
udf_time_to_disk_stamp ( & fe - > attrTime , inode - > i_ctime ) ;
2008-10-15 14:28:03 +04:00
memset ( & ( fe - > impIdent ) , 0 , sizeof ( struct regid ) ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2012-02-14 09:28:42 +04:00
fe - > checkpoint = cpu_to_le32 ( iinfo - > i_checkpoint ) ;
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 ) ;
2012-02-16 21:53:53 +04:00
efe - > logicalBlocksRecorded = cpu_to_le64 ( lb_recorded ) ;
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
2008-02-10 13:25:31 +03:00
udf_time_to_disk_stamp ( & efe - > accessTime , inode - > i_atime ) ;
udf_time_to_disk_stamp ( & efe - > modificationTime , inode - > i_mtime ) ;
udf_time_to_disk_stamp ( & efe - > createTime , iinfo - > i_crtime ) ;
udf_time_to_disk_stamp ( & efe - > attrTime , inode - > i_ctime ) ;
2005-04-17 02:20:36 +04:00
2008-10-15 14:28:03 +04:00
memset ( & ( efe - > impIdent ) , 0 , sizeof ( struct regid ) ) ;
2005-04-17 02:20:36 +04:00
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 ) ;
2012-02-14 09:28:42 +04:00
efe - > checkpoint = cpu_to_le32 ( iinfo - > i_checkpoint ) ;
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 ) ;
2010-01-08 18:46:29 +03:00
crclen + = iinfo - > i_lenEAttr + iinfo - > i_lenAlloc - sizeof ( struct tag ) ;
2005-04-17 02:20:36 +04:00
fe - > descTag . descCRCLength = cpu_to_le16 ( crclen ) ;
2008-10-15 14:28:03 +04:00
fe - > descTag . descCRC = cpu_to_le16 ( crc_itu_t ( 0 , ( char * ) fe + sizeof ( struct tag ) ,
2008-04-17 11:47:48 +04:00
crclen ) ) ;
2008-02-08 15:20:39 +03:00
fe - > descTag . tagChecksum = udf_tag_checksum ( & fe - > descTag ) ;
2005-04-17 02:20:36 +04:00
2010-01-08 18:46:29 +03:00
out :
2010-01-08 18:52:59 +03:00
set_buffer_uptodate ( bh ) ;
2010-01-08 18:46:29 +03:00
unlock_buffer ( bh ) ;
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 ) ;
2010-01-08 18:46:29 +03:00
if ( buffer_write_io_error ( bh ) ) {
2011-10-10 12:08:05 +04:00
udf_warn ( inode - > i_sb , " IO error syncing udf inode [%08lx] \n " ,
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 ;
}
2008-10-15 14:29:03 +04:00
struct inode * udf_iget ( struct super_block * sb , struct 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 ) ;
2014-09-04 18:15:51 +04:00
int err ;
2005-04-17 02:20:36 +04:00
if ( ! inode )
2014-09-04 18:15:51 +04:00
return ERR_PTR ( - ENOMEM ) ;
2005-04-17 02:20:36 +04:00
2014-09-04 18:15:51 +04:00
if ( ! ( inode - > i_state & I_NEW ) )
return inode ;
2005-04-17 02:20:36 +04:00
2014-09-04 18:15:51 +04:00
memcpy ( & UDF_I ( inode ) - > i_location , ino , sizeof ( struct kernel_lb_addr ) ) ;
err = udf_read_inode ( inode ) ;
if ( err < 0 ) {
iget_failed ( inode ) ;
return ERR_PTR ( err ) ;
2005-04-17 02:20:36 +04:00
}
2014-09-04 18:15:51 +04:00
unlock_new_inode ( inode ) ;
2005-04-17 02:20:36 +04:00
return inode ;
}
2010-10-22 02:30:26 +04:00
int udf_add_aext ( struct inode * inode , struct extent_position * epos ,
struct kernel_lb_addr * eloc , uint32_t elen , int inc )
2005-04-17 02:20:36 +04:00
{
int adsize ;
2008-10-15 14:28:03 +04:00
struct short_ad * sad = NULL ;
struct long_ad * lad = NULL ;
2005-04-17 02:20:36 +04:00
struct allocExtDesc * aed ;
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 )
2008-10-15 14:28:03 +04:00
adsize = sizeof ( struct short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2008-10-15 14:28:03 +04:00
adsize = sizeof ( struct long_ad ) ;
2005-04-17 02:20:36 +04:00
else
2010-10-22 02:30:26 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( epos - > offset + ( 2 * adsize ) > inode - > i_sb - > s_blocksize ) {
2010-02-01 05:28:48 +03:00
unsigned char * sptr , * dptr ;
2005-04-17 02:20:36 +04:00
struct buffer_head * nbh ;
int err , loffset ;
2008-10-15 14:28:03 +04:00
struct 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 )
2010-10-22 02:30:26 +04:00
return - ENOSPC ;
2008-02-08 15:20:36 +03:00
nbh = udf_tgetblk ( inode - > i_sb , udf_get_lb_pblock ( inode - > i_sb ,
2008-10-15 14:29:03 +04:00
& epos - > block ,
2008-02-08 15:20:36 +03:00
0 ) ) ;
if ( ! nbh )
2010-10-22 02:30:26 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
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 ;
2008-01-31 00:03:57 +03:00
le32_add_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 ,
2008-10-15 14:28:03 +04:00
epos - > block . logicalBlockNum , sizeof ( struct tag ) ) ;
2005-04-17 02:20:36 +04:00
else
udf_new_tag ( nbh - > b_data , TAG_IDENT_AED , 2 , 1 ,
2008-10-15 14:28:03 +04:00
epos - > block . logicalBlockNum , sizeof ( struct 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 :
2008-10-15 14:28:03 +04:00
sad = ( struct short_ad * ) sptr ;
2007-07-21 15:37:18 +04:00
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 :
2008-10-15 14:28:03 +04:00
lad = ( struct long_ad * ) sptr ;
2007-07-21 15:37:18 +04:00
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
}
2010-10-22 02:30:26 +04:00
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 ;
2008-01-31 00:03:57 +03:00
le32_add_cpu ( & aed - > lengthAllocDescs , adsize ) ;
2008-02-08 15:20:36 +03:00
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
}
2010-10-22 02:30:26 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2010-10-22 02:30:26 +04:00
void udf_write_aext ( struct inode * inode , struct extent_position * epos ,
struct kernel_lb_addr * eloc , uint32_t elen , int inc )
2005-04-17 02:20:36 +04:00
{
int adsize ;
uint8_t * ptr ;
2008-10-15 14:28:03 +04:00
struct short_ad * sad ;
struct 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 :
2008-10-15 14:28:03 +04:00
sad = ( struct short_ad * ) ptr ;
2007-07-21 15:37:18 +04:00
sad - > extLength = cpu_to_le32 ( elen ) ;
2008-10-15 14:29:03 +04:00
sad - > extPosition = cpu_to_le32 ( eloc - > logicalBlockNum ) ;
2008-10-15 14:28:03 +04:00
adsize = sizeof ( struct short_ad ) ;
2007-07-21 15:37:18 +04:00
break ;
2007-07-19 12:47:43 +04:00
case ICBTAG_FLAG_AD_LONG :
2008-10-15 14:28:03 +04:00
lad = ( struct long_ad * ) ptr ;
2007-07-21 15:37:18 +04:00
lad - > extLength = cpu_to_le32 ( elen ) ;
2008-10-15 14:29:03 +04:00
lad - > extLocation = cpu_to_lelb ( * eloc ) ;
2007-07-21 15:37:18 +04:00
memset ( lad - > impUse , 0x00 , sizeof ( lad - > impUse ) ) ;
2008-10-15 14:28:03 +04:00
adsize = sizeof ( struct long_ad ) ;
2007-07-21 15:37:18 +04:00
break ;
2007-07-19 12:47:43 +04:00
default :
2010-10-22 02:30:26 +04:00
return ;
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 ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
int8_t udf_next_aext ( struct inode * inode , struct extent_position * epos ,
2008-10-15 14:28:03 +04:00
struct 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-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( inode - > i_sb , & epos - > block , 0 ) ;
2008-02-08 15:20:36 +03:00
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 ,
2008-10-15 14:28:03 +04:00
struct 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 ;
2008-10-15 14:28:03 +04:00
struct short_ad * sad ;
struct 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 :
2011-10-10 12:08:07 +04:00
udf_debug ( " alloc_type = %d unsupported \n " , 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 ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr neloc , uint32_t nelen )
2005-04-17 02:20:36 +04:00
{
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr oeloc ;
2005-04-17 02:20:36 +04:00
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 ) {
2008-10-15 14:29:03 +04:00
udf_write_aext ( inode , & epos , & neloc , nelen , 1 ) ;
2005-04-17 02:20:36 +04:00
neloc = oeloc ;
nelen = ( etype < < 30 ) | oelen ;
}
2008-10-15 14:29:03 +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 ,
2008-10-15 14:28:03 +04:00
struct 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 )
2008-10-15 14:28:03 +04:00
adsize = sizeof ( struct short_ad ) ;
2008-02-08 15:20:44 +03:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2008-10-15 14:28:03 +04:00
adsize = sizeof ( struct long_ad ) ;
2005-04-17 02:20:36 +04:00
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 ) {
2008-10-15 14:29:03 +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
}
}
2008-10-15 14:28:03 +04:00
memset ( & eloc , 0x00 , sizeof ( struct kernel_lb_addr ) ) ;
2005-04-17 02:20:36 +04:00
elen = 0 ;
2007-07-19 12:47:43 +04:00
if ( epos . bh ! = oepos . bh ) {
2008-10-15 14:29:03 +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 ;
2008-01-31 00:03:57 +03:00
le32_add_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 {
2008-10-15 14:29:03 +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 ;
2008-01-31 00:03:57 +03:00
le32_add_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 ,
2008-10-15 14:28:03 +04:00
struct extent_position * pos , struct kernel_lb_addr * eloc ,
2008-02-08 15:20:36 +03:00
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
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( inode ) ;
2013-01-19 06:17:14 +04:00
if ( ! udf_read_extent_cache ( inode , bcount , & lbcount , pos ) ) {
pos - > offset = 0 ;
pos - > block = iinfo - > i_location ;
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 ) ;
2013-01-19 06:17:14 +04:00
/* update extent cache */
udf_update_extent_cache ( inode , lbcount - * elen , pos , 1 ) ;
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
{
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2007-05-08 11:35:14 +04:00
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 ;
2010-11-16 20:40:47 +03:00
down_read ( & UDF_I ( inode ) - > i_data_sem ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
if ( inode_bmap ( inode , block , & epos , & eloc , & elen , & offset ) = =
( EXT_RECORDED_ALLOCATED > > 30 ) )
2008-10-15 14:29:03 +04:00
ret = udf_get_lb_pblock ( inode - > i_sb , & eloc , offset ) ;
2005-04-17 02:20:36 +04:00
else
ret = 0 ;
2010-11-16 20:40:47 +03:00
up_read ( & UDF_I ( inode ) - > i_data_sem ) ;
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 ;
}