2005-04-17 02:20:36 +04:00
/*
* partition . c
*
* PURPOSE
* Partition 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 - 2001 Ben Fennema
*
* HISTORY
*
2007-07-21 15:37:18 +04:00
* 12 / 06 / 98 blf Created file .
2005-04-17 02:20:36 +04:00
*
*/
# include "udfdecl.h"
# include "udf_sb.h"
# include "udf_i.h"
# include <linux/fs.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/buffer_head.h>
2007-07-19 12:47:43 +04:00
inline uint32_t udf_get_pblock ( struct super_block * sb , uint32_t block ,
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct udf_part_map * map ;
if ( partition > = sbi - > s_partitions ) {
2008-02-08 15:20:36 +03:00
udf_debug ( " block=%d, partition=%d, offset=%d: "
" invalid partition \n " , block , partition , offset ) ;
2005-04-17 02:20:36 +04:00
return 0xFFFFFFFF ;
}
2008-02-08 15:20:30 +03:00
map = & sbi - > s_partmaps [ partition ] ;
if ( map - > s_partition_func )
return map - > s_partition_func ( sb , block , partition , offset ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:30 +03:00
return map - > s_partition_root + block + offset ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
uint32_t udf_get_pblock_virt15 ( struct super_block * sb , uint32_t block ,
2007-07-19 12:47:43 +04:00
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
uint32_t newblock ;
uint32_t index ;
uint32_t loc ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct udf_part_map * map ;
2008-02-08 15:20:36 +03:00
struct udf_virtual_data * vdata ;
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:30 +03:00
map = & sbi - > s_partmaps [ partition ] ;
2008-02-08 15:20:36 +03:00
vdata = & map - > s_type_specific . s_virtual ;
index = ( sb - > s_blocksize - vdata - > s_start_offset ) / sizeof ( uint32_t ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
if ( block > vdata - > s_num_entries ) {
udf_debug ( " Trying to access block beyond end of VAT "
" (%d max %d) \n " , block , vdata - > s_num_entries ) ;
2005-04-17 02:20:36 +04:00
return 0xFFFFFFFF ;
}
2007-07-19 12:47:43 +04:00
if ( block > = index ) {
2005-04-17 02:20:36 +04:00
block - = index ;
newblock = 1 + ( block / ( sb - > s_blocksize / sizeof ( uint32_t ) ) ) ;
index = block % ( sb - > s_blocksize / sizeof ( uint32_t ) ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
newblock = 0 ;
2008-02-08 15:20:36 +03:00
index = vdata - > s_start_offset / sizeof ( uint32_t ) + block ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:30 +03:00
loc = udf_block_map ( sbi - > s_vat_inode , newblock ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
bh = sb_bread ( sb , loc ) ;
if ( ! bh ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d] \n " ,
2007-07-19 12:47:43 +04:00
sb , block , partition , loc , index ) ;
2005-04-17 02:20:36 +04:00
return 0xFFFFFFFF ;
}
2007-07-21 15:37:18 +04:00
loc = le32_to_cpu ( ( ( __le32 * ) bh - > b_data ) [ index ] ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( sbi - > s_vat_inode ) ;
if ( iinfo - > i_location . partitionReferenceNum = = partition ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " recursive call to udf_get_pblock! \n " ) ;
return 0xFFFFFFFF ;
}
2007-07-19 12:47:43 +04:00
return udf_get_pblock ( sb , loc ,
2008-02-08 15:20:44 +03:00
iinfo - > i_location . partitionReferenceNum ,
2007-07-21 15:37:18 +04:00
offset ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
inline uint32_t udf_get_pblock_virt20 ( struct super_block * sb , uint32_t block ,
2007-07-19 12:47:43 +04:00
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
return udf_get_pblock_virt15 ( sb , block , partition , offset ) ;
}
2008-02-08 15:20:30 +03:00
uint32_t udf_get_pblock_spar15 ( struct super_block * sb , uint32_t block ,
2007-07-19 12:47:43 +04:00
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
int i ;
struct sparingTable * st = NULL ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
struct udf_part_map * map ;
uint32_t packet ;
2008-02-08 15:20:36 +03:00
struct udf_sparing_data * sdata ;
2008-02-08 15:20:30 +03:00
map = & sbi - > s_partmaps [ partition ] ;
2008-02-08 15:20:36 +03:00
sdata = & map - > s_type_specific . s_sparing ;
packet = ( block + offset ) & ~ ( sdata - > s_packet_len - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
for ( i = 0 ; i < 4 ; i + + ) {
2008-02-08 15:20:36 +03:00
if ( sdata - > s_spar_map [ i ] ! = NULL ) {
st = ( struct sparingTable * )
sdata - > s_spar_map [ i ] - > b_data ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2007-07-19 12:47:43 +04:00
if ( st ) {
for ( i = 0 ; i < le16_to_cpu ( st - > reallocationTableLen ) ; i + + ) {
2008-02-08 15:20:36 +03:00
struct sparingEntry * entry = & st - > mapEntry [ i ] ;
u32 origLoc = le32_to_cpu ( entry - > origLocation ) ;
if ( origLoc > = 0xFFFFFFF0 )
2005-04-17 02:20:36 +04:00
break ;
2008-02-08 15:20:36 +03:00
else if ( origLoc = = packet )
return le32_to_cpu ( entry - > mappedLocation ) +
( ( block + offset ) &
( sdata - > s_packet_len - 1 ) ) ;
else if ( origLoc > packet )
2005-04-17 02:20:36 +04:00
break ;
}
}
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:30 +03:00
return map - > s_partition_root + block + offset ;
2005-04-17 02:20:36 +04:00
}
int udf_relocate_blocks ( struct super_block * sb , long old_block , long * new_block )
{
struct udf_sparing_data * sdata ;
struct sparingTable * st = NULL ;
struct sparingEntry mapEntry ;
uint32_t packet ;
int i , j , k , l ;
2008-02-08 15:20:30 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2008-02-08 15:20:36 +03:00
u16 reallocationTableLen ;
struct buffer_head * bh ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
for ( i = 0 ; i < sbi - > s_partitions ; i + + ) {
struct udf_part_map * map = & sbi - > s_partmaps [ i ] ;
if ( old_block > map - > s_partition_root & &
old_block < map - > s_partition_root + map - > s_partition_len ) {
sdata = & map - > s_type_specific . s_sparing ;
2008-02-08 15:20:36 +03:00
packet = ( old_block - map - > s_partition_root ) &
~ ( sdata - > s_packet_len - 1 ) ;
2007-07-19 12:47:43 +04:00
2008-02-08 15:20:36 +03:00
for ( j = 0 ; j < 4 ; j + + )
if ( sdata - > s_spar_map [ j ] ! = NULL ) {
st = ( struct sparingTable * )
sdata - > s_spar_map [ j ] - > b_data ;
2005-04-17 02:20:36 +04:00
break ;
}
if ( ! st )
return 1 ;
2008-02-08 15:20:36 +03:00
reallocationTableLen =
le16_to_cpu ( st - > reallocationTableLen ) ;
for ( k = 0 ; k < reallocationTableLen ; k + + ) {
struct sparingEntry * entry = & st - > mapEntry [ k ] ;
u32 origLoc = le32_to_cpu ( entry - > origLocation ) ;
if ( origLoc = = 0xFFFFFFFF ) {
2007-07-19 12:47:43 +04:00
for ( ; j < 4 ; j + + ) {
2008-02-08 15:20:36 +03:00
int len ;
bh = sdata - > s_spar_map [ j ] ;
if ( ! bh )
continue ;
st = ( struct sparingTable * )
bh - > b_data ;
entry - > origLocation =
cpu_to_le32 ( packet ) ;
len =
sizeof ( struct sparingTable ) +
reallocationTableLen *
sizeof ( struct sparingEntry ) ;
udf_update_tag ( ( char * ) st , len ) ;
mark_buffer_dirty ( bh ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
* new_block = le32_to_cpu (
entry - > mappedLocation ) +
( ( old_block -
map - > s_partition_root ) &
( sdata - > s_packet_len - 1 ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2008-02-08 15:20:36 +03:00
} else if ( origLoc = = packet ) {
* new_block = le32_to_cpu (
entry - > mappedLocation ) +
( ( old_block -
map - > s_partition_root ) &
( sdata - > s_packet_len - 1 ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2008-02-08 15:20:36 +03:00
} else if ( origLoc > packet )
2005-04-17 02:20:36 +04:00
break ;
}
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:36 +03:00
for ( l = k ; l < reallocationTableLen ; l + + ) {
struct sparingEntry * entry = & st - > mapEntry [ l ] ;
u32 origLoc = le32_to_cpu ( entry - > origLocation ) ;
if ( origLoc ! = 0xFFFFFFFF )
continue ;
for ( ; j < 4 ; j + + ) {
bh = sdata - > s_spar_map [ j ] ;
if ( ! bh )
continue ;
st = ( struct sparingTable * ) bh - > b_data ;
mapEntry = st - > mapEntry [ l ] ;
mapEntry . origLocation =
cpu_to_le32 ( packet ) ;
memmove ( & st - > mapEntry [ k + 1 ] ,
& st - > mapEntry [ k ] ,
( l - k ) *
sizeof ( struct sparingEntry ) ) ;
st - > mapEntry [ k ] = mapEntry ;
udf_update_tag ( ( char * ) st ,
sizeof ( struct sparingTable ) +
reallocationTableLen *
sizeof ( struct sparingEntry ) ) ;
mark_buffer_dirty ( bh ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
* new_block =
le32_to_cpu (
st - > mapEntry [ k ] . mappedLocation ) +
( ( old_block - map - > s_partition_root ) &
( sdata - > s_packet_len - 1 ) ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-21 15:37:18 +04:00
} /* if old_block */
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:30 +03:00
if ( i = = sbi - > s_partitions ) {
2005-04-17 02:20:36 +04:00
/* outside of partitions */
/* for now, fail =) */
return 1 ;
}
return 0 ;
}