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/quotaops.h>
# include <linux/buffer_head.h>
# include <linux/bitops.h>
# include "udf_i.h"
# include "udf_sb.h"
# define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr)
# define udf_set_bit(nr,addr) ext2_set_bit(nr,addr)
# 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)
# define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset)
# define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x)
# define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y)
# define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y))
# define uintBPL_t uint(BITS_PER_LONG)
# define uint(x) xuint(x)
# define xuint(x) __le ## x
2007-07-19 12:47:43 +04:00
static inline int find_next_one_bit ( void * addr , int size , int offset )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
uintBPL_t * p = ( ( uintBPL_t * ) addr ) + ( offset / BITS_PER_LONG ) ;
int result = offset & ~ ( BITS_PER_LONG - 1 ) ;
2005-04-17 02:20:36 +04:00
unsigned long tmp ;
if ( offset > = size )
return size ;
size - = result ;
2007-07-19 12:47:43 +04:00
offset & = ( BITS_PER_LONG - 1 ) ;
if ( offset ) {
2005-04-17 02:20:36 +04: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 12:47:43 +04:00
while ( size & ~ ( BITS_PER_LONG - 1 ) ) {
2005-04-17 02:20:36 +04:00
if ( ( tmp = leBPL_to_cpup ( p + + ) ) )
goto found_middle ;
result + = BITS_PER_LONG ;
size - = BITS_PER_LONG ;
}
if ( ! size )
return result ;
tmp = leBPL_to_cpup ( p ) ;
2007-07-21 15:37:18 +04:00
found_first :
2007-07-19 12:47:43 +04:00
tmp & = ~ 0UL > > ( BITS_PER_LONG - size ) ;
2007-07-21 15:37:18 +04:00
found_middle :
2005-04-17 02:20:36 +04:00
return result + ffz ( ~ tmp ) ;
}
# define find_first_one_bit(addr, size)\
find_next_one_bit ( ( addr ) , ( size ) , 0 )
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 ;
kernel_lb_addr loc ;
loc . logicalBlockNum = bitmap - > s_extPosition ;
loc . partitionReferenceNum = UDF_SB_PARTITION ( sb ) ;
bh = udf_tread ( sb , udf_get_lb_pblock ( sb , loc , block ) ) ;
2007-07-19 12:47:43 +04:00
if ( ! bh ) {
2005-04-17 02:20:36 +04:00
retval = - EIO ;
}
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 ) {
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 ;
}
2007-07-19 12:47:43 +04: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-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 ;
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 ) ;
2005-04-17 02:20:36 +04:00
if ( bloc . logicalBlockNum < 0 | |
2007-07-21 15:37:18 +04:00
( bloc . logicalBlockNum + count ) > UDF_SB_PARTLEN ( sb , bloc . partitionReferenceNum ) ) {
udf_debug ( " %d < %d || %d + %d > %d \n " ,
bloc . logicalBlockNum , 0 , bloc . logicalBlockNum , count ,
UDF_SB_PARTLEN ( sb , bloc . partitionReferenceNum ) ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
}
2007-07-21 15:37:18 +04:00
block = bloc . logicalBlockNum + offset + ( sizeof ( struct spaceBitmapDesc ) < < 3 ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
do_more :
2005-04-17 02:20:36 +04:00
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 .
*/
2007-07-19 12:47:43 +04:00
if ( bit + count > ( sb - > s_blocksize < < 3 ) ) {
2005-04-17 02:20:36 +04:00
overflow = bit + count - ( sb - > s_blocksize < < 3 ) ;
count - = overflow ;
}
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
for ( i = 0 ; i < count ; i + + ) {
if ( udf_set_bit ( bit + i , bh - > b_data ) ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " bit %ld already set \n " , bit + i ) ;
2007-07-21 15:37:18 +04:00
udf_debug ( " byte=%2x \n " , ( ( char * ) bh - > b_data ) [ ( bit + i ) > > 3 ] ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
if ( inode )
DQUOT_FREE_BLOCK ( inode , 1 ) ;
2007-07-19 12:47:43 +04:00
if ( UDF_SB_LVIDBH ( sb ) ) {
2007-07-21 15:37:18 +04:00
UDF_SB_LVID ( sb ) - > freeSpaceTable [ UDF_SB_PARTITION ( sb ) ] =
cpu_to_le32 ( le32_to_cpu ( UDF_SB_LVID ( sb ) - > freeSpaceTable [ UDF_SB_PARTITION ( sb ) ] ) + 1 ) ;
2005-04-17 02:20:36 +04:00
}
}
}
mark_buffer_dirty ( bh ) ;
2007-07-19 12:47:43 +04:00
if ( overflow ) {
2005-04-17 02:20:36 +04:00
block + = count ;
count = overflow ;
goto do_more ;
}
2007-07-21 15:37:18 +04:00
error_return :
2005-04-17 02:20:36 +04:00
sb - > s_dirt = 1 ;
if ( UDF_SB_LVIDBH ( sb ) )
mark_buffer_dirty ( UDF_SB_LVIDBH ( sb ) ) ;
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_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-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 ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( first_block < 0 | | first_block > = UDF_SB_PARTLEN ( sb , partition ) )
goto out ;
if ( first_block + block_count > UDF_SB_PARTLEN ( sb , partition ) )
block_count = UDF_SB_PARTLEN ( sb , partition ) - first_block ;
2007-07-21 15:37:18 +04:00
repeat :
2005-04-17 02:20:36 +04:00
nr_groups = ( UDF_SB_PARTLEN ( sb , partition ) +
2007-07-19 12:47:43 +04:00
( sizeof ( struct spaceBitmapDesc ) < < 3 ) +
( sb - > s_blocksize * 8 ) - 1 ) / ( sb - > s_blocksize * 8 ) ;
2005-04-17 02:20:36 +04:00
block = first_block + ( 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 out ;
bh = bitmap - > s_block_bitmap [ bitmap_nr ] ;
bit = block % ( sb - > s_blocksize < < 3 ) ;
2007-07-19 12:47:43 +04:00
while ( bit < ( sb - > s_blocksize < < 3 ) & & block_count > 0 ) {
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 out ;
2007-07-21 15:37:18 +04:00
} else if ( DQUOT_PREALLOC_BLOCK ( inode , 1 ) ) {
2005-04-17 02:20:36 +04:00
goto out ;
2007-07-21 15:37:18 +04:00
} else 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 ) ;
DQUOT_FREE_BLOCK ( inode , 1 ) ;
goto out ;
}
2007-07-19 12:47:43 +04:00
block_count - - ;
alloc_count + + ;
bit + + ;
block + + ;
2005-04-17 02:20:36 +04:00
}
mark_buffer_dirty ( bh ) ;
if ( block_count > 0 )
goto repeat ;
2007-07-21 15:37:18 +04:00
out :
2007-07-19 12:47:43 +04:00
if ( UDF_SB_LVIDBH ( sb ) ) {
2005-04-17 02:20:36 +04:00
UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_cpu ( UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] ) - alloc_count ) ;
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( UDF_SB_LVIDBH ( sb ) ) ;
}
sb - > s_dirt = 1 ;
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 inode * inode ,
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 :
2005-04-17 02:20:36 +04:00
if ( goal < 0 | | goal > = UDF_SB_PARTLEN ( sb , partition ) )
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
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
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 {
2007-07-21 15:37:18 +04:00
bit = udf_find_next_one_bit ( ( char * ) bh - > b_data ,
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
2007-07-21 15:37:18 +04: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 :
for ( i = 0 ; i < 7 & & bit > ( group_start < < 3 ) & & udf_test_bit ( bit - 1 , bh - > b_data ) ; i + + , bit - - )
; /* empty loop */
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
/*
* Check quota for allocation of this block .
*/
2007-07-19 12:47:43 +04:00
if ( inode & & DQUOT_ALLOC_BLOCK ( inode , 1 ) ) {
2006-03-23 14:00:44 +03:00
mutex_unlock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
* err = - EDQUOT ;
return 0 ;
}
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 ) ;
2007-07-19 12:47:43 +04:00
if ( UDF_SB_LVIDBH ( sb ) ) {
2005-04-17 02:20:36 +04:00
UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_cpu ( UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] ) - 1 ) ;
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( UDF_SB_LVIDBH ( sb ) ) ;
}
sb - > s_dirt = 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 * inode ,
struct inode * table ,
kernel_lb_addr bloc , uint32_t offset ,
uint32_t count )
2005-04-17 02:20:36 +04:00
{
struct udf_sb_info * sbi = UDF_SB ( sb ) ;
uint32_t start , end ;
2007-05-08 11:35:14 +04:00
uint32_t elen ;
kernel_lb_addr eloc ;
struct extent_position oepos , epos ;
2005-04-17 02:20:36 +04:00
int8_t etype ;
int i ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( bloc . logicalBlockNum < 0 | |
2007-07-21 15:37:18 +04:00
( bloc . logicalBlockNum + count ) > UDF_SB_PARTLEN ( sb , bloc . partitionReferenceNum ) ) {
udf_debug ( " %d < %d || %d + %d > %d \n " ,
bloc . logicalBlockNum , 0 , bloc . logicalBlockNum , count ,
UDF_SB_PARTLEN ( sb , bloc . partitionReferenceNum ) ) ;
2005-04-17 02:20:36 +04:00
goto error_return ;
}
/* We do this up front - There are some error conditions that could occure,
but . . oh well */
if ( inode )
DQUOT_FREE_BLOCK ( inode , count ) ;
2007-07-19 12:47:43 +04:00
if ( UDF_SB_LVIDBH ( sb ) ) {
2005-04-17 02:20:36 +04:00
UDF_SB_LVID ( sb ) - > freeSpaceTable [ UDF_SB_PARTITION ( sb ) ] =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_cpu ( UDF_SB_LVID ( sb ) - > freeSpaceTable [ UDF_SB_PARTITION ( sb ) ] ) + count ) ;
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( UDF_SB_LVIDBH ( sb ) ) ;
}
start = bloc . logicalBlockNum + offset ;
end = bloc . logicalBlockNum + offset + count - 1 ;
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 ;
2007-05-08 11:35:14 +04:00
epos . block = oepos . block = UDF_I_LOCATION ( table ) ;
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 ) {
if ( ( ( eloc . logicalBlockNum + ( elen > > sb - > s_blocksize_bits ) ) = = start ) ) {
if ( ( 0x3FFFFFFF - elen ) < ( count < < sb - > s_blocksize_bits ) ) {
count - = ( ( 0x3FFFFFFF - elen ) > > sb - > s_blocksize_bits ) ;
start + = ( ( 0x3FFFFFFF - elen ) > > sb - > s_blocksize_bits ) ;
elen = ( etype < < 30 ) | ( 0x40000000 - sb - > s_blocksize ) ;
2007-07-19 12:47:43 +04:00
} else {
2007-07-21 15:37:18 +04:00
elen = ( etype < < 30 ) | ( elen + ( count < < sb - > s_blocksize_bits ) ) ;
2005-04-17 02:20:36 +04:00
start + = count ;
count = 0 ;
}
2007-05-08 11:35:14 +04:00
udf_write_aext ( table , & oepos , eloc , elen , 1 ) ;
2007-07-19 12:47:43 +04:00
} else if ( eloc . logicalBlockNum = = ( end + 1 ) ) {
2007-07-21 15:37:18 +04:00
if ( ( 0x3FFFFFFF - elen ) < ( count < < sb - > s_blocksize_bits ) ) {
count - = ( ( 0x3FFFFFFF - elen ) > > sb - > s_blocksize_bits ) ;
end - = ( ( 0x3FFFFFFF - elen ) > > sb - > s_blocksize_bits ) ;
eloc . logicalBlockNum - = ( ( 0x3FFFFFFF - elen ) > > sb - > s_blocksize_bits ) ;
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 ;
2007-07-21 15:37:18 +04:00
elen = ( etype < < 30 ) | ( elen + ( count < < sb - > s_blocksize_bits ) ) ;
2005-04-17 02:20:36 +04:00
end - = count ;
count = 0 ;
}
2007-05-08 11:35:14 +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
/*
* 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 : )
*
* 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 ;
short_ad * sad = NULL ;
long_ad * lad = NULL ;
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
2007-07-21 15:37:18 +04:00
if ( UDF_I_ALLOCTYPE ( table ) = = ICBTAG_FLAG_AD_SHORT ) {
2005-04-17 02:20:36 +04:00
adsize = sizeof ( short_ad ) ;
2007-07-21 15:37:18 +04:00
} else if ( UDF_I_ALLOCTYPE ( table ) = = ICBTAG_FLAG_AD_LONG ) {
2005-04-17 02:20:36 +04:00
adsize = sizeof ( long_ad ) ;
2007-07-21 15:37:18 +04: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 ) {
2005-04-17 02:20:36 +04:00
char * sptr , * dptr ;
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 ;
2007-07-21 15:37:18 +04:00
if ( ! ( epos . bh = udf_tread ( sb , udf_get_lb_pblock ( sb , epos . block , 0 ) ) ) ) {
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 ) ;
2007-07-21 15:37:18 +04: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 ) ;
2007-08-31 10:56:22 +04:00
sptr = UDF_I_DATA ( table ) + epos . offset - adsize ;
2007-07-21 15:37:18 +04:00
dptr = epos . bh - > b_data + sizeof ( struct allocExtDesc ) ;
2005-04-17 02:20:36 +04:00
memcpy ( dptr , sptr , adsize ) ;
2007-07-21 15:37:18 +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 ) ;
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 ;
2007-07-21 15:37:18 +04:00
aed = ( struct allocExtDesc * ) oepos . bh - > b_data ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_cpu ( aed - > lengthAllocDescs ) + adsize ) ;
2007-07-19 12:47:43 +04:00
} else {
2007-08-31 10:56:22 +04:00
sptr = UDF_I_DATA ( table ) + epos . offset ;
2005-04-17 02:20:36 +04:00
UDF_I_LENALLOC ( table ) + = adsize ;
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
}
if ( UDF_SB_UDFREV ( sb ) > = 0x0200 )
2007-07-21 15:37:18 +04:00
udf_new_tag ( epos . bh - > b_data , TAG_IDENT_AED , 3 , 1 ,
epos . block . logicalBlockNum , sizeof ( tag ) ) ;
2005-04-17 02:20:36 +04:00
else
2007-07-21 15:37:18 +04:00
udf_new_tag ( epos . bh - > b_data , TAG_IDENT_AED , 2 , 1 ,
epos . block . logicalBlockNum , sizeof ( tag ) ) ;
2007-07-19 12:47:43 +04:00
switch ( UDF_I_ALLOCTYPE ( table ) ) {
2007-07-21 15:37:18 +04: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 ) ;
2005-04-17 02:20:36 +04:00
break ;
2007-07-21 15:37:18 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
break ;
}
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
}
2007-07-21 15:37:18 +04:00
if ( elen ) { /* It's possible that stealing the block emptied the extent */
2007-05-08 11:35:14 +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 ) {
2005-04-17 02:20:36 +04:00
UDF_I_LENALLOC ( table ) + = adsize ;
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 ;
2005-04-17 02:20:36 +04:00
aed - > lengthAllocDescs =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_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 :
2005-04-17 02:20:36 +04:00
sb - > s_dirt = 1 ;
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 * inode ,
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 ;
kernel_lb_addr eloc ;
struct extent_position epos ;
2005-04-17 02:20:36 +04:00
int8_t etype = - 1 ;
if ( first_block < 0 | | first_block > = UDF_SB_PARTLEN ( sb , partition ) )
return 0 ;
if ( UDF_I_ALLOCTYPE ( table ) = = ICBTAG_FLAG_AD_SHORT )
adsize = sizeof ( short_ad ) ;
else if ( UDF_I_ALLOCTYPE ( table ) = = ICBTAG_FLAG_AD_LONG )
adsize = sizeof ( long_ad ) ;
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 ) ;
epos . block = UDF_I_LOCATION ( table ) ;
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 ) ;
2007-07-21 15:37:18 +04:00
if ( inode & & DQUOT_PREALLOC_BLOCK ( inode , alloc_count > block_count ? block_count : alloc_count ) ) {
2005-04-17 02:20:36 +04:00
alloc_count = 0 ;
2007-07-21 15:37:18 +04:00
} else 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 ) ;
2007-07-21 15:37:18 +04:00
udf_write_aext ( table , & epos , eloc , ( etype < < 30 ) | elen , 1 ) ;
} else {
udf_delete_aext ( table , epos , eloc , ( etype < < 30 ) | elen ) ;
}
} 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
2007-07-19 12:47:43 +04:00
if ( alloc_count & & UDF_SB_LVIDBH ( sb ) ) {
2005-04-17 02:20:36 +04:00
UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_cpu ( UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] ) - alloc_count ) ;
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( UDF_SB_LVIDBH ( sb ) ) ;
sb - > s_dirt = 1 ;
}
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 * inode ,
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 ;
2007-10-17 10:30:17 +04:00
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 ;
* err = - ENOSPC ;
if ( UDF_I_ALLOCTYPE ( table ) = = ICBTAG_FLAG_AD_SHORT )
adsize = sizeof ( short_ad ) ;
else if ( UDF_I_ALLOCTYPE ( table ) = = ICBTAG_FLAG_AD_LONG )
adsize = sizeof ( long_ad ) ;
else
return newblock ;
2006-03-23 14:00:44 +03:00
mutex_lock ( & sbi - > s_alloc_mutex ) ;
2005-04-17 02:20:36 +04:00
if ( goal < 0 | | goal > = UDF_SB_PARTLEN ( sb , partition ) )
goal = 0 ;
/* 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 ) ;
epos . block = UDF_I_LOCATION ( table ) ;
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 ) {
2007-07-21 15:37:18 +04: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 ;
2007-07-19 12:47:43 +04:00
if ( inode & & DQUOT_ALLOC_BLOCK ( inode , 1 ) ) {
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
* err = - EDQUOT ;
return 0 ;
}
if ( goal_elen )
2007-05-08 11:35:14 +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
2007-07-19 12:47:43 +04:00
if ( UDF_SB_LVIDBH ( sb ) ) {
2005-04-17 02:20:36 +04:00
UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] =
2007-07-21 15:37:18 +04:00
cpu_to_le32 ( le32_to_cpu ( UDF_SB_LVID ( sb ) - > freeSpaceTable [ partition ] ) - 1 ) ;
2005-04-17 02:20:36 +04:00
mark_buffer_dirty ( UDF_SB_LVIDBH ( sb ) ) ;
}
sb - > s_dirt = 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-19 12:47:43 +04: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-17 02:20:36 +04:00
{
uint16_t partition = bloc . partitionReferenceNum ;
2007-07-19 12:47:43 +04:00
if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_UNALLOC_BITMAP ) {
2005-04-17 02:20:36 +04:00
return udf_bitmap_free_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_uspace . s_bitmap ,
bloc , offset , count ) ;
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_UNALLOC_TABLE ) {
2005-04-17 02:20:36 +04:00
return udf_table_free_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_uspace . s_table ,
bloc , offset , count ) ;
2007-07-19 12:47:43 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_FREED_BITMAP ) {
2005-04-17 02:20:36 +04:00
return udf_bitmap_free_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_fspace . s_bitmap ,
bloc , offset , count ) ;
2007-07-19 12:47:43 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_FREED_TABLE ) {
2005-04-17 02:20:36 +04:00
return udf_table_free_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_fspace . s_table ,
bloc , offset , count ) ;
} else {
2005-04-17 02:20:36 +04:00
return ;
2007-07-21 15:37:18 +04:00
}
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
{
2007-07-19 12:47:43 +04:00
if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_UNALLOC_BITMAP ) {
2005-04-17 02:20:36 +04:00
return udf_bitmap_prealloc_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_uspace . s_bitmap ,
partition , first_block , block_count ) ;
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_UNALLOC_TABLE ) {
2005-04-17 02:20:36 +04:00
return udf_table_prealloc_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_uspace . s_table ,
partition , first_block , block_count ) ;
2007-07-19 12:47:43 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_FREED_BITMAP ) {
2005-04-17 02:20:36 +04:00
return udf_bitmap_prealloc_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_fspace . s_bitmap ,
partition , first_block , block_count ) ;
2007-07-19 12:47:43 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_FREED_TABLE ) {
2005-04-17 02:20:36 +04:00
return udf_table_prealloc_blocks ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_fspace . s_table ,
partition , first_block , block_count ) ;
} else {
2005-04-17 02:20:36 +04:00
return 0 ;
2007-07-21 15:37:18 +04:00
}
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
{
2007-05-08 11:35:16 +04:00
int ret ;
2007-07-19 12:47:43 +04:00
if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_UNALLOC_BITMAP ) {
2007-05-08 11:35:16 +04:00
ret = udf_bitmap_new_block ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_uspace . s_bitmap ,
partition , goal , err ) ;
2007-05-08 11:35:16 +04:00
return ret ;
2007-07-21 15:37:18 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_UNALLOC_TABLE ) {
2005-04-17 02:20:36 +04:00
return udf_table_new_block ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_uspace . s_table ,
partition , goal , err ) ;
2007-07-19 12:47:43 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_FREED_BITMAP ) {
2005-04-17 02:20:36 +04:00
return udf_bitmap_new_block ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_fspace . s_bitmap ,
partition , goal , err ) ;
2007-07-19 12:47:43 +04:00
} else if ( UDF_SB_PARTFLAGS ( sb , partition ) & UDF_PART_FLAG_FREED_TABLE ) {
2005-04-17 02:20:36 +04:00
return udf_table_new_block ( sb , inode ,
2007-07-21 15:37:18 +04:00
UDF_SB_PARTMAPS ( sb ) [ partition ] . s_fspace . s_table ,
partition , goal , err ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
* err = - EIO ;
return 0 ;
}
}