partition.c 8.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * partition.c
 *
 * PURPOSE
 *      Partition handling routines for the OSTA-UDF(tm) filesystem.
 *
 * 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
 *
17
 * 12/06/98 blf  Created file.
L
Linus Torvalds 已提交
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>
27
#include <linux/mutex.h>
L
Linus Torvalds 已提交
28

29 30
uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
			uint16_t partition, uint32_t offset)
L
Linus Torvalds 已提交
31
{
M
Marcin Slusarz 已提交
32 33 34
	struct udf_sb_info *sbi = UDF_SB(sb);
	struct udf_part_map *map;
	if (partition >= sbi->s_partitions) {
35
		udf_debug("block=%u, partition=%u, offset=%u: invalid partition\n",
J
Joe Perches 已提交
36
			  block, partition, offset);
L
Linus Torvalds 已提交
37 38
		return 0xFFFFFFFF;
	}
M
Marcin Slusarz 已提交
39 40 41
	map = &sbi->s_partmaps[partition];
	if (map->s_partition_func)
		return map->s_partition_func(sb, block, partition, offset);
L
Linus Torvalds 已提交
42
	else
M
Marcin Slusarz 已提交
43
		return map->s_partition_root + block + offset;
L
Linus Torvalds 已提交
44 45
}

46
uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
47
			       uint16_t partition, uint32_t offset)
L
Linus Torvalds 已提交
48 49 50 51 52
{
	struct buffer_head *bh = NULL;
	uint32_t newblock;
	uint32_t index;
	uint32_t loc;
M
Marcin Slusarz 已提交
53 54
	struct udf_sb_info *sbi = UDF_SB(sb);
	struct udf_part_map *map;
M
Marcin Slusarz 已提交
55
	struct udf_virtual_data *vdata;
56
	struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
L
Linus Torvalds 已提交
57

M
Marcin Slusarz 已提交
58
	map = &sbi->s_partmaps[partition];
M
Marcin Slusarz 已提交
59
	vdata = &map->s_type_specific.s_virtual;
L
Linus Torvalds 已提交
60

M
Marcin Slusarz 已提交
61
	if (block > vdata->s_num_entries) {
62
		udf_debug("Trying to access block beyond end of VAT (%u max %u)\n",
J
Joe Perches 已提交
63
			  block, vdata->s_num_entries);
L
Linus Torvalds 已提交
64 65 66
		return 0xFFFFFFFF;
	}

67
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
68 69
		loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
			vdata->s_start_offset))[block]);
70 71 72
		goto translate;
	}
	index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
73
	if (block >= index) {
L
Linus Torvalds 已提交
74 75 76
		block -= index;
		newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
		index = block % (sb->s_blocksize / sizeof(uint32_t));
77
	} else {
L
Linus Torvalds 已提交
78
		newblock = 0;
M
Marcin Slusarz 已提交
79
		index = vdata->s_start_offset / sizeof(uint32_t) + block;
L
Linus Torvalds 已提交
80 81
	}

M
Marcin Slusarz 已提交
82
	loc = udf_block_map(sbi->s_vat_inode, newblock);
L
Linus Torvalds 已提交
83

M
Marcin Slusarz 已提交
84 85
	bh = sb_bread(sb, loc);
	if (!bh) {
86
		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%u,%u) VAT: %u[%u]\n",
87
			  sb, block, partition, loc, index);
L
Linus Torvalds 已提交
88 89 90
		return 0xFFFFFFFF;
	}

91
	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
L
Linus Torvalds 已提交
92

J
Jan Kara 已提交
93
	brelse(bh);
L
Linus Torvalds 已提交
94

95
translate:
96
	if (iinfo->i_location.partitionReferenceNum == partition) {
L
Linus Torvalds 已提交
97 98 99 100
		udf_debug("recursive call to udf_get_pblock!\n");
		return 0xFFFFFFFF;
	}

101
	return udf_get_pblock(sb, loc,
102
			      iinfo->i_location.partitionReferenceNum,
103
			      offset);
L
Linus Torvalds 已提交
104 105
}

M
Marcin Slusarz 已提交
106
inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
107
				      uint16_t partition, uint32_t offset)
L
Linus Torvalds 已提交
108 109 110 111
{
	return udf_get_pblock_virt15(sb, block, partition, offset);
}

M
Marcin Slusarz 已提交
112
uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
113
			       uint16_t partition, uint32_t offset)
L
Linus Torvalds 已提交
114 115 116
{
	int i;
	struct sparingTable *st = NULL;
M
Marcin Slusarz 已提交
117 118 119
	struct udf_sb_info *sbi = UDF_SB(sb);
	struct udf_part_map *map;
	uint32_t packet;
M
Marcin Slusarz 已提交
120
	struct udf_sparing_data *sdata;
M
Marcin Slusarz 已提交
121 122

	map = &sbi->s_partmaps[partition];
M
Marcin Slusarz 已提交
123 124
	sdata = &map->s_type_specific.s_sparing;
	packet = (block + offset) & ~(sdata->s_packet_len - 1);
L
Linus Torvalds 已提交
125

126
	for (i = 0; i < 4; i++) {
M
Marcin Slusarz 已提交
127 128 129
		if (sdata->s_spar_map[i] != NULL) {
			st = (struct sparingTable *)
					sdata->s_spar_map[i]->b_data;
L
Linus Torvalds 已提交
130 131 132 133
			break;
		}
	}

134 135
	if (st) {
		for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
M
Marcin Slusarz 已提交
136 137 138
			struct sparingEntry *entry = &st->mapEntry[i];
			u32 origLoc = le32_to_cpu(entry->origLocation);
			if (origLoc >= 0xFFFFFFF0)
L
Linus Torvalds 已提交
139
				break;
M
Marcin Slusarz 已提交
140 141 142 143 144
			else if (origLoc == packet)
				return le32_to_cpu(entry->mappedLocation) +
					((block + offset) &
						(sdata->s_packet_len - 1));
			else if (origLoc > packet)
L
Linus Torvalds 已提交
145 146 147
				break;
		}
	}
148

M
Marcin Slusarz 已提交
149
	return map->s_partition_root + block + offset;
L
Linus Torvalds 已提交
150 151 152 153 154 155 156 157 158
}

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;
M
Marcin Slusarz 已提交
159
	struct udf_sb_info *sbi = UDF_SB(sb);
M
Marcin Slusarz 已提交
160 161
	u16 reallocationTableLen;
	struct buffer_head *bh;
162
	int ret = 0;
L
Linus Torvalds 已提交
163

164
	mutex_lock(&sbi->s_alloc_mutex);
M
Marcin Slusarz 已提交
165 166 167 168 169
	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;
M
Marcin Slusarz 已提交
170 171
			packet = (old_block - map->s_partition_root) &
						~(sdata->s_packet_len - 1);
172

M
Marcin Slusarz 已提交
173 174 175 176
			for (j = 0; j < 4; j++)
				if (sdata->s_spar_map[j] != NULL) {
					st = (struct sparingTable *)
						sdata->s_spar_map[j]->b_data;
L
Linus Torvalds 已提交
177 178 179
					break;
				}

180 181 182 183
			if (!st) {
				ret = 1;
				goto out;
			}
L
Linus Torvalds 已提交
184

M
Marcin Slusarz 已提交
185 186 187 188 189 190 191
			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) {
192
					for (; j < 4; j++) {
M
Marcin Slusarz 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
						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);
L
Linus Torvalds 已提交
208
					}
M
Marcin Slusarz 已提交
209 210 211 212 213
					*new_block = le32_to_cpu(
							entry->mappedLocation) +
						     ((old_block -
							map->s_partition_root) &
						     (sdata->s_packet_len - 1));
214 215
					ret = 0;
					goto out;
M
Marcin Slusarz 已提交
216 217 218 219 220 221
				} else if (origLoc == packet) {
					*new_block = le32_to_cpu(
							entry->mappedLocation) +
						     ((old_block -
							map->s_partition_root) &
						     (sdata->s_packet_len - 1));
222 223
					ret = 0;
					goto out;
M
Marcin Slusarz 已提交
224
				} else if (origLoc > packet)
L
Linus Torvalds 已提交
225 226
					break;
			}
227

M
Marcin Slusarz 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
			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);
L
Linus Torvalds 已提交
254
				}
M
Marcin Slusarz 已提交
255 256 257 258 259
				*new_block =
					le32_to_cpu(
					      st->mapEntry[k].mappedLocation) +
					((old_block - map->s_partition_root) &
					 (sdata->s_packet_len - 1));
260 261
				ret = 0;
				goto out;
L
Linus Torvalds 已提交
262
			}
263

264 265
			ret = 1;
			goto out;
266
		} /* if old_block */
L
Linus Torvalds 已提交
267
	}
268

M
Marcin Slusarz 已提交
269
	if (i == sbi->s_partitions) {
L
Linus Torvalds 已提交
270 271
		/* outside of partitions */
		/* for now, fail =) */
272
		ret = 1;
L
Linus Torvalds 已提交
273 274
	}

275 276 277
out:
	mutex_unlock(&sbi->s_alloc_mutex);
	return ret;
L
Linus Torvalds 已提交
278
}
279 280 281 282 283 284

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;
285
	struct kernel_lb_addr eloc;
286 287 288 289 290 291 292 293 294 295 296 297
	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,
298 299
			map->s_type_specific.s_metadata.s_phys_partition_ref,
			ext_offset + offset);
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	}

	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\n");

	map = &sbi->s_partmaps[partition];
	mdata = &map->s_type_specific.s_metadata;
	inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;

321 322 323
	if (!inode)
		return 0xFFFFFFFF;

324
	retblk = udf_try_read_meta(inode, block, partition, offset);
325
	if (retblk == 0xFFFFFFFF && mdata->s_metadata_fe) {
J
Joe Perches 已提交
326
		udf_warn(sb, "error reading from METADATA, trying to read from MIRROR\n");
J
Jan Kara 已提交
327
		if (!(mdata->s_flags & MF_MIRROR_FE_LOADED)) {
328
			mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
329 330
				mdata->s_mirror_file_loc,
				mdata->s_phys_partition_ref);
331 332
			if (IS_ERR(mdata->s_mirror_fe))
				mdata->s_mirror_fe = NULL;
J
Jan Kara 已提交
333
			mdata->s_flags |= MF_MIRROR_FE_LOADED;
334 335
		}

336 337 338 339 340 341 342 343
		inode = mdata->s_mirror_fe;
		if (!inode)
			return 0xFFFFFFFF;
		retblk = udf_try_read_meta(inode, block, partition, offset);
	}

	return retblk;
}