patch-2.3.41 linux/fs/udf/partition.c

Next file: linux/fs/udf/super.c
Previous file: linux/fs/udf/namei.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.3.40/linux/fs/udf/partition.c linux/fs/udf/partition.c
@@ -30,161 +30,204 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/udf_fs.h>
+#include <linux/malloc.h>
 
-extern Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+inline Uint32 udf_get_pblock(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
 {
-	Uint16 ident;
-
 	if (partition >= UDF_SB_NUMPARTS(sb))
 	{
 		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
 			block, partition, offset);
 		return 0xFFFFFFFF;
 	}
-	switch (UDF_SB_PARTTYPE(sb, partition))
+	if (UDF_SB_PARTFUNC(sb, partition))
+		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
+	else
+		return UDF_SB_PARTROOT(sb, partition) + block + offset;
+}
+
+Uint32 udf_get_pblock_virt15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+	struct buffer_head *bh = NULL;
+	Uint32 newblock;
+	Uint32 index;
+	Uint32 loc;
+
+	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32);
+
+	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
 	{
-		case UDF_TYPE1_MAP15:
-		{
-			return UDF_SB_PARTROOT(sb, partition) + block + offset;
-		}
-		case UDF_VIRTUAL_MAP15:
-		case UDF_VIRTUAL_MAP20:
-		{
-			struct buffer_head *bh = NULL;
-			Uint32 newblock;
-			Uint32 index;
-			Uint32 loc;
+		udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
+			block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+		return 0xFFFFFFFF;
+	}
 
-			index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(Uint32);
+	if (block >= index)
+	{
+		block -= index;
+		newblock = 1 + (block / (sb->s_blocksize / sizeof(Uint32)));
+		index = block % (sb->s_blocksize / sizeof(Uint32));
+	}
+	else
+	{
+		newblock = 0;
+		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block;
+	}
 
+	loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock);
 
-			if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
-			{
-				udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
-					block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
-				return 0xFFFFFFFF;
-			}
+	if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
+	{
+		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
+			sb, block, partition, loc, index);
+		return 0xFFFFFFFF;
+	}
 
-			if (block >= index)
-			{
-				block -= index;
-				newblock = 1 + (block / (sb->s_blocksize / sizeof(Uint32)));
-				index = block % (sb->s_blocksize / sizeof(Uint32));
-			}
-			else
-			{
-				newblock = 0;
-				index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(Uint32) + block;
-			}
+	loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
 
-			loc = udf_locked_block_map(UDF_SB_VAT(sb), newblock);
+	udf_release_data(bh);
 
-			if (!(bh = bread(sb->s_dev, loc, sb->s_blocksize)))
-			{
-				udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
-					sb, block, partition, loc, index);
-				return 0xFFFFFFFF;
-			}
+	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
+	{
+		udf_debug("recursive call to udf_get_pblock!\n");
+		return 0xFFFFFFFF;
+	}
 
-			loc = le32_to_cpu(((Uint32 *)bh->b_data)[index]);
+	return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+}
 
-			udf_release_data(bh);
+inline Uint32 udf_get_pblock_virt20(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+	return udf_get_pblock_virt15(sb, block, partition, offset);
+}
 
-			if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
-			{
-				udf_debug("recursive call to udf_get_pblock!\n");
-				return 0xFFFFFFFF;
-			}
+Uint32 udf_get_pblock_spar15(struct super_block *sb, Uint32 block, Uint16 partition, Uint32 offset)
+{
+	Uint32 packet = (block + offset) >> UDF_SB_TYPESPAR(sb,partition).s_spar_pshift;
+	Uint32 index = 0;
 
-			return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
-		}
-		case UDF_SPARABLE_MAP15:
-		{
-			Uint32 newblock = UDF_SB_PARTROOT(sb, partition) + block + offset;
-			Uint32 spartable = UDF_SB_TYPESPAR(sb, partition).s_spar_loc;
-			Uint32 plength = UDF_SB_TYPESPAR(sb,partition).s_spar_plen;
-			Uint32 packet = (block + offset) & (~(plength-1));
-			struct buffer_head *bh = NULL;
-			struct SparingTable *st;
-			SparingEntry *se;
+	if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 8)
+		index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap8[packet];
+	else if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 16)
+		index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap16[packet];
+	else if (UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize == 32)
+		index = UDF_SB_TYPESPAR(sb,partition).s_spar_remap.s_spar_remap32[packet];
 
-			bh = udf_read_tagged(sb, spartable, spartable, &ident);
+	if (index == ((1 << UDF_SB_TYPESPAR(sb,partition).s_spar_indexsize)-1))
+		return UDF_SB_PARTROOT(sb,partition) + block + offset;
 
-			if (!bh)
-			{
-				printk(KERN_ERR "udf: udf_read_tagged(%p,%d,%d)\n",
-					sb, spartable, spartable);
-				return 0xFFFFFFFF;
-			}
+	packet = UDF_SB_TYPESPAR(sb,partition).s_spar_map[index];
+	return packet + ((block + offset) & ((1 << UDF_SB_TYPESPAR(sb,partition).s_spar_pshift)-1));
+}
+
+void udf_fill_spartable(struct super_block *sb, struct udf_sparing_data *sdata, int partlen)
+{
+	Uint16 ident;
+	Uint32 spartable;
+	int i;
+	struct buffer_head *bh;
+	struct SparingTable *st;
+
+	for (i=0; i<4; i++)
+	{
+		if (!(spartable = sdata->s_spar_loc[i]))
+			continue;
+
+		bh = udf_read_tagged(sb, spartable, spartable, &ident);
+
+		if (!bh)
+		{
+			sdata->s_spar_loc[i] = 0;
+			continue;
+		}
 
+		if (ident == 0)
+		{
 			st = (struct SparingTable *)bh->b_data;
-			if (ident == 0)
+			if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
 			{
-				if (!strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING)))
-				{
-					Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
-					Uint16 index;
+				SparingEntry *se;
+				Uint16 rtl = le16_to_cpu(st->reallocationTableLen);
+				int index;
 
-					/* If the sparing table span multiple blocks, find out which block we are on */
-
-					se = &(st->mapEntry[0]);
+				if (!sdata->s_spar_map)
+				{
+					int num = 1, mapsize;
+					sdata->s_spar_indexsize = 8;
+					while (rtl*sizeof(Uint32) >= (1 << sdata->s_spar_indexsize))
+					{
+						num ++;
+						sdata->s_spar_indexsize <<= 1;
+					}
+					mapsize = (rtl * sizeof(Uint32)) +
+						((partlen/(1 << sdata->s_spar_pshift)) * sizeof(Uint8) * num);
+					sdata->s_spar_map = kmalloc(mapsize, GFP_KERNEL);
+					sdata->s_spar_remap.s_spar_remap32 = &sdata->s_spar_map[rtl];
+					memset(sdata->s_spar_map, 0xFF, mapsize);
+				}
 
-					if (rtl * sizeof(SparingEntry) + sizeof(struct SparingTable) > sb->s_blocksize)
+				index = sizeof(struct SparingTable);
+				for (i=0; i<rtl; i++)
+				{
+					if (index > sb->s_blocksize)
 					{
-						index = (sb->s_blocksize - sizeof(struct SparingTable)) / sizeof(SparingEntry);
-						if (le32_to_cpu(se[index-1].origLocation) == packet)
+						udf_release_data(bh);
+						bh = udf_tread(sb, ++spartable, sb->s_blocksize);
+						if (!bh)
 						{
-							udf_release_data(bh);
-							return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+							sdata->s_spar_loc[i] = 0;
+							continue;
 						}
-						else if (le32_to_cpu(se[index-1].origLocation) < packet)
+						index = 0;
+					}
+					se = (SparingEntry *)&(bh->b_data[index]);
+					index += sizeof(SparingEntry);
+
+					if (sdata->s_spar_map[i] == 0xFFFFFFFF)
+						sdata->s_spar_map[i] = le32_to_cpu(se->mappedLocation);
+					else if (sdata->s_spar_map[i] != le32_to_cpu(se->mappedLocation))
+					{
+						udf_debug("Found conflicting Sparing Data (%d vs %d for entry %d)\n",
+							sdata->s_spar_map[i], le32_to_cpu(se->mappedLocation), i);
+					}
+
+					if (le32_to_cpu(se->origLocation) < 0xFFFFFFF0)
+					{
+						int packet = le32_to_cpu(se->origLocation) >> sdata->s_spar_pshift;
+						if (sdata->s_spar_indexsize == 8)
 						{
-							do
+							if (sdata->s_spar_remap.s_spar_remap8[packet] == 0xFF)
+								sdata->s_spar_remap.s_spar_remap8[packet] = i;
+							else if (sdata->s_spar_remap.s_spar_remap8[packet] != i)
 							{
-								udf_release_data(bh);
-								bh = udf_tread(sb, spartable, sb->s_blocksize);
-								if (!bh)
-									return 0xFFFFFFFF;
-								se = (SparingEntry *)bh->b_data;
-								spartable ++;
-								rtl -= index;
-								index = sb->s_blocksize / sizeof(SparingEntry);
-
-								if (le32_to_cpu(se[index].origLocation) == packet)
-								{
-									udf_release_data(bh);
-									return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
-								}
-							} while (rtl * sizeof(SparingEntry) > sb->s_blocksize && 
-								le32_to_cpu(se[index-1].origLocation) < packet);
+								udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
+									sdata->s_spar_remap.s_spar_remap8[packet], i);
+							}
 						}
-					}
-			
-					for (index=0; index<rtl; index++)
-					{
-						if (le32_to_cpu(se[index].origLocation) == packet)
+						else if (sdata->s_spar_indexsize == 16)
 						{
-							udf_release_data(bh);
-							return le32_to_cpu(se[index].mappedLocation) | (newblock & (plength-1));
+							if (sdata->s_spar_remap.s_spar_remap16[packet] == 0xFFFF)
+								sdata->s_spar_remap.s_spar_remap16[packet] = i;
+							else if (sdata->s_spar_remap.s_spar_remap16[packet] != i)
+							{
+								udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
+									sdata->s_spar_remap.s_spar_remap16[packet], i);
+							}
 						}
-						else if (le32_to_cpu(se[index].origLocation) > packet)
+						else if (sdata->s_spar_indexsize == 32)
 						{
-							udf_release_data(bh);
-							return newblock;
+							if (sdata->s_spar_remap.s_spar_remap32[packet] == 0xFFFFFFFF)
+								sdata->s_spar_remap.s_spar_remap32[packet] = i;
+							else if (sdata->s_spar_remap.s_spar_remap32[packet] != i)
+							{
+								udf_debug("Found conflicting Sparing Data (%d vs %d)\n",
+									sdata->s_spar_remap.s_spar_remap32[packet], i);
+							}
 						}
 					}
-
-					udf_release_data(bh);
-					return newblock;
 				}
 			}
-			udf_release_data(bh);
 		}
+		udf_release_data(bh);
 	}
-	return 0xFFFFFFFF;
-}
-
-extern Uint32 udf_get_lb_pblock(struct super_block *sb, lb_addr loc, Uint32 offset)
-{
-	return udf_get_pblock(sb, loc.logicalBlockNum, loc.partitionReferenceNum, offset);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)