ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / udf / partition.c
1 /*
2  * partition.c
3  *
4  * PURPOSE
5  *      Partition handling routines for the OSTA-UDF(tm) filesystem.
6  *
7  * CONTACTS
8  *      E-mail regarding any portion of the Linux UDF file system should be
9  *      directed to the development team mailing list (run by majordomo):
10  *              linux_udf@hpesjro.fc.hp.com
11  *
12  * COPYRIGHT
13  *      This file is distributed under the terms of the GNU General Public
14  *      License (GPL). Copies of the GPL can be obtained from:
15  *              ftp://prep.ai.mit.edu/pub/gnu/GPL
16  *      Each contributing author retains all rights to their own work.
17  *
18  *  (C) 1998-2001 Ben Fennema
19  *
20  * HISTORY
21  *
22  * 12/06/98 blf  Created file. 
23  *
24  */
25
26 #include "udfdecl.h"
27 #include "udf_sb.h"
28 #include "udf_i.h"
29
30 #include <linux/fs.h>
31 #include <linux/string.h>
32 #include <linux/udf_fs.h>
33 #include <linux/slab.h>
34 #include <linux/buffer_head.h>
35
36 inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
37 {
38         if (partition >= UDF_SB_NUMPARTS(sb))
39         {
40                 udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
41                         block, partition, offset);
42                 return 0xFFFFFFFF;
43         }
44         if (UDF_SB_PARTFUNC(sb, partition))
45                 return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
46         else
47                 return UDF_SB_PARTROOT(sb, partition) + block + offset;
48 }
49
50 uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
51 {
52         struct buffer_head *bh = NULL;
53         uint32_t newblock;
54         uint32_t index;
55         uint32_t loc;
56
57         index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
58
59         if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
60         {
61                 udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
62                         block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
63                 return 0xFFFFFFFF;
64         }
65
66         if (block >= index)
67         {
68                 block -= index;
69                 newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
70                 index = block % (sb->s_blocksize / sizeof(uint32_t));
71         }
72         else
73         {
74                 newblock = 0;
75                 index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
76         }
77
78         loc = udf_block_map(UDF_SB_VAT(sb), newblock);
79
80         if (!(bh = sb_bread(sb, loc)))
81         {
82                 udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
83                         sb, block, partition, loc, index);
84                 return 0xFFFFFFFF;
85         }
86
87         loc = le32_to_cpu(((uint32_t *)bh->b_data)[index]);
88
89         udf_release_data(bh);
90
91         if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
92         {
93                 udf_debug("recursive call to udf_get_pblock!\n");
94                 return 0xFFFFFFFF;
95         }
96
97         return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
98 }
99
100 inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
101 {
102         return udf_get_pblock_virt15(sb, block, partition, offset);
103 }
104
105 uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
106 {
107         int i;
108         struct sparingTable *st = NULL;
109         uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
110
111         for (i=0; i<4; i++)
112         {
113                 if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
114                 {
115                         st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
116                         break;
117                 }
118         }
119
120         if (st)
121         {
122                 for (i=0; i<st->reallocationTableLen; i++)
123                 {
124                         if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
125                                 break;
126                         else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
127                         {
128                                 return le32_to_cpu(st->mapEntry[i].mappedLocation) +
129                                         ((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
130                         }
131                         else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
132                                 break;
133                 }
134         }
135         return UDF_SB_PARTROOT(sb,partition) + block + offset;
136 }
137
138 int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
139 {
140         struct udf_sparing_data *sdata;
141         struct sparingTable *st = NULL;
142         struct sparingEntry mapEntry;
143         uint32_t packet;
144         int i, j, k, l;
145
146         for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
147         {
148                 if (old_block > UDF_SB_PARTROOT(sb,i) &&
149                     old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
150                 {
151                         sdata = &UDF_SB_TYPESPAR(sb,i);
152                         packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);
153
154                         for (j=0; j<4; j++)
155                         {
156                                 if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
157                                 {
158                                         st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
159                                         break;
160                                 }
161                         }
162
163                         if (!st)
164                                 return 1;
165
166                         for (k=0; k<st->reallocationTableLen; k++)
167                         {
168                                 if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
169                                 {
170                                         for (; j<4; j++)
171                                         {
172                                                 if (sdata->s_spar_map[j])
173                                                 {
174                                                         st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
175                                                         st->mapEntry[k].origLocation = cpu_to_le32(packet);
176                                                         udf_update_tag((char *)st, sizeof(struct sparingTable) + st->reallocationTableLen * sizeof(struct sparingEntry));
177                                                         mark_buffer_dirty(sdata->s_spar_map[j]);
178                                                 }
179                                         }
180                                         *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
181                                                 ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
182                                         return 0;
183                                 }
184                                 else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
185                                 {
186                                         *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
187                                                 ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
188                                         return 0;
189                                 }
190                                 else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
191                                         break;
192                         }
193                         for (l=k; l<st->reallocationTableLen; l++)
194                         {
195                                 if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
196                                 {
197                                         for (; j<4; j++)
198                                         {
199                                                 if (sdata->s_spar_map[j])
200                                                 {
201                                                         st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
202                                                         mapEntry = st->mapEntry[l];
203                                                         mapEntry.origLocation = cpu_to_le32(packet);
204                                                         memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
205                                                         st->mapEntry[k] = mapEntry;
206                                                         udf_update_tag((char *)st, sizeof(struct sparingTable) + st->reallocationTableLen * sizeof(struct sparingEntry));
207                                                         mark_buffer_dirty(sdata->s_spar_map[j]);
208                                                 }
209                                         }
210                                         *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
211                                                 ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
212                                         return 0;
213                                 }
214                         }
215                         return 1;
216                 }
217         }
218         if (i == UDF_SB_NUMPARTS(sb))
219         {
220                 /* outside of partitions */
221                 /* for now, fail =) */
222                 return 1;
223         }
224
225         return 0;
226 }