2005-04-17 02:20:36 +04:00
/*
* balloc . c
*
* PURPOSE
* Block allocation 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 ) 1999 - 2001 Ben Fennema
* ( C ) 1999 Stelias Computing Inc
*
* HISTORY
*
* 02 / 24 / 99 blf Created .
*
*/
# include "udfdecl.h"
# include <linux/buffer_head.h>
# include <linux/bitops.h>
# include "udf_i.h"
# include "udf_sb.h"
2011-03-24 02:42:11 +03:00
# define udf_clear_bit __test_and_clear_bit_le
# define udf_set_bit __test_and_set_bit_le
# define udf_test_bit test_bit_le
# define udf_find_next_one_bit find_next_bit_le
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
static int read_block_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap , unsigned int block ,
unsigned long bitmap_nr )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
int retval = 0 ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr loc ;
2005-04-17 02:20:36 +04:00
loc . logicalBlockNum = bitmap - > s_extPosition ;
2008-02-08 15:20:30 +03:00
loc . partitionReferenceNum = UDF_SB ( sb ) - > s_partition ;
2005-04-17 02:20:36 +04:00
2008-10-15 14:29:03 +04:00
bh = udf_tread ( sb , udf_get_lb_pblock ( sb , & loc , block ) ) ;
2008-02-08 15:20:36 +03:00
if ( ! bh )
2005-04-17 02:20:36 +04:00
retval = - EIO ;
2008-02-08 15:20:36 +03:00
2005-04-17 02:20:36 +04:00
bitmap - > s_block_bitmap [ bitmap_nr ] = bh ;
return retval ;
}
2007-07-19 12:47:43 +04:00
static int __load_block_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap ,
unsigned int block_group )
2005-04-17 02:20:36 +04:00
{
int retval = 0 ;
int nr_groups = bitmap - > s_nr_groups ;
2007-07-19 12:47:43 +04:00
if ( block_group > = nr_groups ) {
2011-10-10 12:08:07 +04:00
udf_debug ( " block_group (%d) > nr_groups (%d) \n " ,
block_group , nr_groups ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
if ( bitmap - > s_block_bitmap [ block_group ] ) {
2005-04-17 02:20:36 +04:00
return block_group ;
2007-07-21 15:37:18 +04:00
} else {
retval = read_block_bitmap ( sb , bitmap , block_group ,
block_group ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 )
return retval ;
return block_group ;
}
}
2007-07-19 12:47:43 +04:00
static inline int load_block_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap ,
unsigned int block_group )
2005-04-17 02:20:36 +04:00
{
int slot ;
slot = __load_block_bitmap ( sb , bitmap , block_group ) ;
if ( slot < 0 )
return slot ;
if ( ! bitmap - > s_block_bitmap [ slot ] )
return - EIO ;
return slot ;
}
2009-03-16 20:27:37 +03:00
static void udf_add_free_space ( struct super_block * sb , u16 partition , u32 cnt )
2008-02-08 15:20:40 +03:00
{
2009-03-16 20:27:37 +03:00
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2008-02-08 15:20:40 +03:00
struct logicalVolIntegrityDesc * lvid ;
2009-03-16 20:27:37 +03:00
if ( ! sbi - > s_lvid_bh )
return ;
2008-02-08 15:20:40 +03:00
lvid = ( struct logicalVolIntegrityDesc * ) sbi - > s_lvid_bh - > b_data ;
2008-01-31 00:03:57 +03:00
le32_add_cpu ( & lvid - > freeSpaceTable [ partition ] , cnt ) ;
2009-03-16 20:27:37 +03:00
udf_updated_lvid ( sb ) ;
2008-02-08 15:20:40 +03:00
}
2007-07-19 12:47:43 +04:00
static void udf_bitmap_free_blocks ( struct super_block * sb ,
struct udf_bitmap * bitmap ,
2008-10-15 14:29:03 +04:00
struct kernel_lb_addr * bloc ,
uint32_t offset ,
2007-07-19 12:47:43 +04:00
uint32_t count )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2007-07-19 12:47:43 +04:00
struct buffer_head * bh = NULL ;
2008-10-15 14:29:03 +04:00
struct udf_part_map * partmap ;
2005-04-17 02:20:36 +04:00
unsigned long block ;
unsigned long block_group ;
unsigned long bit ;
unsigned long i ;
int bitmap_nr ;
unsigned long overflow ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-10-15 14:29:03 +04:00
partmap = & sbi - > s_partmaps [ bloc - > partitionReferenceNum ] ;
2010-03-15 11:21:13 +03:00
if ( bloc - > logicalBlockNum + count < count | |
( bloc - > logicalBlockNum + count ) > partmap - > s_partition_len ) {
2007-07-21 15:37:18 +04:00
udf_debug ( " %d < %d || %d + %d > %d \n " ,
2011-10-10 12:08:07 +04:00
bloc - > logicalBlockNum , 0 ,
bloc - > logicalBlockNum , count ,
partmap - > s_partition_len ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
}
2008-10-15 14:29:03 +04:00
block = bloc - > logicalBlockNum + offset +
2008-02-08 15:20:36 +03:00
( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:41 +03:00
do {
overflow = 0 ;
block_group = block > > ( sb - > s_blocksize_bits + 3 ) ;
bit = block % ( sb - > s_blocksize < < 3 ) ;
/*
* Check to see if we are freeing blocks across a group boundary .
*/
if ( bit + count > ( sb - > s_blocksize < < 3 ) ) {
overflow = bit + count - ( sb - > s_blocksize < < 3 ) ;
count - = overflow ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:41 +03:00
bitmap_nr = load_block_bitmap ( sb , bitmap , block_group ) ;
if ( bitmap_nr < 0 )
goto error_return ;
bh = bitmap - > s_block_bitmap [ bitmap_nr ] ;
for ( i = 0 ; i < count ; i + + ) {
if ( udf_set_bit ( bit + i , bh - > b_data ) ) {
udf_debug ( " bit %ld already set \n " , bit + i ) ;
udf_debug ( " byte=%2x \n " ,
2011-10-10 12:08:07 +04:00
( ( char * ) bh - > b_data ) [ ( bit + i ) > > 3 ] ) ;
2008-02-08 15:20:41 +03:00
}
}
2010-10-21 00:32:02 +04:00
udf_add_free_space ( sb , sbi - > s_partition , count ) ;
2008-02-08 15:20:41 +03:00
mark_buffer_dirty ( bh ) ;
if ( overflow ) {
block + = count ;
count = overflow ;
}
} while ( overflow ) ;
2007-07-21 15:37:18 +04:00
error_return :
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
static int udf_bitmap_prealloc_blocks ( struct super_block * sb ,
struct udf_bitmap * bitmap ,
uint16_t partition , uint32_t first_block ,
uint32_t block_count )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
int alloc_count = 0 ;
int bit , block , block_group , group_start ;
int nr_groups , bitmap_nr ;
struct buffer_head * bh ;
2008-02-08 15:20:30 +03:00
__u32 part_len ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-08 15:20:30 +03:00
part_len = sbi - > s_partmaps [ partition ] . s_partition_len ;
2009-06-23 01:12:29 +04:00
if ( first_block > = part_len )
2005-04-17 02:20:36 +04:00
goto out ;
2008-02-08 15:20:30 +03:00
if ( first_block + block_count > part_len )
block_count = part_len - first_block ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:41 +03:00
do {
nr_groups = udf_compute_nr_groups ( sb , partition ) ;
block = first_block + ( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
block_group = block > > ( sb - > s_blocksize_bits + 3 ) ;
group_start = block_group ? 0 : sizeof ( struct spaceBitmapDesc ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:41 +03:00
bitmap_nr = load_block_bitmap ( sb , bitmap , block_group ) ;
if ( bitmap_nr < 0 )
goto out ;
bh = bitmap - > s_block_bitmap [ bitmap_nr ] ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:41 +03:00
bit = block % ( sb - > s_blocksize < < 3 ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:41 +03:00
while ( bit < ( sb - > s_blocksize < < 3 ) & & block_count > 0 ) {
2010-05-19 18:28:56 +04:00
if ( ! udf_clear_bit ( bit , bh - > b_data ) )
2008-02-08 15:20:41 +03:00
goto out ;
block_count - - ;
alloc_count + + ;
bit + + ;
block + + ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:41 +03:00
mark_buffer_dirty ( bh ) ;
} while ( block_count > 0 ) ;
2007-07-21 15:37:18 +04:00
out :
2009-03-16 20:27:37 +03:00
udf_add_free_space ( sb , partition , - alloc_count ) ;
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return alloc_count ;
}
2007-07-19 12:47:43 +04:00
static int udf_bitmap_new_block ( struct super_block * sb ,
struct udf_bitmap * bitmap , uint16_t partition ,
uint32_t goal , int * err )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2007-07-19 12:47:43 +04:00
int newbit , bit = 0 , block , block_group , group_start ;
2005-04-17 02:20:36 +04:00
int end_goal , nr_groups , bitmap_nr , i ;
struct buffer_head * bh = NULL ;
char * ptr ;
int newblock = 0 ;
* err = - ENOSPC ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
repeat :
2009-06-23 01:12:29 +04:00
if ( goal > = sbi - > s_partmaps [ partition ] . s_partition_len )
2005-04-17 02:20:36 +04:00
goal = 0 ;
nr_groups = bitmap - > s_nr_groups ;
block = goal + ( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
block_group = block > > ( sb - > s_blocksize_bits + 3 ) ;
group_start = block_group ? 0 : sizeof ( struct spaceBitmapDesc ) ;
bitmap_nr = load_block_bitmap ( sb , bitmap , block_group ) ;
if ( bitmap_nr < 0 )
goto error_return ;
bh = bitmap - > s_block_bitmap [ bitmap_nr ] ;
2007-07-21 15:37:18 +04:00
ptr = memscan ( ( char * ) bh - > b_data + group_start , 0xFF ,
sb - > s_blocksize - group_start ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ( ptr - ( ( char * ) bh - > b_data ) ) < sb - > s_blocksize ) {
2005-04-17 02:20:36 +04:00
bit = block % ( sb - > s_blocksize < < 3 ) ;
2007-07-21 15:37:18 +04:00
if ( udf_test_bit ( bit , bh - > b_data ) )
2005-04-17 02:20:36 +04:00
goto got_block ;
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
end_goal = ( bit + 63 ) & ~ 63 ;
bit = udf_find_next_one_bit ( bh - > b_data , end_goal , bit ) ;
if ( bit < end_goal )
goto got_block ;
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:36 +03:00
ptr = memscan ( ( char * ) bh - > b_data + ( bit > > 3 ) , 0xFF ,
sb - > s_blocksize - ( ( bit + 7 ) > > 3 ) ) ;
2005-04-17 02:20:36 +04:00
newbit = ( ptr - ( ( char * ) bh - > b_data ) ) < < 3 ;
2007-07-19 12:47:43 +04:00
if ( newbit < sb - > s_blocksize < < 3 ) {
2005-04-17 02:20:36 +04:00
bit = newbit ;
goto search_back ;
}
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:36 +03:00
newbit = udf_find_next_one_bit ( bh - > b_data ,
sb - > s_blocksize < < 3 , bit ) ;
2007-07-19 12:47:43 +04:00
if ( newbit < sb - > s_blocksize < < 3 ) {
2005-04-17 02:20:36 +04:00
bit = newbit ;
goto got_block ;
}
}
2007-07-19 12:47:43 +04:00
for ( i = 0 ; i < ( nr_groups * 2 ) ; i + + ) {
block_group + + ;
2005-04-17 02:20:36 +04:00
if ( block_group > = nr_groups )
block_group = 0 ;
group_start = block_group ? 0 : sizeof ( struct spaceBitmapDesc ) ;
bitmap_nr = load_block_bitmap ( sb , bitmap , block_group ) ;
if ( bitmap_nr < 0 )
goto error_return ;
bh = bitmap - > s_block_bitmap [ bitmap_nr ] ;
2007-07-19 12:47:43 +04:00
if ( i < nr_groups ) {
2007-07-21 15:37:18 +04:00
ptr = memscan ( ( char * ) bh - > b_data + group_start , 0xFF ,
sb - > s_blocksize - group_start ) ;
2007-07-19 12:47:43 +04:00
if ( ( ptr - ( ( char * ) bh - > b_data ) ) < sb - > s_blocksize ) {
2005-04-17 02:20:36 +04:00
bit = ( ptr - ( ( char * ) bh - > b_data ) ) < < 3 ;
break ;
}
2007-07-19 12:47:43 +04:00
} else {
2011-02-22 22:04:19 +03:00
bit = udf_find_next_one_bit ( bh - > b_data ,
2007-07-21 15:37:18 +04:00
sb - > s_blocksize < < 3 ,
group_start < < 3 ) ;
2005-04-17 02:20:36 +04:00
if ( bit < sb - > s_blocksize < < 3 )
break ;
}
}
2007-07-19 12:47:43 +04:00
if ( i > = ( nr_groups * 2 ) ) {
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return newblock ;
}
if ( bit < sb - > s_blocksize < < 3 )
goto search_back ;
else
2008-02-08 15:20:36 +03:00
bit = udf_find_next_one_bit ( bh - > b_data , sb - > s_blocksize < < 3 ,
group_start < < 3 ) ;
2007-07-19 12:47:43 +04:00
if ( bit > = sb - > s_blocksize < < 3 ) {
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-21 15:37:18 +04:00
search_back :
2008-02-08 15:20:36 +03:00
i = 0 ;
while ( i < 7 & & bit > ( group_start < < 3 ) & &
udf_test_bit ( bit - 1 , bh - > b_data ) ) {
+ + i ;
- - bit ;
}
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
got_block :
2005-04-17 02:20:36 +04:00
newblock = bit + ( block_group < < ( sb - > s_blocksize_bits + 3 ) ) -
2007-07-21 15:37:18 +04:00
( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ! udf_clear_bit ( bit , bh - > b_data ) ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " bit already cleared for block %d \n " , bit ) ;
goto repeat ;
}
mark_buffer_dirty ( bh ) ;
2009-03-16 20:27:37 +03:00
udf_add_free_space ( sb , partition , - 1 ) ;
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
* err = 0 ;
return newblock ;
2007-07-21 15:37:18 +04:00
error_return :
2005-04-17 02:20:36 +04:00
* err = - EIO ;
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2007-07-19 12:47:43 +04:00
static void udf_table_free_blocks ( struct super_block * sb ,
struct inode * table ,
2008-10-15 14:29:03 +04:00
struct kernel_lb_addr * bloc ,
uint32_t offset ,
2007-07-19 12:47:43 +04:00
uint32_t count )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2008-10-15 14:29:03 +04:00
struct udf_part_map * partmap ;
2005-04-17 02:20:36 +04:00
uint32_t start , end ;
2007-05-08 11:35:14 +04:00
uint32_t elen ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2007-05-08 11:35:14 +04:00
struct extent_position oepos , epos ;
2005-04-17 02:20:36 +04:00
int8_t etype ;
int i ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-10-15 14:29:03 +04:00
partmap = & sbi - > s_partmaps [ bloc - > partitionReferenceNum ] ;
2010-03-15 11:21:13 +03:00
if ( bloc - > logicalBlockNum + count < count | |
( bloc - > logicalBlockNum + count ) > partmap - > s_partition_len ) {
2007-07-21 15:37:18 +04:00
udf_debug ( " %d < %d || %d + %d > %d \n " ,
2011-10-10 12:08:07 +04:00
bloc - > logicalBlockNum , 0 ,
bloc - > logicalBlockNum , count ,
2008-10-15 14:29:03 +04:00
partmap - > s_partition_len ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
}
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( table ) ;
2009-03-16 20:27:37 +03:00
udf_add_free_space ( sb , sbi - > s_partition , count ) ;
2005-04-17 02:20:36 +04:00
2008-10-15 14:29:03 +04:00
start = bloc - > logicalBlockNum + offset ;
end = bloc - > logicalBlockNum + offset + count - 1 ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
epos . offset = oepos . offset = sizeof ( struct unallocSpaceEntry ) ;
2005-04-17 02:20:36 +04:00
elen = 0 ;
2008-02-08 15:20:44 +03:00
epos . block = oepos . block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
epos . bh = oepos . bh = NULL ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
while ( count & &
( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2008-02-08 15:20:36 +03:00
if ( ( ( eloc . logicalBlockNum +
( elen > > sb - > s_blocksize_bits ) ) = = start ) ) {
if ( ( 0x3FFFFFFF - elen ) <
( count < < sb - > s_blocksize_bits ) ) {
uint32_t tmp = ( ( 0x3FFFFFFF - elen ) > >
sb - > s_blocksize_bits ) ;
count - = tmp ;
start + = tmp ;
elen = ( etype < < 30 ) |
( 0x40000000 - sb - > s_blocksize ) ;
2007-07-19 12:47:43 +04:00
} else {
2008-02-08 15:20:36 +03:00
elen = ( etype < < 30 ) |
( elen +
( count < < sb - > s_blocksize_bits ) ) ;
2005-04-17 02:20:36 +04:00
start + = count ;
count = 0 ;
}
2008-10-15 14:29:03 +04:00
udf_write_aext ( table , & oepos , & eloc , elen , 1 ) ;
2007-07-19 12:47:43 +04:00
} else if ( eloc . logicalBlockNum = = ( end + 1 ) ) {
2008-02-08 15:20:36 +03:00
if ( ( 0x3FFFFFFF - elen ) <
( count < < sb - > s_blocksize_bits ) ) {
uint32_t tmp = ( ( 0x3FFFFFFF - elen ) > >
sb - > s_blocksize_bits ) ;
count - = tmp ;
end - = tmp ;
eloc . logicalBlockNum - = tmp ;
elen = ( etype < < 30 ) |
( 0x40000000 - sb - > s_blocksize ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
eloc . logicalBlockNum = start ;
2008-02-08 15:20:36 +03:00
elen = ( etype < < 30 ) |
( elen +
( count < < sb - > s_blocksize_bits ) ) ;
2005-04-17 02:20:36 +04:00
end - = count ;
count = 0 ;
}
2008-10-15 14:29:03 +04:00
udf_write_aext ( table , & oepos , & eloc , elen , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( epos . bh ! = oepos . bh ) {
2005-04-17 02:20:36 +04:00
i = - 1 ;
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 = 0 ;
2007-07-21 15:37:18 +04:00
} else {
2007-05-08 11:35:14 +04:00
oepos . offset = epos . offset ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( count ) {
2007-07-21 15:37:18 +04:00
/*
2008-02-08 15:20:36 +03:00
* NOTE : we CANNOT use udf_add_aext here , as it can try to
* allocate a new block , and since we hold the super block
* lock already very bad things would happen : )
2007-07-21 15:37:18 +04:00
*
* We copy the behavior of udf_add_aext , but instead of
* trying to allocate a new block close to the existing one ,
* we just steal a block from the extent we are trying to add .
*
* It would be nice if the blocks were close together , but it
* isn ' t required .
2007-07-19 12:47:43 +04:00
*/
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 ;
eloc . logicalBlockNum = start ;
2007-07-21 15:37:18 +04:00
elen = EXT_RECORDED_ALLOCATED |
( count < < sb - > s_blocksize_bits ) ;
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 ) ;
2008-02-08 15:20:44 +03:00
else {
2007-05-08 11:35:16 +04:00
brelse ( oepos . bh ) ;
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
}
2007-07-19 12:47:43 +04:00
if ( epos . offset + ( 2 * adsize ) > sb - > s_blocksize ) {
2010-02-01 05:28:48 +03:00
unsigned char * sptr , * dptr ;
2005-04-17 02:20:36 +04:00
int loffset ;
2007-07-19 12:47:43 +04:00
2007-05-08 11:35:16 +04:00
brelse ( oepos . bh ) ;
2007-05-08 11:35:14 +04:00
oepos = epos ;
2005-04-17 02:20:36 +04:00
/* Steal a block from the extent being free'd */
2007-05-08 11:35:14 +04:00
epos . block . logicalBlockNum = eloc . logicalBlockNum ;
2007-07-19 12:47:43 +04:00
eloc . logicalBlockNum + + ;
2005-04-17 02:20:36 +04:00
elen - = sb - > s_blocksize ;
2008-02-08 15:20:36 +03:00
epos . bh = udf_tread ( sb ,
2008-10-15 14:29:03 +04:00
udf_get_lb_pblock ( sb , & epos . block , 0 ) ) ;
2008-02-08 15:20:36 +03:00
if ( ! epos . bh ) {
2007-05-08 11:35:16 +04:00
brelse ( oepos . bh ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
}
2007-05-08 11:35:14 +04:00
aed = ( struct allocExtDesc * ) ( epos . bh - > b_data ) ;
2008-02-08 15:20:36 +03:00
aed - > previousAllocExtLocation =
cpu_to_le32 ( oepos . block . logicalBlockNum ) ;
2007-07-19 12:47:43 +04:00
if ( epos . offset + adsize > 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 ) ;
2008-02-08 15:20:44 +03:00
sptr = iinfo - > i_ext . i_data + epos . offset
2008-02-08 15:20:42 +03:00
- adsize ;
2008-02-08 15:20:36 +03:00
dptr = epos . bh - > b_data +
sizeof ( struct allocExtDesc ) ;
2005-04-17 02:20:36 +04:00
memcpy ( dptr , sptr , adsize ) ;
2008-02-08 15:20:36 +03: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 ) ;
2007-07-19 12:47:43 +04:00
if ( oepos . bh ) {
2007-08-31 10:56:22 +04:00
sptr = oepos . bh - > b_data + epos . offset ;
2008-02-08 15:20:36 +03:00
aed = ( struct allocExtDesc * )
oepos . 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
sptr = iinfo - > i_ext . i_data +
2008-02-08 15:20:42 +03:00
epos . offset ;
2008-02-08 15:20:44 +03:00
iinfo - > i_lenAlloc + = adsize ;
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( table ) ;
}
2007-08-31 10:56:22 +04:00
epos . offset = sizeof ( struct allocExtDesc ) ;
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:30 +03:00
if ( sbi - > s_udfrev > = 0x0200 )
2008-02-08 15:20:36 +03:00
udf_new_tag ( epos . bh - > b_data , TAG_IDENT_AED ,
3 , 1 , epos . block . logicalBlockNum ,
2008-10-15 14:28:03 +04:00
sizeof ( struct tag ) ) ;
2005-04-17 02:20:36 +04:00
else
2008-02-08 15:20:36 +03:00
udf_new_tag ( epos . bh - > b_data , TAG_IDENT_AED ,
2 , 1 , epos . block . logicalBlockNum ,
2008-10-15 14:28:03 +04:00
sizeof ( struct tag ) ) ;
2007-07-21 15:37:18 +04:00
2008-02-08 15:20:44 +03:00
switch ( iinfo - > i_alloc_type ) {
2008-02-08 15:20:36 +03:00
case ICBTAG_FLAG_AD_SHORT :
2008-10-15 14:28:03 +04:00
sad = ( struct short_ad * ) sptr ;
2008-02-08 15:20:36 +03:00
sad - > extLength = cpu_to_le32 (
EXT_NEXT_EXTENT_ALLOCDECS |
sb - > s_blocksize ) ;
sad - > extPosition =
cpu_to_le32 ( epos . block . logicalBlockNum ) ;
break ;
case ICBTAG_FLAG_AD_LONG :
2008-10-15 14:28:03 +04:00
lad = ( struct long_ad * ) sptr ;
2008-02-08 15:20:36 +03:00
lad - > extLength = cpu_to_le32 (
EXT_NEXT_EXTENT_ALLOCDECS |
sb - > s_blocksize ) ;
lad - > extLocation =
cpu_to_lelb ( epos . block ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( oepos . bh ) {
2007-05-08 11:35:14 +04:00
udf_update_tag ( oepos . bh - > b_data , loffset ) ;
mark_buffer_dirty ( oepos . bh ) ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
mark_inode_dirty ( table ) ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
}
2008-02-08 15:20:36 +03:00
/* It's possible that stealing the block emptied the extent */
if ( elen ) {
2008-10-15 14:29:03 +04:00
udf_write_aext ( table , & epos , & eloc , elen , 1 ) ;
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 ( table ) ;
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 ) ;
2007-05-08 11:35:14 +04:00
udf_update_tag ( epos . bh - > b_data , epos . offset ) ;
mark_buffer_dirty ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
}
}
}
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
brelse ( oepos . bh ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
error_return :
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return ;
}
2007-07-19 12:47:43 +04:00
static int udf_table_prealloc_blocks ( struct super_block * sb ,
struct inode * table , uint16_t partition ,
uint32_t first_block , uint32_t block_count )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
int alloc_count = 0 ;
2007-05-08 11:35:14 +04:00
uint32_t elen , adsize ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc ;
2007-05-08 11:35:14 +04:00
struct extent_position epos ;
2005-04-17 02:20:36 +04:00
int8_t etype = - 1 ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo ;
2005-04-17 02:20:36 +04:00
2009-06-23 01:12:29 +04:00
if ( first_block > = sbi - > s_partmaps [ partition ] . s_partition_len )
2005-04-17 02:20:36 +04:00
return 0 ;
2008-02-08 15:20:44 +03:00
iinfo = UDF_I ( table ) ;
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
return 0 ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2007-05-08 11:35:14 +04:00
epos . offset = sizeof ( struct unallocSpaceEntry ) ;
2008-02-08 15:20:44 +03:00
epos . block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
epos . bh = NULL ;
2005-04-17 02:20:36 +04:00
eloc . logicalBlockNum = 0xFFFFFFFF ;
2007-07-21 15:37:18 +04:00
while ( first_block ! = eloc . logicalBlockNum & &
( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " eloc=%d, elen=%d, first_block=%d \n " ,
2007-07-19 12:47:43 +04:00
eloc . logicalBlockNum , elen , first_block ) ;
2007-07-21 15:37:18 +04:00
; /* empty loop body */
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
if ( first_block = = eloc . logicalBlockNum ) {
2007-05-08 11:35:14 +04:00
epos . offset - = adsize ;
2005-04-17 02:20:36 +04:00
alloc_count = ( elen > > sb - > s_blocksize_bits ) ;
2010-05-19 18:28:56 +04:00
if ( alloc_count > block_count ) {
2005-04-17 02:20:36 +04:00
alloc_count = block_count ;
eloc . logicalBlockNum + = alloc_count ;
elen - = ( alloc_count < < sb - > s_blocksize_bits ) ;
2008-10-15 14:29:03 +04:00
udf_write_aext ( table , & epos , & eloc ,
2008-02-08 15:20:36 +03:00
( etype < < 30 ) | elen , 1 ) ;
} else
udf_delete_aext ( table , epos , eloc ,
( etype < < 30 ) | elen ) ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
alloc_count = 0 ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
2009-03-16 20:27:37 +03:00
if ( alloc_count )
udf_add_free_space ( sb , partition , - alloc_count ) ;
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return alloc_count ;
}
2007-07-19 12:47:43 +04:00
static int udf_table_new_block ( struct super_block * sb ,
struct inode * table , uint16_t partition ,
uint32_t goal , int * err )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
uint32_t spread = 0xFFFFFFFF , nspread = 0xFFFFFFFF ;
uint32_t newblock = 0 , adsize ;
2007-05-08 11:35:14 +04:00
uint32_t elen , goal_elen = 0 ;
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr eloc , uninitialized_var ( goal_eloc ) ;
2007-05-08 11:35:14 +04:00
struct extent_position epos , goal_epos ;
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 ( table ) ;
2005-04-17 02:20:36 +04:00
* err = - ENOSPC ;
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
return newblock ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2009-06-23 01:12:29 +04:00
if ( goal > = sbi - > s_partmaps [ partition ] . s_partition_len )
2005-04-17 02:20:36 +04:00
goal = 0 ;
2008-02-08 15:20:36 +03:00
/* We search for the closest matching block to goal. If we find
a exact hit , we stop . Otherwise we keep going till we run out
of extents . We store the buffer_head , bloc , and extoffset
of the current closest match and use that when we are done .
2007-07-19 12:47:43 +04:00
*/
2007-05-08 11:35:14 +04:00
epos . offset = sizeof ( struct unallocSpaceEntry ) ;
2008-02-08 15:20:44 +03:00
epos . block = iinfo - > i_location ;
2007-05-08 11:35:14 +04:00
epos . bh = goal_epos . bh = NULL ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
while ( spread & &
( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2007-07-19 12:47:43 +04:00
if ( goal > = eloc . logicalBlockNum ) {
2008-02-08 15:20:36 +03:00
if ( goal < eloc . logicalBlockNum +
( elen > > sb - > s_blocksize_bits ) )
2005-04-17 02:20:36 +04:00
nspread = 0 ;
else
nspread = goal - eloc . logicalBlockNum -
2007-07-21 15:37:18 +04:00
( elen > > sb - > s_blocksize_bits ) ;
} else {
2005-04-17 02:20:36 +04:00
nspread = eloc . logicalBlockNum - goal ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( nspread < spread ) {
2005-04-17 02:20:36 +04:00
spread = nspread ;
2007-07-19 12:47:43 +04:00
if ( goal_epos . bh ! = epos . bh ) {
2007-05-08 11:35:16 +04:00
brelse ( goal_epos . bh ) ;
2007-05-08 11:35:14 +04:00
goal_epos . bh = epos . bh ;
2007-05-08 11:35:16 +04:00
get_bh ( goal_epos . bh ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-08 11:35:14 +04:00
goal_epos . block = epos . block ;
goal_epos . offset = epos . offset - adsize ;
2005-04-17 02:20:36 +04:00
goal_eloc = eloc ;
goal_elen = ( etype < < 30 ) | elen ;
}
}
2007-05-08 11:35:16 +04:00
brelse ( epos . bh ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( spread = = 0xFFFFFFFF ) {
2007-05-08 11:35:16 +04:00
brelse ( goal_epos . bh ) ;
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Only allocate blocks from the beginning of the extent.
That way , we only delete ( empty ) extents , never have to insert an
extent because of splitting */
/* This works, but very poorly.... */
newblock = goal_eloc . logicalBlockNum ;
2007-07-19 12:47:43 +04:00
goal_eloc . logicalBlockNum + + ;
2005-04-17 02:20:36 +04:00
goal_elen - = sb - > s_blocksize ;
if ( goal_elen )
2008-10-15 14:29:03 +04:00
udf_write_aext ( table , & goal_epos , & goal_eloc , goal_elen , 1 ) ;
2005-04-17 02:20:36 +04:00
else
2007-05-08 11:35:14 +04:00
udf_delete_aext ( table , goal_epos , goal_eloc , goal_elen ) ;
2007-05-08 11:35:16 +04:00
brelse ( goal_epos . bh ) ;
2005-04-17 02:20:36 +04:00
2009-03-16 20:27:37 +03:00
udf_add_free_space ( sb , partition , - 1 ) ;
2005-04-17 02:20:36 +04:00
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
* err = 0 ;
return newblock ;
}
2008-10-15 14:29:03 +04:00
void udf_free_blocks ( struct super_block * sb , struct inode * inode ,
struct kernel_lb_addr * bloc , uint32_t offset ,
uint32_t count )
2005-04-17 02:20:36 +04:00
{
2008-10-15 14:29:03 +04:00
uint16_t partition = bloc - > partitionReferenceNum ;
2008-02-08 15:20:30 +03:00
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:30 +03:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP ) {
2012-02-16 16:00:14 +04:00
udf_bitmap_free_blocks ( sb , map - > s_uspace . s_bitmap ,
2008-12-01 15:06:10 +03:00
bloc , offset , count ) ;
2008-02-08 15:20:30 +03:00
} else if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE ) {
2012-02-16 16:00:14 +04:00
udf_table_free_blocks ( sb , map - > s_uspace . s_table ,
2008-12-01 15:06:10 +03:00
bloc , offset , count ) ;
2008-02-08 15:20:30 +03:00
} else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP ) {
2012-02-16 16:00:14 +04:00
udf_bitmap_free_blocks ( sb , map - > s_fspace . s_bitmap ,
2008-12-01 15:06:10 +03:00
bloc , offset , count ) ;
2008-02-08 15:20:30 +03:00
} else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE ) {
2012-02-16 16:00:14 +04:00
udf_table_free_blocks ( sb , map - > s_fspace . s_table ,
2008-12-01 15:06:10 +03:00
bloc , offset , count ) ;
2007-07-21 15:37:18 +04:00
}
2012-02-16 16:00:14 +04:00
if ( inode ) {
inode_sub_bytes ( inode ,
( ( sector_t ) count ) < < sb - > s_blocksize_bits ) ;
}
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
inline int udf_prealloc_blocks ( struct super_block * sb ,
struct inode * inode ,
uint16_t partition , uint32_t first_block ,
uint32_t block_count )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:30 +03:00
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2012-02-16 16:00:14 +04:00
sector_t allocated ;
2008-02-08 15:20:30 +03:00
2008-02-08 15:20:36 +03:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP )
2012-02-16 16:00:14 +04:00
allocated = udf_bitmap_prealloc_blocks ( sb ,
map - > s_uspace . s_bitmap ,
partition , first_block ,
block_count ) ;
2008-02-08 15:20:36 +03:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE )
2012-02-16 16:00:14 +04:00
allocated = udf_table_prealloc_blocks ( sb ,
map - > s_uspace . s_table ,
partition , first_block ,
block_count ) ;
2008-02-08 15:20:36 +03:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP )
2012-02-16 16:00:14 +04:00
allocated = udf_bitmap_prealloc_blocks ( sb ,
map - > s_fspace . s_bitmap ,
partition , first_block ,
block_count ) ;
2008-02-08 15:20:36 +03:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE )
2012-02-16 16:00:14 +04:00
allocated = udf_table_prealloc_blocks ( sb ,
map - > s_fspace . s_table ,
partition , first_block ,
block_count ) ;
2008-02-08 15:20:36 +03:00
else
2005-04-17 02:20:36 +04:00
return 0 ;
2012-02-16 16:00:14 +04:00
if ( inode & & allocated > 0 )
inode_add_bytes ( inode , allocated < < sb - > s_blocksize_bits ) ;
return allocated ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
inline int udf_new_block ( struct super_block * sb ,
struct inode * inode ,
uint16_t partition , uint32_t goal , int * err )
2005-04-17 02:20:36 +04:00
{
2008-02-08 15:20:30 +03:00
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2012-02-16 16:00:14 +04:00
int block ;
2007-05-08 11:35:16 +04:00
2008-02-08 15:20:36 +03:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP )
2012-02-16 16:00:14 +04:00
block = udf_bitmap_new_block ( sb ,
map - > s_uspace . s_bitmap ,
partition , goal , err ) ;
2008-02-08 15:20:36 +03:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE )
2012-02-16 16:00:14 +04:00
block = udf_table_new_block ( sb ,
map - > s_uspace . s_table ,
2007-07-21 15:37:18 +04:00
partition , goal , err ) ;
2012-02-16 16:00:14 +04:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP )
block = udf_bitmap_new_block ( sb ,
map - > s_fspace . s_bitmap ,
partition , goal , err ) ;
2008-02-08 15:20:36 +03:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE )
2012-02-16 16:00:14 +04:00
block = udf_table_new_block ( sb ,
map - > s_fspace . s_table ,
partition , goal , err ) ;
2008-02-08 15:20:36 +03:00
else {
2005-04-17 02:20:36 +04:00
* err = - EIO ;
return 0 ;
}
2012-02-16 16:00:14 +04:00
if ( inode & & block )
inode_add_bytes ( inode , sb - > s_blocksize ) ;
return block ;
2005-04-17 02:20:36 +04:00
}