2005-04-16 15:20:36 -07: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/quotaops.h>
# include <linux/buffer_head.h>
# include <linux/bitops.h>
# include "udf_i.h"
# include "udf_sb.h"
2008-02-08 04:20:36 -08:00
# define udf_clear_bit(nr, addr) ext2_clear_bit(nr, addr)
# define udf_set_bit(nr, addr) ext2_set_bit(nr, addr)
2005-04-16 15:20:36 -07:00
# define udf_test_bit(nr, addr) ext2_test_bit(nr, addr)
# define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size)
2008-02-08 04:20:36 -08:00
# define udf_find_next_one_bit(addr, size, offset) \
find_next_one_bit ( addr , size , offset )
2005-04-16 15:20:36 -07:00
# define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
2008-02-08 04:20:36 -08:00
# define leNUM_to_cpup(x, y) xleNUM_to_cpup(x, y)
# define xleNUM_to_cpup(x, y) (le ## x ## _to_cpup(y))
2005-04-16 15:20:36 -07:00
# define uintBPL_t uint(BITS_PER_LONG)
# define uint(x) xuint(x)
# define xuint(x) __le ## x
2007-07-19 01:47:43 -07:00
static inline int find_next_one_bit ( void * addr , int size , int offset )
2005-04-16 15:20:36 -07:00
{
2007-07-19 01:47:43 -07:00
uintBPL_t * p = ( ( uintBPL_t * ) addr ) + ( offset / BITS_PER_LONG ) ;
int result = offset & ~ ( BITS_PER_LONG - 1 ) ;
2005-04-16 15:20:36 -07:00
unsigned long tmp ;
if ( offset > = size )
return size ;
size - = result ;
2007-07-19 01:47:43 -07:00
offset & = ( BITS_PER_LONG - 1 ) ;
if ( offset ) {
2005-04-16 15:20:36 -07:00
tmp = leBPL_to_cpup ( p + + ) ;
tmp & = ~ 0UL < < offset ;
if ( size < BITS_PER_LONG )
goto found_first ;
if ( tmp )
goto found_middle ;
size - = BITS_PER_LONG ;
result + = BITS_PER_LONG ;
}
2007-07-19 01:47:43 -07:00
while ( size & ~ ( BITS_PER_LONG - 1 ) ) {
2008-02-08 04:20:36 -08:00
tmp = leBPL_to_cpup ( p + + ) ;
if ( tmp )
2005-04-16 15:20:36 -07:00
goto found_middle ;
result + = BITS_PER_LONG ;
size - = BITS_PER_LONG ;
}
if ( ! size )
return result ;
tmp = leBPL_to_cpup ( p ) ;
2007-07-21 04:37:18 -07:00
found_first :
2007-07-19 01:47:43 -07:00
tmp & = ~ 0UL > > ( BITS_PER_LONG - size ) ;
2007-07-21 04:37:18 -07:00
found_middle :
2005-04-16 15:20:36 -07:00
return result + ffz ( ~ tmp ) ;
}
# define find_first_one_bit(addr, size)\
find_next_one_bit ( ( addr ) , ( size ) , 0 )
2007-07-19 01:47:43 -07:00
static int read_block_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap , unsigned int block ,
unsigned long bitmap_nr )
2005-04-16 15:20:36 -07:00
{
struct buffer_head * bh = NULL ;
int retval = 0 ;
kernel_lb_addr loc ;
loc . logicalBlockNum = bitmap - > s_extPosition ;
2008-02-08 04:20:30 -08:00
loc . partitionReferenceNum = UDF_SB ( sb ) - > s_partition ;
2005-04-16 15:20:36 -07:00
bh = udf_tread ( sb , udf_get_lb_pblock ( sb , loc , block ) ) ;
2008-02-08 04:20:36 -08:00
if ( ! bh )
2005-04-16 15:20:36 -07:00
retval = - EIO ;
2008-02-08 04:20:36 -08:00
2005-04-16 15:20:36 -07:00
bitmap - > s_block_bitmap [ bitmap_nr ] = bh ;
return retval ;
}
2007-07-19 01:47:43 -07:00
static int __load_block_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap ,
unsigned int block_group )
2005-04-16 15:20:36 -07:00
{
int retval = 0 ;
int nr_groups = bitmap - > s_nr_groups ;
2007-07-19 01:47:43 -07:00
if ( block_group > = nr_groups ) {
udf_debug ( " block_group (%d) > nr_groups (%d) \n " , block_group ,
nr_groups ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-21 04:37:18 -07:00
if ( bitmap - > s_block_bitmap [ block_group ] ) {
2005-04-16 15:20:36 -07:00
return block_group ;
2007-07-21 04:37:18 -07:00
} else {
retval = read_block_bitmap ( sb , bitmap , block_group ,
block_group ) ;
2005-04-16 15:20:36 -07:00
if ( retval < 0 )
return retval ;
return block_group ;
}
}
2007-07-19 01:47:43 -07:00
static inline int load_block_bitmap ( struct super_block * sb ,
struct udf_bitmap * bitmap ,
unsigned int block_group )
2005-04-16 15:20:36 -07: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 ;
}
2008-02-08 04:20:40 -08:00
static bool udf_add_free_space ( struct udf_sb_info * sbi ,
u16 partition , u32 cnt )
{
struct logicalVolIntegrityDesc * lvid ;
2008-02-13 15:03:33 -08:00
if ( sbi - > s_lvid_bh = = NULL )
2008-02-08 04:20:40 -08:00
return false ;
lvid = ( struct logicalVolIntegrityDesc * ) sbi - > s_lvid_bh - > b_data ;
2008-01-30 22:03:57 +01:00
le32_add_cpu ( & lvid - > freeSpaceTable [ partition ] , cnt ) ;
2008-02-08 04:20:40 -08:00
return true ;
}
2007-07-19 01:47:43 -07:00
static void udf_bitmap_free_blocks ( struct super_block * sb ,
struct inode * inode ,
struct udf_bitmap * bitmap ,
kernel_lb_addr bloc , uint32_t offset ,
uint32_t count )
2005-04-16 15:20:36 -07:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2007-07-19 01:47:43 -07:00
struct buffer_head * bh = NULL ;
2005-04-16 15:20:36 -07:00
unsigned long block ;
unsigned long block_group ;
unsigned long bit ;
unsigned long i ;
int bitmap_nr ;
unsigned long overflow ;
2006-03-23 03:00:44 -08:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( bloc . logicalBlockNum < 0 | |
2008-02-08 04:20:36 -08:00
( bloc . logicalBlockNum + count ) >
sbi - > s_partmaps [ bloc . partitionReferenceNum ] . s_partition_len ) {
2007-07-21 04:37:18 -07:00
udf_debug ( " %d < %d || %d + %d > %d \n " ,
bloc . logicalBlockNum , 0 , bloc . logicalBlockNum , count ,
2008-02-08 04:20:36 -08:00
sbi - > s_partmaps [ bloc . partitionReferenceNum ] .
s_partition_len ) ;
2005-04-16 15:20:36 -07:00
goto error_return ;
}
2008-02-08 04:20:36 -08:00
block = bloc . logicalBlockNum + offset +
( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:41 -08: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-16 15:20:36 -07:00
}
2008-02-08 04:20:41 -08: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 " ,
( ( char * ) bh - > b_data ) [ ( bit + i ) > > 3 ] ) ;
} else {
if ( inode )
DQUOT_FREE_BLOCK ( inode , 1 ) ;
udf_add_free_space ( sbi , sbi - > s_partition , 1 ) ;
}
}
mark_buffer_dirty ( bh ) ;
if ( overflow ) {
block + = count ;
count = overflow ;
}
} while ( overflow ) ;
2007-07-21 04:37:18 -07:00
error_return :
2005-04-16 15:20:36 -07:00
sb - > s_dirt = 1 ;
2008-02-08 04:20:30 -08:00
if ( sbi - > s_lvid_bh )
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-19 01:47:43 -07:00
static int udf_bitmap_prealloc_blocks ( struct super_block * sb ,
struct inode * inode ,
struct udf_bitmap * bitmap ,
uint16_t partition , uint32_t first_block ,
uint32_t block_count )
2005-04-16 15:20:36 -07: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 04:20:30 -08:00
__u32 part_len ;
2005-04-16 15:20:36 -07:00
2006-03-23 03:00:44 -08:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-08 04:20:30 -08:00
part_len = sbi - > s_partmaps [ partition ] . s_partition_len ;
if ( first_block < 0 | | first_block > = part_len )
2005-04-16 15:20:36 -07:00
goto out ;
2008-02-08 04:20:30 -08:00
if ( first_block + block_count > part_len )
block_count = part_len - first_block ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:41 -08: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-16 15:20:36 -07:00
2008-02-08 04:20:41 -08: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-16 15:20:36 -07:00
2008-02-08 04:20:41 -08:00
bit = block % ( sb - > s_blocksize < < 3 ) ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:41 -08:00
while ( bit < ( sb - > s_blocksize < < 3 ) & & block_count > 0 ) {
if ( ! udf_test_bit ( bit , bh - > b_data ) )
goto out ;
else if ( DQUOT_PREALLOC_BLOCK ( inode , 1 ) )
goto out ;
else if ( ! udf_clear_bit ( bit , bh - > b_data ) ) {
udf_debug ( " bit already cleared for block %d \n " , bit ) ;
DQUOT_FREE_BLOCK ( inode , 1 ) ;
goto out ;
}
block_count - - ;
alloc_count + + ;
bit + + ;
block + + ;
2005-04-16 15:20:36 -07:00
}
2008-02-08 04:20:41 -08:00
mark_buffer_dirty ( bh ) ;
} while ( block_count > 0 ) ;
2007-07-21 04:37:18 -07:00
out :
2008-02-08 04:20:40 -08:00
if ( udf_add_free_space ( sbi , partition , - alloc_count ) )
2008-02-08 04:20:30 -08:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-16 15:20:36 -07:00
sb - > s_dirt = 1 ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
return alloc_count ;
}
2007-07-19 01:47:43 -07:00
static int udf_bitmap_new_block ( struct super_block * sb ,
struct inode * inode ,
struct udf_bitmap * bitmap , uint16_t partition ,
uint32_t goal , int * err )
2005-04-16 15:20:36 -07:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
2007-07-19 01:47:43 -07:00
int newbit , bit = 0 , block , block_group , group_start ;
2005-04-16 15:20:36 -07:00
int end_goal , nr_groups , bitmap_nr , i ;
struct buffer_head * bh = NULL ;
char * ptr ;
int newblock = 0 ;
* err = - ENOSPC ;
2006-03-23 03:00:44 -08:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
2007-07-21 04:37:18 -07:00
repeat :
2008-02-08 04:20:30 -08:00
if ( goal < 0 | | goal > = sbi - > s_partmaps [ partition ] . s_partition_len )
2005-04-16 15:20:36 -07: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 04:37:18 -07:00
ptr = memscan ( ( char * ) bh - > b_data + group_start , 0xFF ,
sb - > s_blocksize - group_start ) ;
2005-04-16 15:20:36 -07:00
2007-07-19 01:47:43 -07:00
if ( ( ptr - ( ( char * ) bh - > b_data ) ) < sb - > s_blocksize ) {
2005-04-16 15:20:36 -07:00
bit = block % ( sb - > s_blocksize < < 3 ) ;
2007-07-21 04:37:18 -07:00
if ( udf_test_bit ( bit , bh - > b_data ) )
2005-04-16 15:20:36 -07:00
goto got_block ;
2007-07-21 04:37:18 -07:00
2005-04-16 15:20:36 -07: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 04:37:18 -07:00
2008-02-08 04:20:36 -08:00
ptr = memscan ( ( char * ) bh - > b_data + ( bit > > 3 ) , 0xFF ,
sb - > s_blocksize - ( ( bit + 7 ) > > 3 ) ) ;
2005-04-16 15:20:36 -07:00
newbit = ( ptr - ( ( char * ) bh - > b_data ) ) < < 3 ;
2007-07-19 01:47:43 -07:00
if ( newbit < sb - > s_blocksize < < 3 ) {
2005-04-16 15:20:36 -07:00
bit = newbit ;
goto search_back ;
}
2007-07-21 04:37:18 -07:00
2008-02-08 04:20:36 -08:00
newbit = udf_find_next_one_bit ( bh - > b_data ,
sb - > s_blocksize < < 3 , bit ) ;
2007-07-19 01:47:43 -07:00
if ( newbit < sb - > s_blocksize < < 3 ) {
2005-04-16 15:20:36 -07:00
bit = newbit ;
goto got_block ;
}
}
2007-07-19 01:47:43 -07:00
for ( i = 0 ; i < ( nr_groups * 2 ) ; i + + ) {
block_group + + ;
2005-04-16 15:20:36 -07: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 01:47:43 -07:00
if ( i < nr_groups ) {
2007-07-21 04:37:18 -07:00
ptr = memscan ( ( char * ) bh - > b_data + group_start , 0xFF ,
sb - > s_blocksize - group_start ) ;
2007-07-19 01:47:43 -07:00
if ( ( ptr - ( ( char * ) bh - > b_data ) ) < sb - > s_blocksize ) {
2005-04-16 15:20:36 -07:00
bit = ( ptr - ( ( char * ) bh - > b_data ) ) < < 3 ;
break ;
}
2007-07-19 01:47:43 -07:00
} else {
2007-07-21 04:37:18 -07:00
bit = udf_find_next_one_bit ( ( char * ) bh - > b_data ,
sb - > s_blocksize < < 3 ,
group_start < < 3 ) ;
2005-04-16 15:20:36 -07:00
if ( bit < sb - > s_blocksize < < 3 )
break ;
}
}
2007-07-19 01:47:43 -07:00
if ( i > = ( nr_groups * 2 ) ) {
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
return newblock ;
}
if ( bit < sb - > s_blocksize < < 3 )
goto search_back ;
else
2008-02-08 04:20:36 -08:00
bit = udf_find_next_one_bit ( bh - > b_data , sb - > s_blocksize < < 3 ,
group_start < < 3 ) ;
2007-07-19 01:47:43 -07:00
if ( bit > = sb - > s_blocksize < < 3 ) {
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-21 04:37:18 -07:00
search_back :
2008-02-08 04:20:36 -08:00
i = 0 ;
while ( i < 7 & & bit > ( group_start < < 3 ) & &
udf_test_bit ( bit - 1 , bh - > b_data ) ) {
+ + i ;
- - bit ;
}
2005-04-16 15:20:36 -07:00
2007-07-21 04:37:18 -07:00
got_block :
2005-04-16 15:20:36 -07:00
/*
* Check quota for allocation of this block .
*/
2007-07-19 01:47:43 -07:00
if ( inode & & DQUOT_ALLOC_BLOCK ( inode , 1 ) ) {
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
* err = - EDQUOT ;
return 0 ;
}
newblock = bit + ( block_group < < ( sb - > s_blocksize_bits + 3 ) ) -
2007-07-21 04:37:18 -07:00
( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
2005-04-16 15:20:36 -07:00
2007-07-19 01:47:43 -07:00
if ( ! udf_clear_bit ( bit , bh - > b_data ) ) {
2005-04-16 15:20:36 -07:00
udf_debug ( " bit already cleared for block %d \n " , bit ) ;
goto repeat ;
}
mark_buffer_dirty ( bh ) ;
2008-02-08 04:20:40 -08:00
if ( udf_add_free_space ( sbi , partition , - 1 ) )
2008-02-08 04:20:30 -08:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-16 15:20:36 -07:00
sb - > s_dirt = 1 ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
* err = 0 ;
return newblock ;
2007-07-21 04:37:18 -07:00
error_return :
2005-04-16 15:20:36 -07:00
* err = - EIO ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-19 01:47:43 -07:00
static void udf_table_free_blocks ( struct super_block * sb ,
struct inode * inode ,
struct inode * table ,
kernel_lb_addr bloc , uint32_t offset ,
uint32_t count )
2005-04-16 15:20:36 -07:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
uint32_t start , end ;
2007-05-08 00:35:14 -07:00
uint32_t elen ;
kernel_lb_addr eloc ;
struct extent_position oepos , epos ;
2005-04-16 15:20:36 -07:00
int8_t etype ;
int i ;
2008-02-08 04:20:44 -08:00
struct udf_inode_info * iinfo ;
2005-04-16 15:20:36 -07:00
2006-03-23 03:00:44 -08:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
if ( bloc . logicalBlockNum < 0 | |
2008-02-08 04:20:36 -08:00
( bloc . logicalBlockNum + count ) >
sbi - > s_partmaps [ bloc . partitionReferenceNum ] . s_partition_len ) {
2007-07-21 04:37:18 -07:00
udf_debug ( " %d < %d || %d + %d > %d \n " ,
bloc . logicalBlockNum , 0 , bloc . logicalBlockNum , count ,
2008-02-08 04:20:36 -08:00
sbi - > s_partmaps [ bloc . partitionReferenceNum ] .
s_partition_len ) ;
2005-04-16 15:20:36 -07:00
goto error_return ;
}
2008-02-08 04:20:44 -08:00
iinfo = UDF_I ( table ) ;
2008-02-08 04:20:36 -08:00
/* We do this up front - There are some error conditions that
could occure , but . . oh well */
2005-04-16 15:20:36 -07:00
if ( inode )
DQUOT_FREE_BLOCK ( inode , count ) ;
2008-02-08 04:20:40 -08:00
if ( udf_add_free_space ( sbi , sbi - > s_partition , count ) )
2008-02-08 04:20:30 -08:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-16 15:20:36 -07:00
start = bloc . logicalBlockNum + offset ;
end = bloc . logicalBlockNum + offset + count - 1 ;
2007-05-08 00:35:14 -07:00
epos . offset = oepos . offset = sizeof ( struct unallocSpaceEntry ) ;
2005-04-16 15:20:36 -07:00
elen = 0 ;
2008-02-08 04:20:44 -08:00
epos . block = oepos . block = iinfo - > i_location ;
2007-05-08 00:35:14 -07:00
epos . bh = oepos . bh = NULL ;
2005-04-16 15:20:36 -07:00
2007-07-21 04:37:18 -07:00
while ( count & &
( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2008-02-08 04:20:36 -08: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 01:47:43 -07:00
} else {
2008-02-08 04:20:36 -08:00
elen = ( etype < < 30 ) |
( elen +
( count < < sb - > s_blocksize_bits ) ) ;
2005-04-16 15:20:36 -07:00
start + = count ;
count = 0 ;
}
2007-05-08 00:35:14 -07:00
udf_write_aext ( table , & oepos , eloc , elen , 1 ) ;
2007-07-19 01:47:43 -07:00
} else if ( eloc . logicalBlockNum = = ( end + 1 ) ) {
2008-02-08 04:20:36 -08: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 01:47:43 -07:00
} else {
2005-04-16 15:20:36 -07:00
eloc . logicalBlockNum = start ;
2008-02-08 04:20:36 -08:00
elen = ( etype < < 30 ) |
( elen +
( count < < sb - > s_blocksize_bits ) ) ;
2005-04-16 15:20:36 -07:00
end - = count ;
count = 0 ;
}
2007-05-08 00:35:14 -07:00
udf_write_aext ( table , & oepos , eloc , elen , 1 ) ;
2005-04-16 15:20:36 -07:00
}
2007-07-19 01:47:43 -07:00
if ( epos . bh ! = oepos . bh ) {
2005-04-16 15:20:36 -07:00
i = - 1 ;
2007-05-08 00:35:14 -07:00
oepos . block = epos . block ;
2007-05-08 00:35:16 -07:00
brelse ( oepos . bh ) ;
get_bh ( epos . bh ) ;
2007-05-08 00:35:14 -07:00
oepos . bh = epos . bh ;
oepos . offset = 0 ;
2007-07-21 04:37:18 -07:00
} else {
2007-05-08 00:35:14 -07:00
oepos . offset = epos . offset ;
2007-07-21 04:37:18 -07:00
}
2005-04-16 15:20:36 -07:00
}
2007-07-19 01:47:43 -07:00
if ( count ) {
2007-07-21 04:37:18 -07:00
/*
2008-02-08 04:20:36 -08: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 04:37:18 -07: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 01:47:43 -07:00
*/
2005-04-16 15:20:36 -07:00
int adsize ;
short_ad * sad = NULL ;
long_ad * lad = NULL ;
struct allocExtDesc * aed ;
eloc . logicalBlockNum = start ;
2007-07-21 04:37:18 -07:00
elen = EXT_RECORDED_ALLOCATED |
( count < < sb - > s_blocksize_bits ) ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:44 -08:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2005-04-16 15:20:36 -07:00
adsize = sizeof ( short_ad ) ;
2008-02-08 04:20:44 -08:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2005-04-16 15:20:36 -07:00
adsize = sizeof ( long_ad ) ;
2008-02-08 04:20:44 -08:00
else {
2007-05-08 00:35:16 -07:00
brelse ( oepos . bh ) ;
brelse ( epos . bh ) ;
2005-04-16 15:20:36 -07:00
goto error_return ;
}
2007-07-19 01:47:43 -07:00
if ( epos . offset + ( 2 * adsize ) > sb - > s_blocksize ) {
2005-04-16 15:20:36 -07:00
char * sptr , * dptr ;
int loffset ;
2007-07-19 01:47:43 -07:00
2007-05-08 00:35:16 -07:00
brelse ( oepos . bh ) ;
2007-05-08 00:35:14 -07:00
oepos = epos ;
2005-04-16 15:20:36 -07:00
/* Steal a block from the extent being free'd */
2007-05-08 00:35:14 -07:00
epos . block . logicalBlockNum = eloc . logicalBlockNum ;
2007-07-19 01:47:43 -07:00
eloc . logicalBlockNum + + ;
2005-04-16 15:20:36 -07:00
elen - = sb - > s_blocksize ;
2008-02-08 04:20:36 -08:00
epos . bh = udf_tread ( sb ,
udf_get_lb_pblock ( sb , epos . block , 0 ) ) ;
if ( ! epos . bh ) {
2007-05-08 00:35:16 -07:00
brelse ( oepos . bh ) ;
2005-04-16 15:20:36 -07:00
goto error_return ;
}
2007-05-08 00:35:14 -07:00
aed = ( struct allocExtDesc * ) ( epos . bh - > b_data ) ;
2008-02-08 04:20:36 -08:00
aed - > previousAllocExtLocation =
cpu_to_le32 ( oepos . block . logicalBlockNum ) ;
2007-07-19 01:47:43 -07:00
if ( epos . offset + adsize > sb - > s_blocksize ) {
2007-05-08 00:35:14 -07:00
loffset = epos . offset ;
2005-04-16 15:20:36 -07:00
aed - > lengthAllocDescs = cpu_to_le32 ( adsize ) ;
2008-02-08 04:20:44 -08:00
sptr = iinfo - > i_ext . i_data + epos . offset
2008-02-08 04:20:42 -08:00
- adsize ;
2008-02-08 04:20:36 -08:00
dptr = epos . bh - > b_data +
sizeof ( struct allocExtDesc ) ;
2005-04-16 15:20:36 -07:00
memcpy ( dptr , sptr , adsize ) ;
2008-02-08 04:20:36 -08:00
epos . offset = sizeof ( struct allocExtDesc ) +
adsize ;
2007-07-19 01:47:43 -07:00
} else {
2007-05-08 00:35:14 -07:00
loffset = epos . offset + adsize ;
2005-04-16 15:20:36 -07:00
aed - > lengthAllocDescs = cpu_to_le32 ( 0 ) ;
2007-07-19 01:47:43 -07:00
if ( oepos . bh ) {
2007-08-30 23:56:22 -07:00
sptr = oepos . bh - > b_data + epos . offset ;
2008-02-08 04:20:36 -08:00
aed = ( struct allocExtDesc * )
oepos . bh - > b_data ;
2008-01-30 22:03:57 +01:00
le32_add_cpu ( & aed - > lengthAllocDescs ,
adsize ) ;
2007-07-19 01:47:43 -07:00
} else {
2008-02-08 04:20:44 -08:00
sptr = iinfo - > i_ext . i_data +
2008-02-08 04:20:42 -08:00
epos . offset ;
2008-02-08 04:20:44 -08:00
iinfo - > i_lenAlloc + = adsize ;
2005-04-16 15:20:36 -07:00
mark_inode_dirty ( table ) ;
}
2007-08-30 23:56:22 -07:00
epos . offset = sizeof ( struct allocExtDesc ) ;
2005-04-16 15:20:36 -07:00
}
2008-02-08 04:20:30 -08:00
if ( sbi - > s_udfrev > = 0x0200 )
2008-02-08 04:20:36 -08:00
udf_new_tag ( epos . bh - > b_data , TAG_IDENT_AED ,
3 , 1 , epos . block . logicalBlockNum ,
sizeof ( tag ) ) ;
2005-04-16 15:20:36 -07:00
else
2008-02-08 04:20:36 -08:00
udf_new_tag ( epos . bh - > b_data , TAG_IDENT_AED ,
2 , 1 , epos . block . logicalBlockNum ,
sizeof ( tag ) ) ;
2007-07-21 04:37:18 -07:00
2008-02-08 04:20:44 -08:00
switch ( iinfo - > i_alloc_type ) {
2008-02-08 04:20:36 -08:00
case ICBTAG_FLAG_AD_SHORT :
sad = ( short_ad * ) sptr ;
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 :
lad = ( long_ad * ) sptr ;
lad - > extLength = cpu_to_le32 (
EXT_NEXT_EXTENT_ALLOCDECS |
sb - > s_blocksize ) ;
lad - > extLocation =
cpu_to_lelb ( epos . block ) ;
break ;
2005-04-16 15:20:36 -07:00
}
2007-07-19 01:47:43 -07:00
if ( oepos . bh ) {
2007-05-08 00:35:14 -07:00
udf_update_tag ( oepos . bh - > b_data , loffset ) ;
mark_buffer_dirty ( oepos . bh ) ;
2007-07-21 04:37:18 -07:00
} else {
2005-04-16 15:20:36 -07:00
mark_inode_dirty ( table ) ;
2007-07-21 04:37:18 -07:00
}
2005-04-16 15:20:36 -07:00
}
2008-02-08 04:20:36 -08:00
/* It's possible that stealing the block emptied the extent */
if ( elen ) {
2007-05-08 00:35:14 -07:00
udf_write_aext ( table , & epos , eloc , elen , 1 ) ;
2005-04-16 15:20:36 -07:00
2007-07-19 01:47:43 -07:00
if ( ! epos . bh ) {
2008-02-08 04:20:44 -08:00
iinfo - > i_lenAlloc + = adsize ;
2005-04-16 15:20:36 -07:00
mark_inode_dirty ( table ) ;
2007-07-19 01:47:43 -07:00
} else {
2007-05-08 00:35:14 -07:00
aed = ( struct allocExtDesc * ) epos . bh - > b_data ;
2008-01-30 22:03:57 +01:00
le32_add_cpu ( & aed - > lengthAllocDescs , adsize ) ;
2007-05-08 00:35:14 -07:00
udf_update_tag ( epos . bh - > b_data , epos . offset ) ;
mark_buffer_dirty ( epos . bh ) ;
2005-04-16 15:20:36 -07:00
}
}
}
2007-05-08 00:35:16 -07:00
brelse ( epos . bh ) ;
brelse ( oepos . bh ) ;
2005-04-16 15:20:36 -07:00
2007-07-21 04:37:18 -07:00
error_return :
2005-04-16 15:20:36 -07:00
sb - > s_dirt = 1 ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
return ;
}
2007-07-19 01:47:43 -07:00
static int udf_table_prealloc_blocks ( struct super_block * sb ,
struct inode * inode ,
struct inode * table , uint16_t partition ,
uint32_t first_block , uint32_t block_count )
2005-04-16 15:20:36 -07:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
int alloc_count = 0 ;
2007-05-08 00:35:14 -07:00
uint32_t elen , adsize ;
kernel_lb_addr eloc ;
struct extent_position epos ;
2005-04-16 15:20:36 -07:00
int8_t etype = - 1 ;
2008-02-08 04:20:44 -08:00
struct udf_inode_info * iinfo ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:36 -08:00
if ( first_block < 0 | |
first_block > = sbi - > s_partmaps [ partition ] . s_partition_len )
2005-04-16 15:20:36 -07:00
return 0 ;
2008-02-08 04:20:44 -08:00
iinfo = UDF_I ( table ) ;
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2005-04-16 15:20:36 -07:00
adsize = sizeof ( short_ad ) ;
2008-02-08 04:20:44 -08:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2005-04-16 15:20:36 -07:00
adsize = sizeof ( long_ad ) ;
else
return 0 ;
2006-03-23 03:00:44 -08:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2007-05-08 00:35:14 -07:00
epos . offset = sizeof ( struct unallocSpaceEntry ) ;
2008-02-08 04:20:44 -08:00
epos . block = iinfo - > i_location ;
2007-05-08 00:35:14 -07:00
epos . bh = NULL ;
2005-04-16 15:20:36 -07:00
eloc . logicalBlockNum = 0xFFFFFFFF ;
2007-07-21 04:37:18 -07:00
while ( first_block ! = eloc . logicalBlockNum & &
( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2005-04-16 15:20:36 -07:00
udf_debug ( " eloc=%d, elen=%d, first_block=%d \n " ,
2007-07-19 01:47:43 -07:00
eloc . logicalBlockNum , elen , first_block ) ;
2007-07-21 04:37:18 -07:00
; /* empty loop body */
2005-04-16 15:20:36 -07:00
}
2007-07-19 01:47:43 -07:00
if ( first_block = = eloc . logicalBlockNum ) {
2007-05-08 00:35:14 -07:00
epos . offset - = adsize ;
2005-04-16 15:20:36 -07:00
alloc_count = ( elen > > sb - > s_blocksize_bits ) ;
2008-02-08 04:20:36 -08:00
if ( inode & & DQUOT_PREALLOC_BLOCK ( inode ,
alloc_count > block_count ? block_count : alloc_count ) )
2005-04-16 15:20:36 -07:00
alloc_count = 0 ;
2008-02-08 04:20:36 -08:00
else if ( alloc_count > block_count ) {
2005-04-16 15:20:36 -07:00
alloc_count = block_count ;
eloc . logicalBlockNum + = alloc_count ;
elen - = ( alloc_count < < sb - > s_blocksize_bits ) ;
2008-02-08 04:20:36 -08:00
udf_write_aext ( table , & epos , eloc ,
( etype < < 30 ) | elen , 1 ) ;
} else
udf_delete_aext ( table , epos , eloc ,
( etype < < 30 ) | elen ) ;
2007-07-21 04:37:18 -07:00
} else {
2005-04-16 15:20:36 -07:00
alloc_count = 0 ;
2007-07-21 04:37:18 -07:00
}
2005-04-16 15:20:36 -07:00
2007-05-08 00:35:16 -07:00
brelse ( epos . bh ) ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:40 -08:00
if ( alloc_count & & udf_add_free_space ( sbi , partition , - alloc_count ) ) {
2008-02-08 04:20:30 -08:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-16 15:20:36 -07:00
sb - > s_dirt = 1 ;
}
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
return alloc_count ;
}
2007-07-19 01:47:43 -07:00
static int udf_table_new_block ( struct super_block * sb ,
struct inode * inode ,
struct inode * table , uint16_t partition ,
uint32_t goal , int * err )
2005-04-16 15:20:36 -07:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
uint32_t spread = 0xFFFFFFFF , nspread = 0xFFFFFFFF ;
uint32_t newblock = 0 , adsize ;
2007-05-08 00:35:14 -07:00
uint32_t elen , goal_elen = 0 ;
2007-10-16 23:30:17 -07:00
kernel_lb_addr eloc , uninitialized_var ( goal_eloc ) ;
2007-05-08 00:35:14 -07:00
struct extent_position epos , goal_epos ;
2005-04-16 15:20:36 -07:00
int8_t etype ;
2008-02-08 04:20:44 -08:00
struct udf_inode_info * iinfo = UDF_I ( table ) ;
2005-04-16 15:20:36 -07:00
* err = - ENOSPC ;
2008-02-08 04:20:44 -08:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_SHORT )
2005-04-16 15:20:36 -07:00
adsize = sizeof ( short_ad ) ;
2008-02-08 04:20:44 -08:00
else if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_LONG )
2005-04-16 15:20:36 -07:00
adsize = sizeof ( long_ad ) ;
else
return newblock ;
2006-03-23 03:00:44 -08:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2008-02-08 04:20:30 -08:00
if ( goal < 0 | | goal > = sbi - > s_partmaps [ partition ] . s_partition_len )
2005-04-16 15:20:36 -07:00
goal = 0 ;
2008-02-08 04:20:36 -08: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 01:47:43 -07:00
*/
2007-05-08 00:35:14 -07:00
epos . offset = sizeof ( struct unallocSpaceEntry ) ;
2008-02-08 04:20:44 -08:00
epos . block = iinfo - > i_location ;
2007-05-08 00:35:14 -07:00
epos . bh = goal_epos . bh = NULL ;
2005-04-16 15:20:36 -07:00
2007-07-21 04:37:18 -07:00
while ( spread & &
( etype = udf_next_aext ( table , & epos , & eloc , & elen , 1 ) ) ! = - 1 ) {
2007-07-19 01:47:43 -07:00
if ( goal > = eloc . logicalBlockNum ) {
2008-02-08 04:20:36 -08:00
if ( goal < eloc . logicalBlockNum +
( elen > > sb - > s_blocksize_bits ) )
2005-04-16 15:20:36 -07:00
nspread = 0 ;
else
nspread = goal - eloc . logicalBlockNum -
2007-07-21 04:37:18 -07:00
( elen > > sb - > s_blocksize_bits ) ;
} else {
2005-04-16 15:20:36 -07:00
nspread = eloc . logicalBlockNum - goal ;
2007-07-21 04:37:18 -07:00
}
2005-04-16 15:20:36 -07:00
2007-07-19 01:47:43 -07:00
if ( nspread < spread ) {
2005-04-16 15:20:36 -07:00
spread = nspread ;
2007-07-19 01:47:43 -07:00
if ( goal_epos . bh ! = epos . bh ) {
2007-05-08 00:35:16 -07:00
brelse ( goal_epos . bh ) ;
2007-05-08 00:35:14 -07:00
goal_epos . bh = epos . bh ;
2007-05-08 00:35:16 -07:00
get_bh ( goal_epos . bh ) ;
2005-04-16 15:20:36 -07:00
}
2007-05-08 00:35:14 -07:00
goal_epos . block = epos . block ;
goal_epos . offset = epos . offset - adsize ;
2005-04-16 15:20:36 -07:00
goal_eloc = eloc ;
goal_elen = ( etype < < 30 ) | elen ;
}
}
2007-05-08 00:35:16 -07:00
brelse ( epos . bh ) ;
2005-04-16 15:20:36 -07:00
2007-07-19 01:47:43 -07:00
if ( spread = = 0xFFFFFFFF ) {
2007-05-08 00:35:16 -07:00
brelse ( goal_epos . bh ) ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07: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 01:47:43 -07:00
goal_eloc . logicalBlockNum + + ;
2005-04-16 15:20:36 -07:00
goal_elen - = sb - > s_blocksize ;
2007-07-19 01:47:43 -07:00
if ( inode & & DQUOT_ALLOC_BLOCK ( inode , 1 ) ) {
2007-05-08 00:35:16 -07:00
brelse ( goal_epos . bh ) ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
* err = - EDQUOT ;
return 0 ;
}
if ( goal_elen )
2007-05-08 00:35:14 -07:00
udf_write_aext ( table , & goal_epos , goal_eloc , goal_elen , 1 ) ;
2005-04-16 15:20:36 -07:00
else
2007-05-08 00:35:14 -07:00
udf_delete_aext ( table , goal_epos , goal_eloc , goal_elen ) ;
2007-05-08 00:35:16 -07:00
brelse ( goal_epos . bh ) ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:40 -08:00
if ( udf_add_free_space ( sbi , partition , - 1 ) )
2008-02-08 04:20:30 -08:00
mark_buffer_dirty ( sbi - > s_lvid_bh ) ;
2005-04-16 15:20:36 -07:00
sb - > s_dirt = 1 ;
2006-03-23 03:00:44 -08:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-16 15:20:36 -07:00
* err = 0 ;
return newblock ;
}
2007-07-19 01:47:43 -07:00
inline void udf_free_blocks ( struct super_block * sb ,
struct inode * inode ,
kernel_lb_addr bloc , uint32_t offset ,
uint32_t count )
2005-04-16 15:20:36 -07:00
{
uint16_t partition = bloc . partitionReferenceNum ;
2008-02-08 04:20:30 -08:00
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2005-04-16 15:20:36 -07:00
2008-02-08 04:20:30 -08:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP ) {
2005-04-16 15:20:36 -07:00
return udf_bitmap_free_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_uspace . s_bitmap ,
2007-07-21 04:37:18 -07:00
bloc , offset , count ) ;
2008-02-08 04:20:30 -08:00
} else if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE ) {
2005-04-16 15:20:36 -07:00
return udf_table_free_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_uspace . s_table ,
2007-07-21 04:37:18 -07:00
bloc , offset , count ) ;
2008-02-08 04:20:30 -08:00
} else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP ) {
2005-04-16 15:20:36 -07:00
return udf_bitmap_free_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_fspace . s_bitmap ,
2007-07-21 04:37:18 -07:00
bloc , offset , count ) ;
2008-02-08 04:20:30 -08:00
} else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE ) {
2005-04-16 15:20:36 -07:00
return udf_table_free_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_fspace . s_table ,
2007-07-21 04:37:18 -07:00
bloc , offset , count ) ;
} else {
2005-04-16 15:20:36 -07:00
return ;
2007-07-21 04:37:18 -07:00
}
2005-04-16 15:20:36 -07:00
}
2007-07-19 01:47:43 -07: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-16 15:20:36 -07:00
{
2008-02-08 04:20:30 -08:00
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2008-02-08 04:20:36 -08:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP )
2005-04-16 15:20:36 -07:00
return udf_bitmap_prealloc_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_uspace . s_bitmap ,
2008-02-08 04:20:36 -08:00
partition , first_block ,
block_count ) ;
else if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE )
2005-04-16 15:20:36 -07:00
return udf_table_prealloc_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_uspace . s_table ,
2008-02-08 04:20:36 -08:00
partition , first_block ,
block_count ) ;
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP )
2005-04-16 15:20:36 -07:00
return udf_bitmap_prealloc_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_fspace . s_bitmap ,
2008-02-08 04:20:36 -08:00
partition , first_block ,
block_count ) ;
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE )
2005-04-16 15:20:36 -07:00
return udf_table_prealloc_blocks ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_fspace . s_table ,
2008-02-08 04:20:36 -08:00
partition , first_block ,
block_count ) ;
else
2005-04-16 15:20:36 -07:00
return 0 ;
}
2007-07-19 01:47:43 -07:00
inline int udf_new_block ( struct super_block * sb ,
struct inode * inode ,
uint16_t partition , uint32_t goal , int * err )
2005-04-16 15:20:36 -07:00
{
2008-02-08 04:20:30 -08:00
struct udf_part_map * map = & UDF_SB ( sb ) - > s_partmaps [ partition ] ;
2007-05-08 00:35:16 -07:00
2008-02-08 04:20:36 -08:00
if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP )
return udf_bitmap_new_block ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_uspace . s_bitmap ,
2007-07-21 04:37:18 -07:00
partition , goal , err ) ;
2008-02-08 04:20:36 -08:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE )
2005-04-16 15:20:36 -07:00
return udf_table_new_block ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_uspace . s_table ,
2007-07-21 04:37:18 -07:00
partition , goal , err ) ;
2008-02-08 04:20:36 -08:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_BITMAP )
2005-04-16 15:20:36 -07:00
return udf_bitmap_new_block ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_fspace . s_bitmap ,
2007-07-21 04:37:18 -07:00
partition , goal , err ) ;
2008-02-08 04:20:36 -08:00
else if ( map - > s_partition_flags & UDF_PART_FLAG_FREED_TABLE )
2005-04-16 15:20:36 -07:00
return udf_table_new_block ( sb , inode ,
2008-02-08 04:20:30 -08:00
map - > s_fspace . s_table ,
2007-07-21 04:37:18 -07:00
partition , goal , err ) ;
2008-02-08 04:20:36 -08:00
else {
2005-04-16 15:20:36 -07:00
* err = - EIO ;
return 0 ;
}
}