partition.c 6.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 27 28 29
 *
 */

#include "udfdecl.h"
#include "udf_sb.h"
#include "udf_i.h"

#include <linux/fs.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>

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

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

M
Marcin Slusarz 已提交
59
	map = &sbi->s_partmaps[partition];
M
Marcin Slusarz 已提交
60 61
	vdata = &map->s_type_specific.s_virtual;
	index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
L
Linus Torvalds 已提交
62

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

69
	if (block >= index) {
L
Linus Torvalds 已提交
70 71 72
		block -= index;
		newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
		index = block % (sb->s_blocksize / sizeof(uint32_t));
73
	} else {
L
Linus Torvalds 已提交
74
		newblock = 0;
M
Marcin Slusarz 已提交
75
		index = vdata->s_start_offset / sizeof(uint32_t) + block;
L
Linus Torvalds 已提交
76 77
	}

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

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

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

J
Jan Kara 已提交
89
	brelse(bh);
L
Linus Torvalds 已提交
90

91 92
	iinfo = UDF_I(sbi->s_vat_inode);
	if (iinfo->i_location.partitionReferenceNum == partition) {
L
Linus Torvalds 已提交
93 94 95 96
		udf_debug("recursive call to udf_get_pblock!\n");
		return 0xFFFFFFFF;
	}

97
	return udf_get_pblock(sb, loc,
98
			      iinfo->i_location.partitionReferenceNum,
99
			      offset);
L
Linus Torvalds 已提交
100 101
}

M
Marcin Slusarz 已提交
102
inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
103
				      uint16_t partition, uint32_t offset)
L
Linus Torvalds 已提交
104 105 106 107
{
	return udf_get_pblock_virt15(sb, block, partition, offset);
}

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

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

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

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

M
Marcin Slusarz 已提交
145
	return map->s_partition_root + block + offset;
L
Linus Torvalds 已提交
146 147 148 149 150 151 152 153 154
}

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 已提交
155
	struct udf_sb_info *sbi = UDF_SB(sb);
M
Marcin Slusarz 已提交
156 157
	u16 reallocationTableLen;
	struct buffer_head *bh;
L
Linus Torvalds 已提交
158

M
Marcin Slusarz 已提交
159 160 161 162 163
	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 已提交
164 165
			packet = (old_block - map->s_partition_root) &
						~(sdata->s_packet_len - 1);
166

M
Marcin Slusarz 已提交
167 168 169 170
			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 已提交
171 172 173 174 175 176
					break;
				}

			if (!st)
				return 1;

M
Marcin Slusarz 已提交
177 178 179 180 181 182 183
			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) {
184
					for (; j < 4; j++) {
M
Marcin Slusarz 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
						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 已提交
200
					}
M
Marcin Slusarz 已提交
201 202 203 204 205
					*new_block = le32_to_cpu(
							entry->mappedLocation) +
						     ((old_block -
							map->s_partition_root) &
						     (sdata->s_packet_len - 1));
L
Linus Torvalds 已提交
206
					return 0;
M
Marcin Slusarz 已提交
207 208 209 210 211 212
				} else if (origLoc == packet) {
					*new_block = le32_to_cpu(
							entry->mappedLocation) +
						     ((old_block -
							map->s_partition_root) &
						     (sdata->s_packet_len - 1));
L
Linus Torvalds 已提交
213
					return 0;
M
Marcin Slusarz 已提交
214
				} else if (origLoc > packet)
L
Linus Torvalds 已提交
215 216
					break;
			}
217

M
Marcin Slusarz 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243
			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 已提交
244
				}
M
Marcin Slusarz 已提交
245 246 247 248 249 250
				*new_block =
					le32_to_cpu(
					      st->mapEntry[k].mappedLocation) +
					((old_block - map->s_partition_root) &
					 (sdata->s_packet_len - 1));
				return 0;
L
Linus Torvalds 已提交
251
			}
252

L
Linus Torvalds 已提交
253
			return 1;
254
		} /* if old_block */
L
Linus Torvalds 已提交
255
	}
256

M
Marcin Slusarz 已提交
257
	if (i == sbi->s_partitions) {
L
Linus Torvalds 已提交
258 259 260 261 262 263 264
		/* outside of partitions */
		/* for now, fail =) */
		return 1;
	}

	return 0;
}