1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * partition.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * PURPOSE
5*4882a593Smuzhiyun * Partition handling routines for the OSTA-UDF(tm) filesystem.
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * COPYRIGHT
8*4882a593Smuzhiyun * This file is distributed under the terms of the GNU General Public
9*4882a593Smuzhiyun * License (GPL). Copies of the GPL can be obtained from:
10*4882a593Smuzhiyun * ftp://prep.ai.mit.edu/pub/gnu/GPL
11*4882a593Smuzhiyun * Each contributing author retains all rights to their own work.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * (C) 1998-2001 Ben Fennema
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * HISTORY
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * 12/06/98 blf Created file.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun */
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "udfdecl.h"
22*4882a593Smuzhiyun #include "udf_sb.h"
23*4882a593Smuzhiyun #include "udf_i.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #include <linux/fs.h>
26*4882a593Smuzhiyun #include <linux/string.h>
27*4882a593Smuzhiyun #include <linux/mutex.h>
28*4882a593Smuzhiyun
udf_get_pblock(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)29*4882a593Smuzhiyun uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
30*4882a593Smuzhiyun uint16_t partition, uint32_t offset)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun struct udf_sb_info *sbi = UDF_SB(sb);
33*4882a593Smuzhiyun struct udf_part_map *map;
34*4882a593Smuzhiyun if (partition >= sbi->s_partitions) {
35*4882a593Smuzhiyun udf_debug("block=%u, partition=%u, offset=%u: invalid partition\n",
36*4882a593Smuzhiyun block, partition, offset);
37*4882a593Smuzhiyun return 0xFFFFFFFF;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun map = &sbi->s_partmaps[partition];
40*4882a593Smuzhiyun if (map->s_partition_func)
41*4882a593Smuzhiyun return map->s_partition_func(sb, block, partition, offset);
42*4882a593Smuzhiyun else
43*4882a593Smuzhiyun return map->s_partition_root + block + offset;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
udf_get_pblock_virt15(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)46*4882a593Smuzhiyun uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
47*4882a593Smuzhiyun uint16_t partition, uint32_t offset)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun struct buffer_head *bh = NULL;
50*4882a593Smuzhiyun uint32_t newblock;
51*4882a593Smuzhiyun uint32_t index;
52*4882a593Smuzhiyun uint32_t loc;
53*4882a593Smuzhiyun struct udf_sb_info *sbi = UDF_SB(sb);
54*4882a593Smuzhiyun struct udf_part_map *map;
55*4882a593Smuzhiyun struct udf_virtual_data *vdata;
56*4882a593Smuzhiyun struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun map = &sbi->s_partmaps[partition];
59*4882a593Smuzhiyun vdata = &map->s_type_specific.s_virtual;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun if (block > vdata->s_num_entries) {
62*4882a593Smuzhiyun udf_debug("Trying to access block beyond end of VAT (%u max %u)\n",
63*4882a593Smuzhiyun block, vdata->s_num_entries);
64*4882a593Smuzhiyun return 0xFFFFFFFF;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
68*4882a593Smuzhiyun loc = le32_to_cpu(((__le32 *)(iinfo->i_data +
69*4882a593Smuzhiyun vdata->s_start_offset))[block]);
70*4882a593Smuzhiyun goto translate;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
73*4882a593Smuzhiyun if (block >= index) {
74*4882a593Smuzhiyun block -= index;
75*4882a593Smuzhiyun newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
76*4882a593Smuzhiyun index = block % (sb->s_blocksize / sizeof(uint32_t));
77*4882a593Smuzhiyun } else {
78*4882a593Smuzhiyun newblock = 0;
79*4882a593Smuzhiyun index = vdata->s_start_offset / sizeof(uint32_t) + block;
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun loc = udf_block_map(sbi->s_vat_inode, newblock);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun bh = sb_bread(sb, loc);
85*4882a593Smuzhiyun if (!bh) {
86*4882a593Smuzhiyun udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%u,%u) VAT: %u[%u]\n",
87*4882a593Smuzhiyun sb, block, partition, loc, index);
88*4882a593Smuzhiyun return 0xFFFFFFFF;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun brelse(bh);
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun translate:
96*4882a593Smuzhiyun if (iinfo->i_location.partitionReferenceNum == partition) {
97*4882a593Smuzhiyun udf_debug("recursive call to udf_get_pblock!\n");
98*4882a593Smuzhiyun return 0xFFFFFFFF;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun return udf_get_pblock(sb, loc,
102*4882a593Smuzhiyun iinfo->i_location.partitionReferenceNum,
103*4882a593Smuzhiyun offset);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
udf_get_pblock_virt20(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)106*4882a593Smuzhiyun inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
107*4882a593Smuzhiyun uint16_t partition, uint32_t offset)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun return udf_get_pblock_virt15(sb, block, partition, offset);
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun
udf_get_pblock_spar15(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)112*4882a593Smuzhiyun uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
113*4882a593Smuzhiyun uint16_t partition, uint32_t offset)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun int i;
116*4882a593Smuzhiyun struct sparingTable *st = NULL;
117*4882a593Smuzhiyun struct udf_sb_info *sbi = UDF_SB(sb);
118*4882a593Smuzhiyun struct udf_part_map *map;
119*4882a593Smuzhiyun uint32_t packet;
120*4882a593Smuzhiyun struct udf_sparing_data *sdata;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun map = &sbi->s_partmaps[partition];
123*4882a593Smuzhiyun sdata = &map->s_type_specific.s_sparing;
124*4882a593Smuzhiyun packet = (block + offset) & ~(sdata->s_packet_len - 1);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
127*4882a593Smuzhiyun if (sdata->s_spar_map[i] != NULL) {
128*4882a593Smuzhiyun st = (struct sparingTable *)
129*4882a593Smuzhiyun sdata->s_spar_map[i]->b_data;
130*4882a593Smuzhiyun break;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (st) {
135*4882a593Smuzhiyun for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
136*4882a593Smuzhiyun struct sparingEntry *entry = &st->mapEntry[i];
137*4882a593Smuzhiyun u32 origLoc = le32_to_cpu(entry->origLocation);
138*4882a593Smuzhiyun if (origLoc >= 0xFFFFFFF0)
139*4882a593Smuzhiyun break;
140*4882a593Smuzhiyun else if (origLoc == packet)
141*4882a593Smuzhiyun return le32_to_cpu(entry->mappedLocation) +
142*4882a593Smuzhiyun ((block + offset) &
143*4882a593Smuzhiyun (sdata->s_packet_len - 1));
144*4882a593Smuzhiyun else if (origLoc > packet)
145*4882a593Smuzhiyun break;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun return map->s_partition_root + block + offset;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
udf_relocate_blocks(struct super_block * sb,long old_block,long * new_block)152*4882a593Smuzhiyun int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun struct udf_sparing_data *sdata;
155*4882a593Smuzhiyun struct sparingTable *st = NULL;
156*4882a593Smuzhiyun struct sparingEntry mapEntry;
157*4882a593Smuzhiyun uint32_t packet;
158*4882a593Smuzhiyun int i, j, k, l;
159*4882a593Smuzhiyun struct udf_sb_info *sbi = UDF_SB(sb);
160*4882a593Smuzhiyun u16 reallocationTableLen;
161*4882a593Smuzhiyun struct buffer_head *bh;
162*4882a593Smuzhiyun int ret = 0;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun mutex_lock(&sbi->s_alloc_mutex);
165*4882a593Smuzhiyun for (i = 0; i < sbi->s_partitions; i++) {
166*4882a593Smuzhiyun struct udf_part_map *map = &sbi->s_partmaps[i];
167*4882a593Smuzhiyun if (old_block > map->s_partition_root &&
168*4882a593Smuzhiyun old_block < map->s_partition_root + map->s_partition_len) {
169*4882a593Smuzhiyun sdata = &map->s_type_specific.s_sparing;
170*4882a593Smuzhiyun packet = (old_block - map->s_partition_root) &
171*4882a593Smuzhiyun ~(sdata->s_packet_len - 1);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun for (j = 0; j < 4; j++)
174*4882a593Smuzhiyun if (sdata->s_spar_map[j] != NULL) {
175*4882a593Smuzhiyun st = (struct sparingTable *)
176*4882a593Smuzhiyun sdata->s_spar_map[j]->b_data;
177*4882a593Smuzhiyun break;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (!st) {
181*4882a593Smuzhiyun ret = 1;
182*4882a593Smuzhiyun goto out;
183*4882a593Smuzhiyun }
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun reallocationTableLen =
186*4882a593Smuzhiyun le16_to_cpu(st->reallocationTableLen);
187*4882a593Smuzhiyun for (k = 0; k < reallocationTableLen; k++) {
188*4882a593Smuzhiyun struct sparingEntry *entry = &st->mapEntry[k];
189*4882a593Smuzhiyun u32 origLoc = le32_to_cpu(entry->origLocation);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun if (origLoc == 0xFFFFFFFF) {
192*4882a593Smuzhiyun for (; j < 4; j++) {
193*4882a593Smuzhiyun int len;
194*4882a593Smuzhiyun bh = sdata->s_spar_map[j];
195*4882a593Smuzhiyun if (!bh)
196*4882a593Smuzhiyun continue;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun st = (struct sparingTable *)
199*4882a593Smuzhiyun bh->b_data;
200*4882a593Smuzhiyun entry->origLocation =
201*4882a593Smuzhiyun cpu_to_le32(packet);
202*4882a593Smuzhiyun len =
203*4882a593Smuzhiyun sizeof(struct sparingTable) +
204*4882a593Smuzhiyun reallocationTableLen *
205*4882a593Smuzhiyun sizeof(struct sparingEntry);
206*4882a593Smuzhiyun udf_update_tag((char *)st, len);
207*4882a593Smuzhiyun mark_buffer_dirty(bh);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun *new_block = le32_to_cpu(
210*4882a593Smuzhiyun entry->mappedLocation) +
211*4882a593Smuzhiyun ((old_block -
212*4882a593Smuzhiyun map->s_partition_root) &
213*4882a593Smuzhiyun (sdata->s_packet_len - 1));
214*4882a593Smuzhiyun ret = 0;
215*4882a593Smuzhiyun goto out;
216*4882a593Smuzhiyun } else if (origLoc == packet) {
217*4882a593Smuzhiyun *new_block = le32_to_cpu(
218*4882a593Smuzhiyun entry->mappedLocation) +
219*4882a593Smuzhiyun ((old_block -
220*4882a593Smuzhiyun map->s_partition_root) &
221*4882a593Smuzhiyun (sdata->s_packet_len - 1));
222*4882a593Smuzhiyun ret = 0;
223*4882a593Smuzhiyun goto out;
224*4882a593Smuzhiyun } else if (origLoc > packet)
225*4882a593Smuzhiyun break;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun for (l = k; l < reallocationTableLen; l++) {
229*4882a593Smuzhiyun struct sparingEntry *entry = &st->mapEntry[l];
230*4882a593Smuzhiyun u32 origLoc = le32_to_cpu(entry->origLocation);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun if (origLoc != 0xFFFFFFFF)
233*4882a593Smuzhiyun continue;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun for (; j < 4; j++) {
236*4882a593Smuzhiyun bh = sdata->s_spar_map[j];
237*4882a593Smuzhiyun if (!bh)
238*4882a593Smuzhiyun continue;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun st = (struct sparingTable *)bh->b_data;
241*4882a593Smuzhiyun mapEntry = st->mapEntry[l];
242*4882a593Smuzhiyun mapEntry.origLocation =
243*4882a593Smuzhiyun cpu_to_le32(packet);
244*4882a593Smuzhiyun memmove(&st->mapEntry[k + 1],
245*4882a593Smuzhiyun &st->mapEntry[k],
246*4882a593Smuzhiyun (l - k) *
247*4882a593Smuzhiyun sizeof(struct sparingEntry));
248*4882a593Smuzhiyun st->mapEntry[k] = mapEntry;
249*4882a593Smuzhiyun udf_update_tag((char *)st,
250*4882a593Smuzhiyun sizeof(struct sparingTable) +
251*4882a593Smuzhiyun reallocationTableLen *
252*4882a593Smuzhiyun sizeof(struct sparingEntry));
253*4882a593Smuzhiyun mark_buffer_dirty(bh);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun *new_block =
256*4882a593Smuzhiyun le32_to_cpu(
257*4882a593Smuzhiyun st->mapEntry[k].mappedLocation) +
258*4882a593Smuzhiyun ((old_block - map->s_partition_root) &
259*4882a593Smuzhiyun (sdata->s_packet_len - 1));
260*4882a593Smuzhiyun ret = 0;
261*4882a593Smuzhiyun goto out;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun ret = 1;
265*4882a593Smuzhiyun goto out;
266*4882a593Smuzhiyun } /* if old_block */
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun if (i == sbi->s_partitions) {
270*4882a593Smuzhiyun /* outside of partitions */
271*4882a593Smuzhiyun /* for now, fail =) */
272*4882a593Smuzhiyun ret = 1;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun out:
276*4882a593Smuzhiyun mutex_unlock(&sbi->s_alloc_mutex);
277*4882a593Smuzhiyun return ret;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
udf_try_read_meta(struct inode * inode,uint32_t block,uint16_t partition,uint32_t offset)280*4882a593Smuzhiyun static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
281*4882a593Smuzhiyun uint16_t partition, uint32_t offset)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun struct super_block *sb = inode->i_sb;
284*4882a593Smuzhiyun struct udf_part_map *map;
285*4882a593Smuzhiyun struct kernel_lb_addr eloc;
286*4882a593Smuzhiyun uint32_t elen;
287*4882a593Smuzhiyun sector_t ext_offset;
288*4882a593Smuzhiyun struct extent_position epos = {};
289*4882a593Smuzhiyun uint32_t phyblock;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
292*4882a593Smuzhiyun (EXT_RECORDED_ALLOCATED >> 30))
293*4882a593Smuzhiyun phyblock = 0xFFFFFFFF;
294*4882a593Smuzhiyun else {
295*4882a593Smuzhiyun map = &UDF_SB(sb)->s_partmaps[partition];
296*4882a593Smuzhiyun /* map to sparable/physical partition desc */
297*4882a593Smuzhiyun phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
298*4882a593Smuzhiyun map->s_type_specific.s_metadata.s_phys_partition_ref,
299*4882a593Smuzhiyun ext_offset + offset);
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun brelse(epos.bh);
303*4882a593Smuzhiyun return phyblock;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
udf_get_pblock_meta25(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)306*4882a593Smuzhiyun uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
307*4882a593Smuzhiyun uint16_t partition, uint32_t offset)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct udf_sb_info *sbi = UDF_SB(sb);
310*4882a593Smuzhiyun struct udf_part_map *map;
311*4882a593Smuzhiyun struct udf_meta_data *mdata;
312*4882a593Smuzhiyun uint32_t retblk;
313*4882a593Smuzhiyun struct inode *inode;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun udf_debug("READING from METADATA\n");
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun map = &sbi->s_partmaps[partition];
318*4882a593Smuzhiyun mdata = &map->s_type_specific.s_metadata;
319*4882a593Smuzhiyun inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun if (!inode)
322*4882a593Smuzhiyun return 0xFFFFFFFF;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun retblk = udf_try_read_meta(inode, block, partition, offset);
325*4882a593Smuzhiyun if (retblk == 0xFFFFFFFF && mdata->s_metadata_fe) {
326*4882a593Smuzhiyun udf_warn(sb, "error reading from METADATA, trying to read from MIRROR\n");
327*4882a593Smuzhiyun if (!(mdata->s_flags & MF_MIRROR_FE_LOADED)) {
328*4882a593Smuzhiyun mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
329*4882a593Smuzhiyun mdata->s_mirror_file_loc,
330*4882a593Smuzhiyun mdata->s_phys_partition_ref);
331*4882a593Smuzhiyun if (IS_ERR(mdata->s_mirror_fe))
332*4882a593Smuzhiyun mdata->s_mirror_fe = NULL;
333*4882a593Smuzhiyun mdata->s_flags |= MF_MIRROR_FE_LOADED;
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun inode = mdata->s_mirror_fe;
337*4882a593Smuzhiyun if (!inode)
338*4882a593Smuzhiyun return 0xFFFFFFFF;
339*4882a593Smuzhiyun retblk = udf_try_read_meta(inode, block, partition, offset);
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun return retblk;
343*4882a593Smuzhiyun }
344