udf: Fix memory leak when mounting
authorJan Kara <jack@suse.cz>
Wed, 27 Jun 2012 20:27:05 +0000 (22:27 +0200)
committerJan Kara <jack@suse.cz>
Mon, 9 Jul 2012 10:03:12 +0000 (12:03 +0200)
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>
fs/udf/super.c

index e7534fb..8a75838 100644 (file)
@@ -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;
@@ -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;
 }
 
 /*
@@ -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;
@@ -2071,9 +2085,6 @@ 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);
@@ -2081,8 +2092,7 @@ error_out:
        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;
 
@@ -2123,16 +2133,12 @@ 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);
@@ -2140,7 +2146,7 @@ static void udf_put_super(struct super_block *sb)
        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;
 }