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