Blame view

fs/udf/partition.c 6.1 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
27
28
29
   *
   */
  
  #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>
cb00ea352   Cyrill Gorcunov   UDF: coding style...
30
31
  inline 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
  {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
33
  	if (partition >= UDF_SB_NUMPARTS(sb)) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
34
35
36
  		udf_debug("block=%d, partition=%d, offset=%d: invalid partition
  ",
  			  block, partition, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  		return 0xFFFFFFFF;
  	}
  	if (UDF_SB_PARTFUNC(sb, partition))
28de7948a   Cyrill Gorcunov   UDF: coding style...
40
  		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  	else
  		return UDF_SB_PARTROOT(sb, partition) + block + offset;
  }
28de7948a   Cyrill Gorcunov   UDF: coding style...
44
  uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
cb00ea352   Cyrill Gorcunov   UDF: coding style...
45
  			       uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
47
48
49
50
  {
  	struct buffer_head *bh = NULL;
  	uint32_t newblock;
  	uint32_t index;
  	uint32_t loc;
28de7948a   Cyrill Gorcunov   UDF: coding style...
51
  	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

28de7948a   Cyrill Gorcunov   UDF: coding style...
53
54
55
56
  	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) {
  		udf_debug("Trying to access block beyond end of VAT (%d max %d)
  ",
  			  block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
  		return 0xFFFFFFFF;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
59
  	if (block >= index) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
  		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...
63
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  		newblock = 0;
28de7948a   Cyrill Gorcunov   UDF: coding style...
65
  		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
  	}
  
  	loc = udf_block_map(UDF_SB_VAT(sb), newblock);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
69
  	if (!(bh = sb_bread(sb, loc))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
  		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]
  ",
cb00ea352   Cyrill Gorcunov   UDF: coding style...
72
  			  sb, block, partition, loc, index);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
74
  		return 0xFFFFFFFF;
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
75
  	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

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

cb00ea352   Cyrill Gorcunov   UDF: coding style...
79
  	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
81
82
83
  		udf_debug("recursive call to udf_get_pblock!
  ");
  		return 0xFFFFFFFF;
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
84
  	return udf_get_pblock(sb, loc,
28de7948a   Cyrill Gorcunov   UDF: coding style...
85
86
  			      UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum,
  			      offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
88
89
  inline uint32_t udf_get_pblock_virt20(struct super_block * sb, uint32_t block,
  				      uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
  {
  	return udf_get_pblock_virt15(sb, block, partition, offset);
  }
cb00ea352   Cyrill Gorcunov   UDF: coding style...
93
94
  uint32_t udf_get_pblock_spar15(struct super_block * sb, uint32_t block,
  			       uint16_t partition, uint32_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
  {
  	int i;
  	struct sparingTable *st = NULL;
28de7948a   Cyrill Gorcunov   UDF: coding style...
98
  	uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99

cb00ea352   Cyrill Gorcunov   UDF: coding style...
100
  	for (i = 0; i < 4; i++) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
101
102
  		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL) {
  			st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
  			break;
  		}
  	}
cb00ea352   Cyrill Gorcunov   UDF: coding style...
106
107
  	if (st) {
  		for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
108
  			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  				break;
28de7948a   Cyrill Gorcunov   UDF: coding style...
110
111
112
113
  			} else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet) {
  				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
  					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
  			} else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
114
  				break;
28de7948a   Cyrill Gorcunov   UDF: coding style...
115
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  		}
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
118
119
  
  	return UDF_SB_PARTROOT(sb,partition) + block + offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
121
122
123
124
125
126
127
128
  }
  
  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;
cb00ea352   Cyrill Gorcunov   UDF: coding style...
129
  	for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
130
131
132
133
  		if (old_block > UDF_SB_PARTROOT(sb,i) &&
  		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i)) {
  			sdata = &UDF_SB_TYPESPAR(sb,i);
  			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
cb00ea352   Cyrill Gorcunov   UDF: coding style...
134
135
  
  			for (j = 0; j < 4; j++) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
136
137
  				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) {
  					st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
143
  					break;
  				}
  			}
  
  			if (!st)
  				return 1;
28de7948a   Cyrill Gorcunov   UDF: coding style...
144
145
  			for (k = 0; k < le16_to_cpu(st->reallocationTableLen); k++) {
  				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF) {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
146
147
  					for (; j < 4; j++) {
  						if (sdata->s_spar_map[j]) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
148
149
150
151
  							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
  							st->mapEntry[k].origLocation = cpu_to_le32(packet);
  							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
  							mark_buffer_dirty(sdata->s_spar_map[j]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  						}
  					}
28de7948a   Cyrill Gorcunov   UDF: coding style...
154
155
  					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
  						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  					return 0;
28de7948a   Cyrill Gorcunov   UDF: coding style...
157
158
159
  				} else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet) {
  					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
  						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
  					return 0;
28de7948a   Cyrill Gorcunov   UDF: coding style...
161
  				} else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  					break;
28de7948a   Cyrill Gorcunov   UDF: coding style...
163
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  			}
28de7948a   Cyrill Gorcunov   UDF: coding style...
165
166
167
  
  			for (l = k; l < le16_to_cpu(st->reallocationTableLen); l++) {
  				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF) {
cb00ea352   Cyrill Gorcunov   UDF: coding style...
168
169
  					for (; j < 4; j++) {
  						if (sdata->s_spar_map[j]) {
28de7948a   Cyrill Gorcunov   UDF: coding style...
170
171
172
173
174
175
176
  							st = (struct sparingTable *)sdata->s_spar_map[j]->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) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
  							mark_buffer_dirty(sdata->s_spar_map[j]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
  						}
  					}
28de7948a   Cyrill Gorcunov   UDF: coding style...
179
180
  					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
  						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
  					return 0;
  				}
  			}
28de7948a   Cyrill Gorcunov   UDF: coding style...
184

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  			return 1;
28de7948a   Cyrill Gorcunov   UDF: coding style...
186
  		} /* if old_block */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	}
28de7948a   Cyrill Gorcunov   UDF: coding style...
188

cb00ea352   Cyrill Gorcunov   UDF: coding style...
189
  	if (i == UDF_SB_NUMPARTS(sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
193
194
195
196
  		/* outside of partitions */
  		/* for now, fail =) */
  		return 1;
  	}
  
  	return 0;
  }