xref: /openbmc/linux/fs/udf/partition.c (revision d5cb9783536a41df9f9cba5b0a1d78047ed787f7)
1 /*
2  * partition.c
3  *
4  * PURPOSE
5  *      Partition handling routines for the OSTA-UDF(tm) filesystem.
6  *
7  * CONTACTS
8  *      E-mail regarding any portion of the Linux UDF file system should be
9  *      directed to the development team mailing list (run by majordomo):
10  *              linux_udf@hpesjro.fc.hp.com
11  *
12  * COPYRIGHT
13  *      This file is distributed under the terms of the GNU General Public
14  *      License (GPL). Copies of the GPL can be obtained from:
15  *              ftp://prep.ai.mit.edu/pub/gnu/GPL
16  *      Each contributing author retains all rights to their own work.
17  *
18  *  (C) 1998-2001 Ben Fennema
19  *
20  * HISTORY
21  *
22  * 12/06/98 blf  Created file.
23  *
24  */
25 
26 #include "udfdecl.h"
27 #include "udf_sb.h"
28 #include "udf_i.h"
29 
30 #include <linux/fs.h>
31 #include <linux/string.h>
32 #include <linux/udf_fs.h>
33 #include <linux/slab.h>
34 #include <linux/buffer_head.h>
35 
36 inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
37 {
38 	if (partition >= UDF_SB_NUMPARTS(sb))
39 	{
40 		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
41 			block, partition, offset);
42 		return 0xFFFFFFFF;
43 	}
44 	if (UDF_SB_PARTFUNC(sb, partition))
45 		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
46 	else
47 		return UDF_SB_PARTROOT(sb, partition) + block + offset;
48 }
49 
50 uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
51 {
52 	struct buffer_head *bh = NULL;
53 	uint32_t newblock;
54 	uint32_t index;
55 	uint32_t loc;
56 
57 	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
58 
59 	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
60 	{
61 		udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
62 			block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
63 		return 0xFFFFFFFF;
64 	}
65 
66 	if (block >= index)
67 	{
68 		block -= index;
69 		newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
70 		index = block % (sb->s_blocksize / sizeof(uint32_t));
71 	}
72 	else
73 	{
74 		newblock = 0;
75 		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
76 	}
77 
78 	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
79 
80 	if (!(bh = sb_bread(sb, loc)))
81 	{
82 		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
83 			sb, block, partition, loc, index);
84 		return 0xFFFFFFFF;
85 	}
86 
87 	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
88 
89 	udf_release_data(bh);
90 
91 	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
92 	{
93 		udf_debug("recursive call to udf_get_pblock!\n");
94 		return 0xFFFFFFFF;
95 	}
96 
97 	return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
98 }
99 
100 inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
101 {
102 	return udf_get_pblock_virt15(sb, block, partition, offset);
103 }
104 
105 uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
106 {
107 	int i;
108 	struct sparingTable *st = NULL;
109 	uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
110 
111 	for (i=0; i<4; i++)
112 	{
113 		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
114 		{
115 			st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
116 			break;
117 		}
118 	}
119 
120 	if (st)
121 	{
122 		for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
123 		{
124 			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
125 				break;
126 			else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
127 			{
128 				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
129 					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
130 			}
131 			else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
132 				break;
133 		}
134 	}
135 	return UDF_SB_PARTROOT(sb,partition) + block + offset;
136 }
137 
138 int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
139 {
140 	struct udf_sparing_data *sdata;
141 	struct sparingTable *st = NULL;
142 	struct sparingEntry mapEntry;
143 	uint32_t packet;
144 	int i, j, k, l;
145 
146 	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
147 	{
148 		if (old_block > UDF_SB_PARTROOT(sb,i) &&
149 		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
150 		{
151 			sdata = &UDF_SB_TYPESPAR(sb,i);
152 			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
153 
154 			for (j=0; j<4; j++)
155 			{
156 				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
157 				{
158 					st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
159 					break;
160 				}
161 			}
162 
163 			if (!st)
164 				return 1;
165 
166 			for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
167 			{
168 				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
169 				{
170 					for (; j<4; j++)
171 					{
172 						if (sdata->s_spar_map[j])
173 						{
174 							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
175 							st->mapEntry[k].origLocation = cpu_to_le32(packet);
176 							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
177 							mark_buffer_dirty(sdata->s_spar_map[j]);
178 						}
179 					}
180 					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
181 						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
182 					return 0;
183 				}
184 				else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
185 				{
186 					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
187 						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
188 					return 0;
189 				}
190 				else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
191 					break;
192 			}
193 			for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
194 			{
195 				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
196 				{
197 					for (; j<4; j++)
198 					{
199 						if (sdata->s_spar_map[j])
200 						{
201 							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
202 							mapEntry = st->mapEntry[l];
203 							mapEntry.origLocation = cpu_to_le32(packet);
204 							memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
205 							st->mapEntry[k] = mapEntry;
206 							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
207 							mark_buffer_dirty(sdata->s_spar_map[j]);
208 						}
209 					}
210 					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
211 						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
212 					return 0;
213 				}
214 			}
215 			return 1;
216 		}
217 	}
218 	if (i == UDF_SB_NUMPARTS(sb))
219 	{
220 		/* outside of partitions */
221 		/* for now, fail =) */
222 		return 1;
223 	}
224 
225 	return 0;
226 }
227