nfsd4: set shorter timeout
[safe/jmp/linux-2.6] / fs / udf / partition.c
index 4d36f26..4b540ee 100644 (file)
@@ -4,11 +4,6 @@
  * PURPOSE
  *      Partition handling routines for the OSTA-UDF(tm) filesystem.
  *
- * CONTACTS
- *      E-mail regarding any portion of the Linux UDF file system should be
- *      directed to the development team mailing list (run by majordomo):
- *              linux_udf@hpesjro.fc.hp.com
- *
  * COPYRIGHT
  *      This file is distributed under the terms of the GNU General Public
  *      License (GPL). Copies of the GPL can be obtained from:
@@ -19,7 +14,7 @@
  *
  * HISTORY
  *
- * 12/06/98 blf  Created file. 
+ * 12/06/98 blf  Created file.
  *
  */
 
 
 #include <linux/fs.h>
 #include <linux/string.h>
-#include <linux/udf_fs.h>
 #include <linux/slab.h>
 #include <linux/buffer_head.h>
 
-inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
+                       uint16_t partition, uint32_t offset)
 {
-       if (partition >= UDF_SB_NUMPARTS(sb))
-       {
-               udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
-                       block, partition, offset);
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map;
+       if (partition >= sbi->s_partitions) {
+               udf_debug("block=%d, partition=%d, offset=%d: "
+                         "invalid partition\n", block, partition, offset);
                return 0xFFFFFFFF;
        }
-       if (UDF_SB_PARTFUNC(sb, partition))
-               return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
+       map = &sbi->s_partmaps[partition];
+       if (map->s_partition_func)
+               return map->s_partition_func(sb, block, partition, offset);
        else
-               return UDF_SB_PARTROOT(sb, partition) + block + offset;
+               return map->s_partition_root + block + offset;
 }
 
-uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
+                              uint16_t partition, uint32_t offset)
 {
        struct buffer_head *bh = NULL;
        uint32_t newblock;
        uint32_t index;
        uint32_t loc;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map;
+       struct udf_virtual_data *vdata;
+       struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
 
-       index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);
+       map = &sbi->s_partmaps[partition];
+       vdata = &map->s_type_specific.s_virtual;
 
-       if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
-       {
-               udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
-                       block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
+       if (block > vdata->s_num_entries) {
+               udf_debug("Trying to access block beyond end of VAT "
+                         "(%d max %d)\n", block, vdata->s_num_entries);
                return 0xFFFFFFFF;
        }
 
-       if (block >= index)
-       {
+       if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
+               loc = le32_to_cpu(((__le32 *)(iinfo->i_ext.i_data +
+                       vdata->s_start_offset))[block]);
+               goto translate;
+       }
+       index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
+       if (block >= index) {
                block -= index;
                newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
                index = block % (sb->s_blocksize / sizeof(uint32_t));
-       }
-       else
-       {
+       } else {
                newblock = 0;
-               index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
+               index = vdata->s_start_offset / sizeof(uint32_t) + block;
        }
 
-       loc = udf_block_map(UDF_SB_VAT(sb), newblock);
+       loc = udf_block_map(sbi->s_vat_inode, newblock);
 
-       if (!(bh = sb_bread(sb, loc)))
-       {
+       bh = sb_bread(sb, loc);
+       if (!bh) {
                udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
-                       sb, block, partition, loc, index);
+                         sb, block, partition, loc, index);
                return 0xFFFFFFFF;
        }
 
        loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
 
-       udf_release_data(bh);
+       brelse(bh);
 
-       if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
-       {
+translate:
+       if (iinfo->i_location.partitionReferenceNum == partition) {
                udf_debug("recursive call to udf_get_pblock!\n");
                return 0xFFFFFFFF;
        }
 
-       return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
+       return udf_get_pblock(sb, loc,
+                             iinfo->i_location.partitionReferenceNum,
+                             offset);
 }
 
-inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
+                                     uint16_t partition, uint32_t offset)
 {
        return udf_get_pblock_virt15(sb, block, partition, offset);
 }
 
-uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
+                              uint16_t partition, uint32_t offset)
 {
        int i;
        struct sparingTable *st = NULL;
-       uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map;
+       uint32_t packet;
+       struct udf_sparing_data *sdata;
+
+       map = &sbi->s_partmaps[partition];
+       sdata = &map->s_type_specific.s_sparing;
+       packet = (block + offset) & ~(sdata->s_packet_len - 1);
 
-       for (i=0; i<4; i++)
-       {
-               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;
+       for (i = 0; i < 4; i++) {
+               if (sdata->s_spar_map[i] != NULL) {
+                       st = (struct sparingTable *)
+                                       sdata->s_spar_map[i]->b_data;
                        break;
                }
        }
 
-       if (st)
-       {
-               for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
-               {
-                       if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
+       if (st) {
+               for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
+                       struct sparingEntry *entry = &st->mapEntry[i];
+                       u32 origLoc = le32_to_cpu(entry->origLocation);
+                       if (origLoc >= 0xFFFFFFF0)
                                break;
-                       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)
+                       else if (origLoc == packet)
+                               return le32_to_cpu(entry->mappedLocation) +
+                                       ((block + offset) &
+                                               (sdata->s_packet_len - 1));
+                       else if (origLoc > packet)
                                break;
                }
        }
-       return UDF_SB_PARTROOT(sb,partition) + block + offset;
+
+       return map->s_partition_root + block + offset;
 }
 
 int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
@@ -142,81 +157,109 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
        struct sparingEntry mapEntry;
        uint32_t packet;
        int i, j, k, l;
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       u16 reallocationTableLen;
+       struct buffer_head *bh;
+
+       for (i = 0; i < sbi->s_partitions; i++) {
+               struct udf_part_map *map = &sbi->s_partmaps[i];
+               if (old_block > map->s_partition_root &&
+                   old_block < map->s_partition_root + map->s_partition_len) {
+                       sdata = &map->s_type_specific.s_sparing;
+                       packet = (old_block - map->s_partition_root) &
+                                               ~(sdata->s_packet_len - 1);
 
-       for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
-       {
-               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);
-
-                       for (j=0; j<4; j++)
-                       {
-                               if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
-                               {
-                                       st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
+                       for (j = 0; j < 4; j++)
+                               if (sdata->s_spar_map[j] != NULL) {
+                                       st = (struct sparingTable *)
+                                               sdata->s_spar_map[j]->b_data;
                                        break;
                                }
-                       }
 
                        if (!st)
                                return 1;
 
-                       for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
-                       {
-                               if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
-                               {
-                                       for (; j<4; j++)
-                                       {
-                                               if (sdata->s_spar_map[j])
-                                               {
-                                                       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]);
-                                               }
+                       reallocationTableLen =
+                                       le16_to_cpu(st->reallocationTableLen);
+                       for (k = 0; k < reallocationTableLen; k++) {
+                               struct sparingEntry *entry = &st->mapEntry[k];
+                               u32 origLoc = le32_to_cpu(entry->origLocation);
+
+                               if (origLoc == 0xFFFFFFFF) {
+                                       for (; j < 4; j++) {
+                                               int len;
+                                               bh = sdata->s_spar_map[j];
+                                               if (!bh)
+                                                       continue;
+
+                                               st = (struct sparingTable *)
+                                                               bh->b_data;
+                                               entry->origLocation =
+                                                       cpu_to_le32(packet);
+                                               len =
+                                                 sizeof(struct sparingTable) +
+                                                 reallocationTableLen *
+                                                 sizeof(struct sparingEntry);
+                                               udf_update_tag((char *)st, len);
+                                               mark_buffer_dirty(bh);
                                        }
-                                       *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
-                                               ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
+                                       *new_block = le32_to_cpu(
+                                                       entry->mappedLocation) +
+                                                    ((old_block -
+                                                       map->s_partition_root) &
+                                                    (sdata->s_packet_len - 1));
                                        return 0;
-                               }
-                               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));
+                               } else if (origLoc == packet) {
+                                       *new_block = le32_to_cpu(
+                                                       entry->mappedLocation) +
+                                                    ((old_block -
+                                                       map->s_partition_root) &
+                                                    (sdata->s_packet_len - 1));
                                        return 0;
-                               }
-                               else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
+                               } else if (origLoc > packet)
                                        break;
                        }
-                       for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
-                       {
-                               if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
-                               {
-                                       for (; j<4; j++)
-                                       {
-                                               if (sdata->s_spar_map[j])
-                                               {
-                                                       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]);
-                                               }
-                                       }
-                                       *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
-                                               ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
-                                       return 0;
+
+                       for (l = k; l < reallocationTableLen; l++) {
+                               struct sparingEntry *entry = &st->mapEntry[l];
+                               u32 origLoc = le32_to_cpu(entry->origLocation);
+
+                               if (origLoc != 0xFFFFFFFF)
+                                       continue;
+
+                               for (; j < 4; j++) {
+                                       bh = sdata->s_spar_map[j];
+                                       if (!bh)
+                                               continue;
+
+                                       st = (struct sparingTable *)bh->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) +
+                                               reallocationTableLen *
+                                               sizeof(struct sparingEntry));
+                                       mark_buffer_dirty(bh);
                                }
+                               *new_block =
+                                       le32_to_cpu(
+                                             st->mapEntry[k].mappedLocation) +
+                                       ((old_block - map->s_partition_root) &
+                                        (sdata->s_packet_len - 1));
+                               return 0;
                        }
+
                        return 1;
-               }
+               } /* if old_block */
        }
-       if (i == UDF_SB_NUMPARTS(sb))
-       {
+
+       if (i == sbi->s_partitions) {
                /* outside of partitions */
                /* for now, fail =) */
                return 1;
@@ -224,3 +267,58 @@ int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
 
        return 0;
 }
+
+static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
+                                       uint16_t partition, uint32_t offset)
+{
+       struct super_block *sb = inode->i_sb;
+       struct udf_part_map *map;
+       struct kernel_lb_addr eloc;
+       uint32_t elen;
+       sector_t ext_offset;
+       struct extent_position epos = {};
+       uint32_t phyblock;
+
+       if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
+                                               (EXT_RECORDED_ALLOCATED >> 30))
+               phyblock = 0xFFFFFFFF;
+       else {
+               map = &UDF_SB(sb)->s_partmaps[partition];
+               /* map to sparable/physical partition desc */
+               phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
+                       map->s_partition_num, ext_offset + offset);
+       }
+
+       brelse(epos.bh);
+       return phyblock;
+}
+
+uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
+                               uint16_t partition, uint32_t offset)
+{
+       struct udf_sb_info *sbi = UDF_SB(sb);
+       struct udf_part_map *map;
+       struct udf_meta_data *mdata;
+       uint32_t retblk;
+       struct inode *inode;
+
+       udf_debug("READING from METADATA\n");
+
+       map = &sbi->s_partmaps[partition];
+       mdata = &map->s_type_specific.s_metadata;
+       inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
+
+       /* We shouldn't mount such media... */
+       BUG_ON(!inode);
+       retblk = udf_try_read_meta(inode, block, partition, offset);
+       if (retblk == 0xFFFFFFFF) {
+               udf_warning(sb, __func__, "error reading from METADATA, "
+                       "trying to read from MIRROR");
+               inode = mdata->s_mirror_fe;
+               if (!inode)
+                       return 0xFFFFFFFF;
+               retblk = udf_try_read_meta(inode, block, partition, offset);
+       }
+
+       return retblk;
+}