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 30
 *
 */

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

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

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

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

M
Marcin Slusarz 已提交
91 92
	if (UDF_I_LOCATION(sbi->s_vat_inode).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,
M
Marcin Slusarz 已提交
98 99
			      UDF_I_LOCATION(sbi->s_vat_inode).
							partitionReferenceNum,
100
			      offset);
L
Linus Torvalds 已提交
101 102
}

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

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

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

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

131 132
	if (st) {
		for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
M
Marcin Slusarz 已提交
133 134 135
			struct sparingEntry *entry = &st->mapEntry[i];
			u32 origLoc = le32_to_cpu(entry->origLocation);
			if (origLoc >= 0xFFFFFFF0)
L
Linus Torvalds 已提交
136
				break;
M
Marcin Slusarz 已提交
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)
L
Linus Torvalds 已提交
142 143 144
				break;
		}
	}
145

M
Marcin Slusarz 已提交
146
	return map->s_partition_root + block + offset;
L
Linus Torvalds 已提交
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;
M
Marcin Slusarz 已提交
156
	struct udf_sb_info *sbi = UDF_SB(sb);
M
Marcin Slusarz 已提交
157 158
	u16 reallocationTableLen;
	struct buffer_head *bh;
L
Linus Torvalds 已提交
159

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

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

			if (!st)
				return 1;

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

M
Marcin Slusarz 已提交
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 244
			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 已提交
245
				}
M
Marcin Slusarz 已提交
246 247 248 249 250 251
				*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 已提交
252
			}
253

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

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

	return 0;
}