Skip to content

Commit

Permalink
udf: Fix memory leak when mounting
Browse files Browse the repository at this point in the history
When we are mounting filesystem, we can load one partition table before
finding out that we cannot complete processing of logical volume descriptor
and trying the reserve descriptor. Free the table properly before trying
the reserve descriptor.

Signed-off-by: Jan Kara <jack@suse.cz>
  • Loading branch information
Jan Kara committed Jul 9, 2012
1 parent e124a32 commit bff943a
Showing 1 changed file with 64 additions and 58 deletions.
122 changes: 64 additions & 58 deletions fs/udf/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,63 @@ static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count)
return 0;
}

static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
{
int i;
int nr_groups = bitmap->s_nr_groups;
int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) *
nr_groups);

for (i = 0; i < nr_groups; i++)
if (bitmap->s_block_bitmap[i])
brelse(bitmap->s_block_bitmap[i]);

if (size <= PAGE_SIZE)
kfree(bitmap);
else
vfree(bitmap);
}

static void udf_free_partition(struct udf_part_map *map)
{
int i;
struct udf_meta_data *mdata;

if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
iput(map->s_uspace.s_table);
if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
iput(map->s_fspace.s_table);
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
udf_sb_free_bitmap(map->s_uspace.s_bitmap);
if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
udf_sb_free_bitmap(map->s_fspace.s_bitmap);
if (map->s_partition_type == UDF_SPARABLE_MAP15)
for (i = 0; i < 4; i++)
brelse(map->s_type_specific.s_sparing.s_spar_map[i]);
else if (map->s_partition_type == UDF_METADATA_MAP25) {
mdata = &map->s_type_specific.s_metadata;
iput(mdata->s_metadata_fe);
mdata->s_metadata_fe = NULL;

iput(mdata->s_mirror_fe);
mdata->s_mirror_fe = NULL;

iput(mdata->s_bitmap_fe);
mdata->s_bitmap_fe = NULL;
}
}

static void udf_sb_free_partitions(struct super_block *sb)
{
struct udf_sb_info *sbi = UDF_SB(sb);
int i;

for (i = 0; i < sbi->s_partitions; i++)
udf_free_partition(&sbi->s_partmaps[i]);
kfree(sbi->s_partmaps);
sbi->s_partmaps = NULL;
}

static int udf_show_options(struct seq_file *seq, struct dentry *root)
{
struct super_block *sb = root->d_sb;
Expand Down Expand Up @@ -1596,7 +1653,11 @@ static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh,
/* responsible for finding the PartitionDesc(s) */
if (!udf_process_sequence(sb, main_s, main_e, fileset))
return 1;
return !udf_process_sequence(sb, reserve_s, reserve_e, fileset);
udf_sb_free_partitions(sb);
if (!udf_process_sequence(sb, reserve_s, reserve_e, fileset))
return 1;
udf_sb_free_partitions(sb);
return 0;
}

/*
Expand Down Expand Up @@ -1861,55 +1922,8 @@ u64 lvid_get_unique_id(struct super_block *sb)
return ret;
}

static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
{
int i;
int nr_groups = bitmap->s_nr_groups;
int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) *
nr_groups);

for (i = 0; i < nr_groups; i++)
if (bitmap->s_block_bitmap[i])
brelse(bitmap->s_block_bitmap[i]);

if (size <= PAGE_SIZE)
kfree(bitmap);
else
vfree(bitmap);
}

static void udf_free_partition(struct udf_part_map *map)
{
int i;
struct udf_meta_data *mdata;

if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE)
iput(map->s_uspace.s_table);
if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE)
iput(map->s_fspace.s_table);
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP)
udf_sb_free_bitmap(map->s_uspace.s_bitmap);
if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP)
udf_sb_free_bitmap(map->s_fspace.s_bitmap);
if (map->s_partition_type == UDF_SPARABLE_MAP15)
for (i = 0; i < 4; i++)
brelse(map->s_type_specific.s_sparing.s_spar_map[i]);
else if (map->s_partition_type == UDF_METADATA_MAP25) {
mdata = &map->s_type_specific.s_metadata;
iput(mdata->s_metadata_fe);
mdata->s_metadata_fe = NULL;

iput(mdata->s_mirror_fe);
mdata->s_mirror_fe = NULL;

iput(mdata->s_bitmap_fe);
mdata->s_bitmap_fe = NULL;
}
}

static int udf_fill_super(struct super_block *sb, void *options, int silent)
{
int i;
int ret;
struct inode *inode = NULL;
struct udf_options uopt;
Expand Down Expand Up @@ -2071,18 +2085,14 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
error_out:
if (sbi->s_vat_inode)
iput(sbi->s_vat_inode);
if (sbi->s_partitions)
for (i = 0; i < sbi->s_partitions; i++)
udf_free_partition(&sbi->s_partmaps[i]);
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map);
#endif
if (!(sb->s_flags & MS_RDONLY))
udf_close_lvid(sb);
brelse(sbi->s_lvid_bh);

kfree(sbi->s_partmaps);
udf_sb_free_partitions(sb);
kfree(sbi);
sb->s_fs_info = NULL;

Expand Down Expand Up @@ -2123,24 +2133,20 @@ void _udf_warn(struct super_block *sb, const char *function,

static void udf_put_super(struct super_block *sb)
{
int i;
struct udf_sb_info *sbi;

sbi = UDF_SB(sb);

if (sbi->s_vat_inode)
iput(sbi->s_vat_inode);
if (sbi->s_partitions)
for (i = 0; i < sbi->s_partitions; i++)
udf_free_partition(&sbi->s_partmaps[i]);
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map);
#endif
if (!(sb->s_flags & MS_RDONLY))
udf_close_lvid(sb);
brelse(sbi->s_lvid_bh);
kfree(sbi->s_partmaps);
udf_sb_free_partitions(sb);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
}
Expand Down

0 comments on commit bff943a

Please sign in to comment.