udf: Fix 64-bit sign extension issues affecting blocks > 0x7FFFFFFF
Large (> 1 TiB) UDF filesystems appear subject to several problems when mounted on 64-bit systems: * readdir() can fail on a directory containing File Identifiers residing above 0x7FFFFFFF. This manifests as a 'ls' command failing with EIO. * FIBMAP on a file block located above 0x7FFFFFFF can return a negative value. The low 32 bits are correct, but applications that don't mask the high 32 bits of the result can perform incorrectly. Per suggestion by Jan Kara, introduce a udf_pblk_t type for representation of UDF block addresses. Ultimately, all driver functions that manipulate UDF block addresses should use this type; for now, deployment is limited to functions with actual or potential sign extension issues. Changes to udf_readdir() and udf_block_map() address the issues noted above; other changes address potential similar issues uncovered during audit of the driver code. Signed-off-by: Steven J. Magnani <steve@digidescorp.com> Signed-off-by: Jan Kara <jack@suse.cz>
This commit is contained in:
@@ -218,16 +218,18 @@ out:
|
||||
return alloc_count;
|
||||
}
|
||||
|
||||
static int udf_bitmap_new_block(struct super_block *sb,
|
||||
static udf_pblk_t udf_bitmap_new_block(struct super_block *sb,
|
||||
struct udf_bitmap *bitmap, uint16_t partition,
|
||||
uint32_t goal, int *err)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
int newbit, bit = 0, block, block_group, group_start;
|
||||
int newbit, bit = 0;
|
||||
udf_pblk_t block;
|
||||
int block_group, group_start;
|
||||
int end_goal, nr_groups, bitmap_nr, i;
|
||||
struct buffer_head *bh = NULL;
|
||||
char *ptr;
|
||||
int newblock = 0;
|
||||
udf_pblk_t newblock = 0;
|
||||
|
||||
*err = -ENOSPC;
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
@@ -545,13 +547,14 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
|
||||
return alloc_count;
|
||||
}
|
||||
|
||||
static int udf_table_new_block(struct super_block *sb,
|
||||
static udf_pblk_t udf_table_new_block(struct super_block *sb,
|
||||
struct inode *table, uint16_t partition,
|
||||
uint32_t goal, int *err)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF;
|
||||
uint32_t newblock = 0, adsize;
|
||||
udf_pblk_t newblock = 0;
|
||||
uint32_t adsize;
|
||||
uint32_t elen, goal_elen = 0;
|
||||
struct kernel_lb_addr eloc, uninitialized_var(goal_eloc);
|
||||
struct extent_position epos, goal_epos;
|
||||
@@ -700,12 +703,12 @@ inline int udf_prealloc_blocks(struct super_block *sb,
|
||||
return allocated;
|
||||
}
|
||||
|
||||
inline int udf_new_block(struct super_block *sb,
|
||||
inline udf_pblk_t udf_new_block(struct super_block *sb,
|
||||
struct inode *inode,
|
||||
uint16_t partition, uint32_t goal, int *err)
|
||||
{
|
||||
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
|
||||
int block;
|
||||
udf_pblk_t block;
|
||||
|
||||
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
|
||||
block = udf_bitmap_new_block(sb,
|
||||
|
Reference in New Issue
Block a user