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