diff options
| author | Jan Kara <jack@suse.cz> | 2007-08-31 02:56:22 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-08-31 04:42:22 -0400 |
| commit | bcec44770cc65660369ae17b4e44be027a64a46c (patch) | |
| tree | 38424fde8e60f70c3bab7180c6dd90fc027f9103 | |
| parent | 989f89c57e6361e7d16fbd9572b5da7d313b073d (diff) | |
UDF: handle wrong superblock better
If UDF superblock is incorrect, we can fail to find a table of free /
allocated space and consequently Oops. Handle this situation more
gracefully by ignoring the broken UDF partition.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | fs/udf/super.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c index 382be7be5ae3..c68a6e730b97 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
| @@ -89,7 +89,7 @@ static int udf_find_fileset(struct super_block *, kernel_lb_addr *, | |||
| 89 | static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); | 89 | static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); |
| 90 | static void udf_load_fileset(struct super_block *, struct buffer_head *, | 90 | static void udf_load_fileset(struct super_block *, struct buffer_head *, |
| 91 | kernel_lb_addr *); | 91 | kernel_lb_addr *); |
| 92 | static void udf_load_partdesc(struct super_block *, struct buffer_head *); | 92 | static int udf_load_partdesc(struct super_block *, struct buffer_head *); |
| 93 | static void udf_open_lvid(struct super_block *); | 93 | static void udf_open_lvid(struct super_block *); |
| 94 | static void udf_close_lvid(struct super_block *); | 94 | static void udf_close_lvid(struct super_block *); |
| 95 | static unsigned int udf_count_free(struct super_block *); | 95 | static unsigned int udf_count_free(struct super_block *); |
| @@ -877,7 +877,7 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, | |||
| 877 | root->logicalBlockNum, root->partitionReferenceNum); | 877 | root->logicalBlockNum, root->partitionReferenceNum); |
| 878 | } | 878 | } |
| 879 | 879 | ||
| 880 | static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) | 880 | static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) |
| 881 | { | 881 | { |
| 882 | struct partitionDesc *p; | 882 | struct partitionDesc *p; |
| 883 | int i; | 883 | int i; |
| @@ -912,6 +912,11 @@ static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) | |||
| 912 | 912 | ||
| 913 | UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table = | 913 | UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table = |
| 914 | udf_iget(sb, loc); | 914 | udf_iget(sb, loc); |
| 915 | if (!UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table) { | ||
| 916 | udf_debug("cannot load unallocSpaceTable (part %d)\n", | ||
| 917 | i); | ||
| 918 | return 1; | ||
| 919 | } | ||
| 915 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE; | 920 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE; |
| 916 | udf_debug("unallocSpaceTable (part %d) @ %ld\n", | 921 | udf_debug("unallocSpaceTable (part %d) @ %ld\n", |
| 917 | i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino); | 922 | i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino); |
| @@ -938,6 +943,11 @@ static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) | |||
| 938 | 943 | ||
| 939 | UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table = | 944 | UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table = |
| 940 | udf_iget(sb, loc); | 945 | udf_iget(sb, loc); |
| 946 | if (!UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table) { | ||
| 947 | udf_debug("cannot load freedSpaceTable (part %d)\n", | ||
| 948 | i); | ||
| 949 | return 1; | ||
| 950 | } | ||
| 941 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE; | 951 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE; |
| 942 | udf_debug("freedSpaceTable (part %d) @ %ld\n", | 952 | udf_debug("freedSpaceTable (part %d) @ %ld\n", |
| 943 | i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino); | 953 | i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino); |
| @@ -966,6 +976,7 @@ static void udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) | |||
| 966 | le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i), | 976 | le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i), |
| 967 | UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i)); | 977 | UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i)); |
| 968 | } | 978 | } |
| 979 | return 0; | ||
| 969 | } | 980 | } |
| 970 | 981 | ||
| 971 | static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, | 982 | static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, |
| @@ -1177,12 +1188,19 @@ static int udf_process_sequence(struct super_block *sb, long block, long lastblo | |||
| 1177 | udf_load_logicalvol(sb, bh, fileset); | 1188 | udf_load_logicalvol(sb, bh, fileset); |
| 1178 | } else if (i == VDS_POS_PARTITION_DESC) { | 1189 | } else if (i == VDS_POS_PARTITION_DESC) { |
| 1179 | struct buffer_head *bh2 = NULL; | 1190 | struct buffer_head *bh2 = NULL; |
| 1180 | udf_load_partdesc(sb, bh); | 1191 | if (udf_load_partdesc(sb, bh)) { |
| 1192 | brelse(bh); | ||
| 1193 | return 1; | ||
| 1194 | } | ||
| 1181 | for (j = vds[i].block + 1; j < vds[VDS_POS_TERMINATING_DESC].block; j++) { | 1195 | for (j = vds[i].block + 1; j < vds[VDS_POS_TERMINATING_DESC].block; j++) { |
| 1182 | bh2 = udf_read_tagged(sb, j, j, &ident); | 1196 | bh2 = udf_read_tagged(sb, j, j, &ident); |
| 1183 | gd = (struct generic_desc *)bh2->b_data; | 1197 | gd = (struct generic_desc *)bh2->b_data; |
| 1184 | if (ident == TAG_IDENT_PD) | 1198 | if (ident == TAG_IDENT_PD) |
| 1185 | udf_load_partdesc(sb, bh2); | 1199 | if (udf_load_partdesc(sb, bh2)) { |
| 1200 | brelse(bh); | ||
| 1201 | brelse(bh2); | ||
| 1202 | return 1; | ||
| 1203 | } | ||
| 1186 | brelse(bh2); | 1204 | brelse(bh2); |
| 1187 | } | 1205 | } |
| 1188 | } | 1206 | } |
