Blame view

fs/udf/partition.c 8.65 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   * partition.c
   *
   * PURPOSE
   *      Partition handling routines for the OSTA-UDF(tm) filesystem.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
13
14
15
16
   * COPYRIGHT
   *      This file is distributed under the terms of the GNU General Public
   *      License (GPL). Copies of the GPL can be obtained from:
   *              ftp://prep.ai.mit.edu/pub/gnu/GPL
   *      Each contributing author retains all rights to their own work.
   *
   *  (C) 1998-2001 Ben Fennema
   *
   * HISTORY
   *
28de7948a   Cyrill Gorcunov   UDF: coding style...
17
   * 12/06/98 blf  Created file.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
26
   *
   */
  
  #include "udfdecl.h"
  #include "udf_sb.h"
  #include "udf_i.h"
  
  #include <linux/fs.h>
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #include <linux/buffer_head.h>
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
28
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

22ba0317c   Adrian Bunk   udf: fs/udf/parti...
30
31
  uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
  			uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  {
6c79e987d   Marcin Slusarz   udf: remove some ...
33
34
35
  	struct udf_sb_info *sbi = UDF_SB(sb);
  	struct udf_part_map *map;
  	if (partition >= sbi->s_partitions) {
a983f368f   Joe Perches   udf: Neaten udf_d...
36
37
38
  		udf_debug("block=%d, partition=%d, offset=%d: invalid partition
  ",
  			  block, partition, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  		return 0xFFFFFFFF;
  	}
6c79e987d   Marcin Slusarz   udf: remove some ...
41
42
43
  	map = &sbi->s_partmaps[partition];
  	if (map->s_partition_func)
  		return map->s_partition_func(sb, block, partition, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  	else
6c79e987d   Marcin Slusarz   udf: remove some ...
45
  		return map->s_partition_root + block + offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  }
28de7948a   Cyrill Gorcunov   UDF: coding style...
47
  uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
48
  			       uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
  {
  	struct buffer_head *bh = NULL;
  	uint32_t newblock;
  	uint32_t index;
  	uint32_t loc;
6c79e987d   Marcin Slusarz   udf: remove some ...
54
55
  	struct udf_sb_info *sbi = UDF_SB(sb);
  	struct udf_part_map *map;
4b11111ab   Marcin Slusarz   udf: fix coding s...
56
  	struct udf_virtual_data *vdata;
fa5e08156   Jan Kara   udf: Handle VAT p...
57
  	struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

6c79e987d   Marcin Slusarz   udf: remove some ...
59
  	map = &sbi->s_partmaps[partition];
4b11111ab   Marcin Slusarz   udf: fix coding s...
60
  	vdata = &map->s_type_specific.s_virtual;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61

4b11111ab   Marcin Slusarz   udf: fix coding s...
62
  	if (block > vdata->s_num_entries) {
a983f368f   Joe Perches   udf: Neaten udf_d...
63
64
65
  		udf_debug("Trying to access block beyond end of VAT (%d max %d)
  ",
  			  block, vdata->s_num_entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
  		return 0xFFFFFFFF;
  	}
fa5e08156   Jan Kara   udf: Handle VAT p...
68
  	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
47c9358a0   Sebastian Manciulea   udf: Fix bug in V...
69
70
  		loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
  			vdata->s_start_offset))[block]);
fa5e08156   Jan Kara   udf: Handle VAT p...
71
72
73
  		goto translate;
  	}
  	index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
74
  	if (block >= index) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
  		block -= index;
  		newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
  		index = block % (sb->s_blocksize / sizeof(uint32_t));
cb00ea352   Cyrill Gorcunov   UDF: coding style...
78
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  		newblock = 0;
4b11111ab   Marcin Slusarz   udf: fix coding s...
80
  		index = vdata->s_start_offset / sizeof(uint32_t) + block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
  	}
6c79e987d   Marcin Slusarz   udf: remove some ...
82
  	loc = udf_block_map(sbi->s_vat_inode, newblock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83

4b11111ab   Marcin Slusarz   udf: fix coding s...
84
85
  	bh = sb_bread(sb, loc);
  	if (!bh) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
  		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]
  ",
cb00ea352   Cyrill Gorcunov   UDF: coding style...
88
  			  sb, block, partition, loc, index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  		return 0xFFFFFFFF;
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
91
  	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92

3bf25cb40   Jan Kara   udf: use get_bh()
93
  	brelse(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

fa5e08156   Jan Kara   udf: Handle VAT p...
95
  translate:
48d6d8ff7   Marcin Slusarz   udf: cache struct...
96
  	if (iinfo->i_location.partitionReferenceNum == partition) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
  		udf_debug("recursive call to udf_get_pblock!
  ");
  		return 0xFFFFFFFF;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
101
  	return udf_get_pblock(sb, loc,
48d6d8ff7   Marcin Slusarz   udf: cache struct...
102
  			      iinfo->i_location.partitionReferenceNum,
28de7948a   Cyrill Gorcunov   UDF: coding style...
103
  			      offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  }
4b11111ab   Marcin Slusarz   udf: fix coding s...
105
  inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
106
  				      uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
  {
  	return udf_get_pblock_virt15(sb, block, partition, offset);
  }
6c79e987d   Marcin Slusarz   udf: remove some ...
110
  uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
111
  			       uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
  {
  	int i;
  	struct sparingTable *st = NULL;
6c79e987d   Marcin Slusarz   udf: remove some ...
115
116
117
  	struct udf_sb_info *sbi = UDF_SB(sb);
  	struct udf_part_map *map;
  	uint32_t packet;
4b11111ab   Marcin Slusarz   udf: fix coding s...
118
  	struct udf_sparing_data *sdata;
6c79e987d   Marcin Slusarz   udf: remove some ...
119
120
  
  	map = &sbi->s_partmaps[partition];
4b11111ab   Marcin Slusarz   udf: fix coding s...
121
122
  	sdata = &map->s_type_specific.s_sparing;
  	packet = (block + offset) & ~(sdata->s_packet_len - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123

cb00ea352   Cyrill Gorcunov   UDF: coding style...
124
  	for (i = 0; i < 4; i++) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
125
126
127
  		if (sdata->s_spar_map[i] != NULL) {
  			st = (struct sparingTable *)
  					sdata->s_spar_map[i]->b_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
  			break;
  		}
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
131
132
  	if (st) {
  		for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
133
134
135
  			struct sparingEntry *entry = &st->mapEntry[i];
  			u32 origLoc = le32_to_cpu(entry->origLocation);
  			if (origLoc >= 0xFFFFFFF0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  				break;
4b11111ab   Marcin Slusarz   udf: fix coding s...
137
138
139
140
141
  			else if (origLoc == packet)
  				return le32_to_cpu(entry->mappedLocation) +
  					((block + offset) &
  						(sdata->s_packet_len - 1));
  			else if (origLoc > packet)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
144
  				break;
  		}
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
145

6c79e987d   Marcin Slusarz   udf: remove some ...
146
  	return map->s_partition_root + block + offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
  }
  
  int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
  {
  	struct udf_sparing_data *sdata;
  	struct sparingTable *st = NULL;
  	struct sparingEntry mapEntry;
  	uint32_t packet;
  	int i, j, k, l;
6c79e987d   Marcin Slusarz   udf: remove some ...
156
  	struct udf_sb_info *sbi = UDF_SB(sb);
4b11111ab   Marcin Slusarz   udf: fix coding s...
157
158
  	u16 reallocationTableLen;
  	struct buffer_head *bh;
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
159
  	int ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

7db09be62   Alessio Igor Bogani   udf: Use of s_all...
161
  	mutex_lock(&sbi->s_alloc_mutex);
6c79e987d   Marcin Slusarz   udf: remove some ...
162
163
164
165
166
  	for (i = 0; i < sbi->s_partitions; i++) {
  		struct udf_part_map *map = &sbi->s_partmaps[i];
  		if (old_block > map->s_partition_root &&
  		    old_block < map->s_partition_root + map->s_partition_len) {
  			sdata = &map->s_type_specific.s_sparing;
4b11111ab   Marcin Slusarz   udf: fix coding s...
167
168
  			packet = (old_block - map->s_partition_root) &
  						~(sdata->s_packet_len - 1);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
169

4b11111ab   Marcin Slusarz   udf: fix coding s...
170
171
172
173
  			for (j = 0; j < 4; j++)
  				if (sdata->s_spar_map[j] != NULL) {
  					st = (struct sparingTable *)
  						sdata->s_spar_map[j]->b_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  					break;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176

7db09be62   Alessio Igor Bogani   udf: Use of s_all...
177
178
179
180
  			if (!st) {
  				ret = 1;
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181

4b11111ab   Marcin Slusarz   udf: fix coding s...
182
183
184
185
186
187
188
  			reallocationTableLen =
  					le16_to_cpu(st->reallocationTableLen);
  			for (k = 0; k < reallocationTableLen; k++) {
  				struct sparingEntry *entry = &st->mapEntry[k];
  				u32 origLoc = le32_to_cpu(entry->origLocation);
  
  				if (origLoc == 0xFFFFFFFF) {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
189
  					for (; j < 4; j++) {
4b11111ab   Marcin Slusarz   udf: fix coding s...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
  						int len;
  						bh = sdata->s_spar_map[j];
  						if (!bh)
  							continue;
  
  						st = (struct sparingTable *)
  								bh->b_data;
  						entry->origLocation =
  							cpu_to_le32(packet);
  						len =
  						  sizeof(struct sparingTable) +
  						  reallocationTableLen *
  						  sizeof(struct sparingEntry);
  						udf_update_tag((char *)st, len);
  						mark_buffer_dirty(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
  					}
4b11111ab   Marcin Slusarz   udf: fix coding s...
206
207
208
209
210
  					*new_block = le32_to_cpu(
  							entry->mappedLocation) +
  						     ((old_block -
  							map->s_partition_root) &
  						     (sdata->s_packet_len - 1));
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
211
212
  					ret = 0;
  					goto out;
4b11111ab   Marcin Slusarz   udf: fix coding s...
213
214
215
216
217
218
  				} else if (origLoc == packet) {
  					*new_block = le32_to_cpu(
  							entry->mappedLocation) +
  						     ((old_block -
  							map->s_partition_root) &
  						     (sdata->s_packet_len - 1));
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
219
220
  					ret = 0;
  					goto out;
4b11111ab   Marcin Slusarz   udf: fix coding s...
221
  				} else if (origLoc > packet)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  					break;
  			}
28de7948a   Cyrill Gorcunov   UDF: coding style...
224

4b11111ab   Marcin Slusarz   udf: fix coding s...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
  			for (l = k; l < reallocationTableLen; l++) {
  				struct sparingEntry *entry = &st->mapEntry[l];
  				u32 origLoc = le32_to_cpu(entry->origLocation);
  
  				if (origLoc != 0xFFFFFFFF)
  					continue;
  
  				for (; j < 4; j++) {
  					bh = sdata->s_spar_map[j];
  					if (!bh)
  						continue;
  
  					st = (struct sparingTable *)bh->b_data;
  					mapEntry = st->mapEntry[l];
  					mapEntry.origLocation =
  							cpu_to_le32(packet);
  					memmove(&st->mapEntry[k + 1],
  						&st->mapEntry[k],
  						(l - k) *
  						sizeof(struct sparingEntry));
  					st->mapEntry[k] = mapEntry;
  					udf_update_tag((char *)st,
  						sizeof(struct sparingTable) +
  						reallocationTableLen *
  						sizeof(struct sparingEntry));
  					mark_buffer_dirty(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  				}
4b11111ab   Marcin Slusarz   udf: fix coding s...
252
253
254
255
256
  				*new_block =
  					le32_to_cpu(
  					      st->mapEntry[k].mappedLocation) +
  					((old_block - map->s_partition_root) &
  					 (sdata->s_packet_len - 1));
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
257
258
  				ret = 0;
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  			}
28de7948a   Cyrill Gorcunov   UDF: coding style...
260

7db09be62   Alessio Igor Bogani   udf: Use of s_all...
261
262
  			ret = 1;
  			goto out;
28de7948a   Cyrill Gorcunov   UDF: coding style...
263
  		} /* if old_block */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
265

6c79e987d   Marcin Slusarz   udf: remove some ...
266
  	if (i == sbi->s_partitions) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
  		/* outside of partitions */
  		/* for now, fail =) */
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
269
  		ret = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  	}
7db09be62   Alessio Igor Bogani   udf: Use of s_all...
271
272
273
  out:
  	mutex_unlock(&sbi->s_alloc_mutex);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  }
bfb257a59   Jan Kara   udf: Add read-onl...
275
276
277
278
279
280
  
  static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
  					uint16_t partition, uint32_t offset)
  {
  	struct super_block *sb = inode->i_sb;
  	struct udf_part_map *map;
5ca4e4be8   Pekka Enberg   Remove struct typ...
281
  	struct kernel_lb_addr eloc;
bfb257a59   Jan Kara   udf: Add read-onl...
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  	uint32_t elen;
  	sector_t ext_offset;
  	struct extent_position epos = {};
  	uint32_t phyblock;
  
  	if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
  						(EXT_RECORDED_ALLOCATED >> 30))
  		phyblock = 0xFFFFFFFF;
  	else {
  		map = &UDF_SB(sb)->s_partmaps[partition];
  		/* map to sparable/physical partition desc */
  		phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
  			map->s_partition_num, ext_offset + offset);
  	}
  
  	brelse(epos.bh);
  	return phyblock;
  }
  
  uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
  				uint16_t partition, uint32_t offset)
  {
  	struct udf_sb_info *sbi = UDF_SB(sb);
  	struct udf_part_map *map;
  	struct udf_meta_data *mdata;
  	uint32_t retblk;
  	struct inode *inode;
  
  	udf_debug("READING from METADATA
  ");
  
  	map = &sbi->s_partmaps[partition];
  	mdata = &map->s_type_specific.s_metadata;
  	inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
  
  	/* We shouldn't mount such media... */
  	BUG_ON(!inode);
  	retblk = udf_try_read_meta(inode, block, partition, offset);
3080a74ea   Namjae Jeon   udf: Skip mirror ...
320
  	if (retblk == 0xFFFFFFFF && mdata->s_metadata_fe) {
a40ecd7b3   Joe Perches   udf: Rename udf_w...
321
322
  		udf_warn(sb, "error reading from METADATA, trying to read from MIRROR
  ");
ed47a7d00   Jan Kara   udf: Cleanup meta...
323
  		if (!(mdata->s_flags & MF_MIRROR_FE_LOADED)) {
3080a74ea   Namjae Jeon   udf: Skip mirror ...
324
325
  			mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
  				mdata->s_mirror_file_loc, map->s_partition_num);
ed47a7d00   Jan Kara   udf: Cleanup meta...
326
  			mdata->s_flags |= MF_MIRROR_FE_LOADED;
3080a74ea   Namjae Jeon   udf: Skip mirror ...
327
  		}
bfb257a59   Jan Kara   udf: Add read-onl...
328
329
330
331
332
333
334
335
  		inode = mdata->s_mirror_fe;
  		if (!inode)
  			return 0xFFFFFFFF;
  		retblk = udf_try_read_meta(inode, block, partition, offset);
  	}
  
  	return retblk;
  }