~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to fs/udf/partition.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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/buffer_head.h>
 
28
#include <linux/mutex.h>
 
29
 
 
30
uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
 
31
                        uint16_t partition, uint32_t offset)
 
32
{
 
33
        struct udf_sb_info *sbi = UDF_SB(sb);
 
34
        struct udf_part_map *map;
 
35
        if (partition >= sbi->s_partitions) {
 
36
                udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
 
37
                          block, partition, offset);
 
38
                return 0xFFFFFFFF;
 
39
        }
 
40
        map = &sbi->s_partmaps[partition];
 
41
        if (map->s_partition_func)
 
42
                return map->s_partition_func(sb, block, partition, offset);
 
43
        else
 
44
                return map->s_partition_root + block + offset;
 
45
}
 
46
 
 
47
uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
 
48
                               uint16_t partition, uint32_t offset)
 
49
{
 
50
        struct buffer_head *bh = NULL;
 
51
        uint32_t newblock;
 
52
        uint32_t index;
 
53
        uint32_t loc;
 
54
        struct udf_sb_info *sbi = UDF_SB(sb);
 
55
        struct udf_part_map *map;
 
56
        struct udf_virtual_data *vdata;
 
57
        struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
 
58
 
 
59
        map = &sbi->s_partmaps[partition];
 
60
        vdata = &map->s_type_specific.s_virtual;
 
61
 
 
62
        if (block > vdata->s_num_entries) {
 
63
                udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
 
64
                          block, vdata->s_num_entries);
 
65
                return 0xFFFFFFFF;
 
66
        }
 
67
 
 
68
        if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
 
69
                loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
 
70
                        vdata->s_start_offset))[block]);
 
71
                goto translate;
 
72
        }
 
73
        index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
 
74
        if (block >= index) {
 
75
                block -= index;
 
76
                newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
 
77
                index = block % (sb->s_blocksize / sizeof(uint32_t));
 
78
        } else {
 
79
                newblock = 0;
 
80
                index = vdata->s_start_offset / sizeof(uint32_t) + block;
 
81
        }
 
82
 
 
83
        loc = udf_block_map(sbi->s_vat_inode, newblock);
 
84
 
 
85
        bh = sb_bread(sb, loc);
 
86
        if (!bh) {
 
87
                udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
 
88
                          sb, block, partition, loc, index);
 
89
                return 0xFFFFFFFF;
 
90
        }
 
91
 
 
92
        loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
 
93
 
 
94
        brelse(bh);
 
95
 
 
96
translate:
 
97
        if (iinfo->i_location.partitionReferenceNum == partition) {
 
98
                udf_debug("recursive call to udf_get_pblock!\n");
 
99
                return 0xFFFFFFFF;
 
100
        }
 
101
 
 
102
        return udf_get_pblock(sb, loc,
 
103
                              iinfo->i_location.partitionReferenceNum,
 
104
                              offset);
 
105
}
 
106
 
 
107
inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
 
108
                                      uint16_t partition, uint32_t offset)
 
109
{
 
110
        return udf_get_pblock_virt15(sb, block, partition, offset);
 
111
}
 
112
 
 
113
uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
 
114
                               uint16_t partition, uint32_t offset)
 
115
{
 
116
        int i;
 
117
        struct sparingTable *st = NULL;
 
118
        struct udf_sb_info *sbi = UDF_SB(sb);
 
119
        struct udf_part_map *map;
 
120
        uint32_t packet;
 
121
        struct udf_sparing_data *sdata;
 
122
 
 
123
        map = &sbi->s_partmaps[partition];
 
124
        sdata = &map->s_type_specific.s_sparing;
 
125
        packet = (block + offset) & ~(sdata->s_packet_len - 1);
 
126
 
 
127
        for (i = 0; i < 4; i++) {
 
128
                if (sdata->s_spar_map[i] != NULL) {
 
129
                        st = (struct sparingTable *)
 
130
                                        sdata->s_spar_map[i]->b_data;
 
131
                        break;
 
132
                }
 
133
        }
 
134
 
 
135
        if (st) {
 
136
                for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
 
137
                        struct sparingEntry *entry = &st->mapEntry[i];
 
138
                        u32 origLoc = le32_to_cpu(entry->origLocation);
 
139
                        if (origLoc >= 0xFFFFFFF0)
 
140
                                break;
 
141
                        else if (origLoc == packet)
 
142
                                return le32_to_cpu(entry->mappedLocation) +
 
143
                                        ((block + offset) &
 
144
                                                (sdata->s_packet_len - 1));
 
145
                        else if (origLoc > packet)
 
146
                                break;
 
147
                }
 
148
        }
 
149
 
 
150
        return map->s_partition_root + block + offset;
 
151
}
 
152
 
 
153
int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
 
154
{
 
155
        struct udf_sparing_data *sdata;
 
156
        struct sparingTable *st = NULL;
 
157
        struct sparingEntry mapEntry;
 
158
        uint32_t packet;
 
159
        int i, j, k, l;
 
160
        struct udf_sb_info *sbi = UDF_SB(sb);
 
161
        u16 reallocationTableLen;
 
162
        struct buffer_head *bh;
 
163
        int ret = 0;
 
164
 
 
165
        mutex_lock(&sbi->s_alloc_mutex);
 
166
        for (i = 0; i < sbi->s_partitions; i++) {
 
167
                struct udf_part_map *map = &sbi->s_partmaps[i];
 
168
                if (old_block > map->s_partition_root &&
 
169
                    old_block < map->s_partition_root + map->s_partition_len) {
 
170
                        sdata = &map->s_type_specific.s_sparing;
 
171
                        packet = (old_block - map->s_partition_root) &
 
172
                                                ~(sdata->s_packet_len - 1);
 
173
 
 
174
                        for (j = 0; j < 4; j++)
 
175
                                if (sdata->s_spar_map[j] != NULL) {
 
176
                                        st = (struct sparingTable *)
 
177
                                                sdata->s_spar_map[j]->b_data;
 
178
                                        break;
 
179
                                }
 
180
 
 
181
                        if (!st) {
 
182
                                ret = 1;
 
183
                                goto out;
 
184
                        }
 
185
 
 
186
                        reallocationTableLen =
 
187
                                        le16_to_cpu(st->reallocationTableLen);
 
188
                        for (k = 0; k < reallocationTableLen; k++) {
 
189
                                struct sparingEntry *entry = &st->mapEntry[k];
 
190
                                u32 origLoc = le32_to_cpu(entry->origLocation);
 
191
 
 
192
                                if (origLoc == 0xFFFFFFFF) {
 
193
                                        for (; j < 4; j++) {
 
194
                                                int len;
 
195
                                                bh = sdata->s_spar_map[j];
 
196
                                                if (!bh)
 
197
                                                        continue;
 
198
 
 
199
                                                st = (struct sparingTable *)
 
200
                                                                bh->b_data;
 
201
                                                entry->origLocation =
 
202
                                                        cpu_to_le32(packet);
 
203
                                                len =
 
204
                                                  sizeof(struct sparingTable) +
 
205
                                                  reallocationTableLen *
 
206
                                                  sizeof(struct sparingEntry);
 
207
                                                udf_update_tag((char *)st, len);
 
208
                                                mark_buffer_dirty(bh);
 
209
                                        }
 
210
                                        *new_block = le32_to_cpu(
 
211
                                                        entry->mappedLocation) +
 
212
                                                     ((old_block -
 
213
                                                        map->s_partition_root) &
 
214
                                                     (sdata->s_packet_len - 1));
 
215
                                        ret = 0;
 
216
                                        goto out;
 
217
                                } else if (origLoc == packet) {
 
218
                                        *new_block = le32_to_cpu(
 
219
                                                        entry->mappedLocation) +
 
220
                                                     ((old_block -
 
221
                                                        map->s_partition_root) &
 
222
                                                     (sdata->s_packet_len - 1));
 
223
                                        ret = 0;
 
224
                                        goto out;
 
225
                                } else if (origLoc > packet)
 
226
                                        break;
 
227
                        }
 
228
 
 
229
                        for (l = k; l < reallocationTableLen; l++) {
 
230
                                struct sparingEntry *entry = &st->mapEntry[l];
 
231
                                u32 origLoc = le32_to_cpu(entry->origLocation);
 
232
 
 
233
                                if (origLoc != 0xFFFFFFFF)
 
234
                                        continue;
 
235
 
 
236
                                for (; j < 4; j++) {
 
237
                                        bh = sdata->s_spar_map[j];
 
238
                                        if (!bh)
 
239
                                                continue;
 
240
 
 
241
                                        st = (struct sparingTable *)bh->b_data;
 
242
                                        mapEntry = st->mapEntry[l];
 
243
                                        mapEntry.origLocation =
 
244
                                                        cpu_to_le32(packet);
 
245
                                        memmove(&st->mapEntry[k + 1],
 
246
                                                &st->mapEntry[k],
 
247
                                                (l - k) *
 
248
                                                sizeof(struct sparingEntry));
 
249
                                        st->mapEntry[k] = mapEntry;
 
250
                                        udf_update_tag((char *)st,
 
251
                                                sizeof(struct sparingTable) +
 
252
                                                reallocationTableLen *
 
253
                                                sizeof(struct sparingEntry));
 
254
                                        mark_buffer_dirty(bh);
 
255
                                }
 
256
                                *new_block =
 
257
                                        le32_to_cpu(
 
258
                                              st->mapEntry[k].mappedLocation) +
 
259
                                        ((old_block - map->s_partition_root) &
 
260
                                         (sdata->s_packet_len - 1));
 
261
                                ret = 0;
 
262
                                goto out;
 
263
                        }
 
264
 
 
265
                        ret = 1;
 
266
                        goto out;
 
267
                } /* if old_block */
 
268
        }
 
269
 
 
270
        if (i == sbi->s_partitions) {
 
271
                /* outside of partitions */
 
272
                /* for now, fail =) */
 
273
                ret = 1;
 
274
        }
 
275
 
 
276
out:
 
277
        mutex_unlock(&sbi->s_alloc_mutex);
 
278
        return ret;
 
279
}
 
280
 
 
281
static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
 
282
                                        uint16_t partition, uint32_t offset)
 
283
{
 
284
        struct super_block *sb = inode->i_sb;
 
285
        struct udf_part_map *map;
 
286
        struct kernel_lb_addr eloc;
 
287
        uint32_t elen;
 
288
        sector_t ext_offset;
 
289
        struct extent_position epos = {};
 
290
        uint32_t phyblock;
 
291
 
 
292
        if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
 
293
                                                (EXT_RECORDED_ALLOCATED >> 30))
 
294
                phyblock = 0xFFFFFFFF;
 
295
        else {
 
296
                map = &UDF_SB(sb)->s_partmaps[partition];
 
297
                /* map to sparable/physical partition desc */
 
298
                phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
 
299
                        map->s_partition_num, ext_offset + offset);
 
300
        }
 
301
 
 
302
        brelse(epos.bh);
 
303
        return phyblock;
 
304
}
 
305
 
 
306
uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
 
307
                                uint16_t partition, uint32_t offset)
 
308
{
 
309
        struct udf_sb_info *sbi = UDF_SB(sb);
 
310
        struct udf_part_map *map;
 
311
        struct udf_meta_data *mdata;
 
312
        uint32_t retblk;
 
313
        struct inode *inode;
 
314
 
 
315
        udf_debug("READING from METADATA\n");
 
316
 
 
317
        map = &sbi->s_partmaps[partition];
 
318
        mdata = &map->s_type_specific.s_metadata;
 
319
        inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
 
320
 
 
321
        /* We shouldn't mount such media... */
 
322
        BUG_ON(!inode);
 
323
        retblk = udf_try_read_meta(inode, block, partition, offset);
 
324
        if (retblk == 0xFFFFFFFF && mdata->s_metadata_fe) {
 
325
                udf_warn(sb, "error reading from METADATA, trying to read from MIRROR\n");
 
326
                if (!(mdata->s_flags & MF_MIRROR_FE_LOADED)) {
 
327
                        mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
 
328
                                mdata->s_mirror_file_loc, map->s_partition_num);
 
329
                        mdata->s_flags |= MF_MIRROR_FE_LOADED;
 
330
                }
 
331
 
 
332
                inode = mdata->s_mirror_fe;
 
333
                if (!inode)
 
334
                        return 0xFFFFFFFF;
 
335
                retblk = udf_try_read_meta(inode, block, partition, offset);
 
336
        }
 
337
 
 
338
        return retblk;
 
339
}