1*5ce34554SBagas Sanjaya // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * partition.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * PURPOSE
61da177e4SLinus Torvalds * Partition handling routines for the OSTA-UDF(tm) filesystem.
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * COPYRIGHT
91da177e4SLinus Torvalds * (C) 1998-2001 Ben Fennema
101da177e4SLinus Torvalds *
111da177e4SLinus Torvalds * HISTORY
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * 12/06/98 blf Created file.
141da177e4SLinus Torvalds *
151da177e4SLinus Torvalds */
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #include "udfdecl.h"
181da177e4SLinus Torvalds #include "udf_sb.h"
191da177e4SLinus Torvalds #include "udf_i.h"
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds #include <linux/fs.h>
221da177e4SLinus Torvalds #include <linux/string.h>
237db09be6SAlessio Igor Bogani #include <linux/mutex.h>
241da177e4SLinus Torvalds
udf_get_pblock(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)2522ba0317SAdrian Bunk uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
26cb00ea35SCyrill Gorcunov uint16_t partition, uint32_t offset)
271da177e4SLinus Torvalds {
286c79e987SMarcin Slusarz struct udf_sb_info *sbi = UDF_SB(sb);
296c79e987SMarcin Slusarz struct udf_part_map *map;
306c79e987SMarcin Slusarz if (partition >= sbi->s_partitions) {
31fcbf7637SSteve Magnani udf_debug("block=%u, partition=%u, offset=%u: invalid partition\n",
32a983f368SJoe Perches block, partition, offset);
331da177e4SLinus Torvalds return 0xFFFFFFFF;
341da177e4SLinus Torvalds }
356c79e987SMarcin Slusarz map = &sbi->s_partmaps[partition];
366c79e987SMarcin Slusarz if (map->s_partition_func)
376c79e987SMarcin Slusarz return map->s_partition_func(sb, block, partition, offset);
381da177e4SLinus Torvalds else
396c79e987SMarcin Slusarz return map->s_partition_root + block + offset;
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds
udf_get_pblock_virt15(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)42cb00ea35SCyrill Gorcunov uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block,
43cb00ea35SCyrill Gorcunov uint16_t partition, uint32_t offset)
441da177e4SLinus Torvalds {
451da177e4SLinus Torvalds struct buffer_head *bh = NULL;
461da177e4SLinus Torvalds uint32_t newblock;
471da177e4SLinus Torvalds uint32_t index;
481da177e4SLinus Torvalds uint32_t loc;
496c79e987SMarcin Slusarz struct udf_sb_info *sbi = UDF_SB(sb);
506c79e987SMarcin Slusarz struct udf_part_map *map;
514b11111aSMarcin Slusarz struct udf_virtual_data *vdata;
52fa5e0815SJan Kara struct udf_inode_info *iinfo = UDF_I(sbi->s_vat_inode);
534215db46SJan Kara int err;
541da177e4SLinus Torvalds
556c79e987SMarcin Slusarz map = &sbi->s_partmaps[partition];
564b11111aSMarcin Slusarz vdata = &map->s_type_specific.s_virtual;
571da177e4SLinus Torvalds
584b11111aSMarcin Slusarz if (block > vdata->s_num_entries) {
59fcbf7637SSteve Magnani udf_debug("Trying to access block beyond end of VAT (%u max %u)\n",
60a983f368SJoe Perches block, vdata->s_num_entries);
611da177e4SLinus Torvalds return 0xFFFFFFFF;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds
64fa5e0815SJan Kara if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
65382a2287SJan Kara loc = le32_to_cpu(((__le32 *)(iinfo->i_data +
6647c9358aSSebastian Manciulea vdata->s_start_offset))[block]);
67fa5e0815SJan Kara goto translate;
68fa5e0815SJan Kara }
69fa5e0815SJan Kara index = (sb->s_blocksize - vdata->s_start_offset) / sizeof(uint32_t);
70cb00ea35SCyrill Gorcunov if (block >= index) {
711da177e4SLinus Torvalds block -= index;
721da177e4SLinus Torvalds newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
731da177e4SLinus Torvalds index = block % (sb->s_blocksize / sizeof(uint32_t));
74cb00ea35SCyrill Gorcunov } else {
751da177e4SLinus Torvalds newblock = 0;
764b11111aSMarcin Slusarz index = vdata->s_start_offset / sizeof(uint32_t) + block;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds
794215db46SJan Kara bh = udf_bread(sbi->s_vat_inode, newblock, 0, &err);
804b11111aSMarcin Slusarz if (!bh) {
81f8d0dd0bSTom Rix udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%u,%u)\n",
82f8d0dd0bSTom Rix sb, block, partition);
831da177e4SLinus Torvalds return 0xFFFFFFFF;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);
871da177e4SLinus Torvalds
883bf25cb4SJan Kara brelse(bh);
891da177e4SLinus Torvalds
90fa5e0815SJan Kara translate:
9148d6d8ffSMarcin Slusarz if (iinfo->i_location.partitionReferenceNum == partition) {
921da177e4SLinus Torvalds udf_debug("recursive call to udf_get_pblock!\n");
931da177e4SLinus Torvalds return 0xFFFFFFFF;
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds
96cb00ea35SCyrill Gorcunov return udf_get_pblock(sb, loc,
9748d6d8ffSMarcin Slusarz iinfo->i_location.partitionReferenceNum,
9828de7948SCyrill Gorcunov offset);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds
udf_get_pblock_virt20(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)101cb00ea35SCyrill Gorcunov inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block,
102cb00ea35SCyrill Gorcunov uint16_t partition, uint32_t offset)
1031da177e4SLinus Torvalds {
1041da177e4SLinus Torvalds return udf_get_pblock_virt15(sb, block, partition, offset);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds
udf_get_pblock_spar15(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)107cb00ea35SCyrill Gorcunov uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block,
108cb00ea35SCyrill Gorcunov uint16_t partition, uint32_t offset)
1091da177e4SLinus Torvalds {
1101da177e4SLinus Torvalds int i;
1111da177e4SLinus Torvalds struct sparingTable *st = NULL;
1126c79e987SMarcin Slusarz struct udf_sb_info *sbi = UDF_SB(sb);
1136c79e987SMarcin Slusarz struct udf_part_map *map;
1146c79e987SMarcin Slusarz uint32_t packet;
1154b11111aSMarcin Slusarz struct udf_sparing_data *sdata;
1166c79e987SMarcin Slusarz
1176c79e987SMarcin Slusarz map = &sbi->s_partmaps[partition];
1184b11111aSMarcin Slusarz sdata = &map->s_type_specific.s_sparing;
1194b11111aSMarcin Slusarz packet = (block + offset) & ~(sdata->s_packet_len - 1);
1201da177e4SLinus Torvalds
121cb00ea35SCyrill Gorcunov for (i = 0; i < 4; i++) {
1224b11111aSMarcin Slusarz if (sdata->s_spar_map[i] != NULL) {
1234b11111aSMarcin Slusarz st = (struct sparingTable *)
1244b11111aSMarcin Slusarz sdata->s_spar_map[i]->b_data;
1251da177e4SLinus Torvalds break;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds
129cb00ea35SCyrill Gorcunov if (st) {
130cb00ea35SCyrill Gorcunov for (i = 0; i < le16_to_cpu(st->reallocationTableLen); i++) {
1314b11111aSMarcin Slusarz struct sparingEntry *entry = &st->mapEntry[i];
1324b11111aSMarcin Slusarz u32 origLoc = le32_to_cpu(entry->origLocation);
1334b11111aSMarcin Slusarz if (origLoc >= 0xFFFFFFF0)
1341da177e4SLinus Torvalds break;
1354b11111aSMarcin Slusarz else if (origLoc == packet)
1364b11111aSMarcin Slusarz return le32_to_cpu(entry->mappedLocation) +
1374b11111aSMarcin Slusarz ((block + offset) &
1384b11111aSMarcin Slusarz (sdata->s_packet_len - 1));
1394b11111aSMarcin Slusarz else if (origLoc > packet)
1401da177e4SLinus Torvalds break;
1411da177e4SLinus Torvalds }
1421da177e4SLinus Torvalds }
14328de7948SCyrill Gorcunov
1446c79e987SMarcin Slusarz return map->s_partition_root + block + offset;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds
udf_relocate_blocks(struct super_block * sb,long old_block,long * new_block)1471da177e4SLinus Torvalds int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds struct udf_sparing_data *sdata;
1501da177e4SLinus Torvalds struct sparingTable *st = NULL;
1511da177e4SLinus Torvalds struct sparingEntry mapEntry;
1521da177e4SLinus Torvalds uint32_t packet;
1531da177e4SLinus Torvalds int i, j, k, l;
1546c79e987SMarcin Slusarz struct udf_sb_info *sbi = UDF_SB(sb);
1554b11111aSMarcin Slusarz u16 reallocationTableLen;
1564b11111aSMarcin Slusarz struct buffer_head *bh;
1577db09be6SAlessio Igor Bogani int ret = 0;
1581da177e4SLinus Torvalds
1597db09be6SAlessio Igor Bogani mutex_lock(&sbi->s_alloc_mutex);
1606c79e987SMarcin Slusarz for (i = 0; i < sbi->s_partitions; i++) {
1616c79e987SMarcin Slusarz struct udf_part_map *map = &sbi->s_partmaps[i];
1626c79e987SMarcin Slusarz if (old_block > map->s_partition_root &&
1636c79e987SMarcin Slusarz old_block < map->s_partition_root + map->s_partition_len) {
1646c79e987SMarcin Slusarz sdata = &map->s_type_specific.s_sparing;
1654b11111aSMarcin Slusarz packet = (old_block - map->s_partition_root) &
1664b11111aSMarcin Slusarz ~(sdata->s_packet_len - 1);
1671da177e4SLinus Torvalds
1684b11111aSMarcin Slusarz for (j = 0; j < 4; j++)
1694b11111aSMarcin Slusarz if (sdata->s_spar_map[j] != NULL) {
1704b11111aSMarcin Slusarz st = (struct sparingTable *)
1714b11111aSMarcin Slusarz sdata->s_spar_map[j]->b_data;
1721da177e4SLinus Torvalds break;
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds
1757db09be6SAlessio Igor Bogani if (!st) {
1767db09be6SAlessio Igor Bogani ret = 1;
1777db09be6SAlessio Igor Bogani goto out;
1787db09be6SAlessio Igor Bogani }
1791da177e4SLinus Torvalds
1804b11111aSMarcin Slusarz reallocationTableLen =
1814b11111aSMarcin Slusarz le16_to_cpu(st->reallocationTableLen);
1824b11111aSMarcin Slusarz for (k = 0; k < reallocationTableLen; k++) {
1834b11111aSMarcin Slusarz struct sparingEntry *entry = &st->mapEntry[k];
1844b11111aSMarcin Slusarz u32 origLoc = le32_to_cpu(entry->origLocation);
1854b11111aSMarcin Slusarz
1864b11111aSMarcin Slusarz if (origLoc == 0xFFFFFFFF) {
187cb00ea35SCyrill Gorcunov for (; j < 4; j++) {
1884b11111aSMarcin Slusarz int len;
1894b11111aSMarcin Slusarz bh = sdata->s_spar_map[j];
1904b11111aSMarcin Slusarz if (!bh)
1914b11111aSMarcin Slusarz continue;
1924b11111aSMarcin Slusarz
1934b11111aSMarcin Slusarz st = (struct sparingTable *)
1944b11111aSMarcin Slusarz bh->b_data;
1954b11111aSMarcin Slusarz entry->origLocation =
1964b11111aSMarcin Slusarz cpu_to_le32(packet);
1974b11111aSMarcin Slusarz len =
1984b11111aSMarcin Slusarz sizeof(struct sparingTable) +
1994b11111aSMarcin Slusarz reallocationTableLen *
2004b11111aSMarcin Slusarz sizeof(struct sparingEntry);
2014b11111aSMarcin Slusarz udf_update_tag((char *)st, len);
2024b11111aSMarcin Slusarz mark_buffer_dirty(bh);
2031da177e4SLinus Torvalds }
2044b11111aSMarcin Slusarz *new_block = le32_to_cpu(
2054b11111aSMarcin Slusarz entry->mappedLocation) +
2064b11111aSMarcin Slusarz ((old_block -
2074b11111aSMarcin Slusarz map->s_partition_root) &
2084b11111aSMarcin Slusarz (sdata->s_packet_len - 1));
2097db09be6SAlessio Igor Bogani ret = 0;
2107db09be6SAlessio Igor Bogani goto out;
2114b11111aSMarcin Slusarz } else if (origLoc == packet) {
2124b11111aSMarcin Slusarz *new_block = le32_to_cpu(
2134b11111aSMarcin Slusarz entry->mappedLocation) +
2144b11111aSMarcin Slusarz ((old_block -
2154b11111aSMarcin Slusarz map->s_partition_root) &
2164b11111aSMarcin Slusarz (sdata->s_packet_len - 1));
2177db09be6SAlessio Igor Bogani ret = 0;
2187db09be6SAlessio Igor Bogani goto out;
2194b11111aSMarcin Slusarz } else if (origLoc > packet)
2201da177e4SLinus Torvalds break;
2211da177e4SLinus Torvalds }
22228de7948SCyrill Gorcunov
2234b11111aSMarcin Slusarz for (l = k; l < reallocationTableLen; l++) {
2244b11111aSMarcin Slusarz struct sparingEntry *entry = &st->mapEntry[l];
2254b11111aSMarcin Slusarz u32 origLoc = le32_to_cpu(entry->origLocation);
2264b11111aSMarcin Slusarz
2274b11111aSMarcin Slusarz if (origLoc != 0xFFFFFFFF)
2284b11111aSMarcin Slusarz continue;
2294b11111aSMarcin Slusarz
230cb00ea35SCyrill Gorcunov for (; j < 4; j++) {
2314b11111aSMarcin Slusarz bh = sdata->s_spar_map[j];
2324b11111aSMarcin Slusarz if (!bh)
2334b11111aSMarcin Slusarz continue;
2344b11111aSMarcin Slusarz
2354b11111aSMarcin Slusarz st = (struct sparingTable *)bh->b_data;
23628de7948SCyrill Gorcunov mapEntry = st->mapEntry[l];
2374b11111aSMarcin Slusarz mapEntry.origLocation =
2384b11111aSMarcin Slusarz cpu_to_le32(packet);
2394b11111aSMarcin Slusarz memmove(&st->mapEntry[k + 1],
2404b11111aSMarcin Slusarz &st->mapEntry[k],
2414b11111aSMarcin Slusarz (l - k) *
2424b11111aSMarcin Slusarz sizeof(struct sparingEntry));
24328de7948SCyrill Gorcunov st->mapEntry[k] = mapEntry;
2444b11111aSMarcin Slusarz udf_update_tag((char *)st,
2454b11111aSMarcin Slusarz sizeof(struct sparingTable) +
2464b11111aSMarcin Slusarz reallocationTableLen *
2474b11111aSMarcin Slusarz sizeof(struct sparingEntry));
2484b11111aSMarcin Slusarz mark_buffer_dirty(bh);
2491da177e4SLinus Torvalds }
2504b11111aSMarcin Slusarz *new_block =
2514b11111aSMarcin Slusarz le32_to_cpu(
2524b11111aSMarcin Slusarz st->mapEntry[k].mappedLocation) +
2534b11111aSMarcin Slusarz ((old_block - map->s_partition_root) &
2544b11111aSMarcin Slusarz (sdata->s_packet_len - 1));
2557db09be6SAlessio Igor Bogani ret = 0;
2567db09be6SAlessio Igor Bogani goto out;
2571da177e4SLinus Torvalds }
25828de7948SCyrill Gorcunov
2597db09be6SAlessio Igor Bogani ret = 1;
2607db09be6SAlessio Igor Bogani goto out;
26128de7948SCyrill Gorcunov } /* if old_block */
2621da177e4SLinus Torvalds }
26328de7948SCyrill Gorcunov
2646c79e987SMarcin Slusarz if (i == sbi->s_partitions) {
2651da177e4SLinus Torvalds /* outside of partitions */
2661da177e4SLinus Torvalds /* for now, fail =) */
2677db09be6SAlessio Igor Bogani ret = 1;
2681da177e4SLinus Torvalds }
2691da177e4SLinus Torvalds
2707db09be6SAlessio Igor Bogani out:
2717db09be6SAlessio Igor Bogani mutex_unlock(&sbi->s_alloc_mutex);
2727db09be6SAlessio Igor Bogani return ret;
2731da177e4SLinus Torvalds }
274bfb257a5SJan Kara
udf_try_read_meta(struct inode * inode,uint32_t block,uint16_t partition,uint32_t offset)275bfb257a5SJan Kara static uint32_t udf_try_read_meta(struct inode *inode, uint32_t block,
276bfb257a5SJan Kara uint16_t partition, uint32_t offset)
277bfb257a5SJan Kara {
278bfb257a5SJan Kara struct super_block *sb = inode->i_sb;
279bfb257a5SJan Kara struct udf_part_map *map;
2805ca4e4beSPekka Enberg struct kernel_lb_addr eloc;
281bfb257a5SJan Kara uint32_t elen;
282bfb257a5SJan Kara sector_t ext_offset;
283bfb257a5SJan Kara struct extent_position epos = {};
284bfb257a5SJan Kara uint32_t phyblock;
285bfb257a5SJan Kara
286bfb257a5SJan Kara if (inode_bmap(inode, block, &epos, &eloc, &elen, &ext_offset) !=
287bfb257a5SJan Kara (EXT_RECORDED_ALLOCATED >> 30))
288bfb257a5SJan Kara phyblock = 0xFFFFFFFF;
289bfb257a5SJan Kara else {
290bfb257a5SJan Kara map = &UDF_SB(sb)->s_partmaps[partition];
291bfb257a5SJan Kara /* map to sparable/physical partition desc */
292bfb257a5SJan Kara phyblock = udf_get_pblock(sb, eloc.logicalBlockNum,
2937888824bSAlden Tondettar map->s_type_specific.s_metadata.s_phys_partition_ref,
2947888824bSAlden Tondettar ext_offset + offset);
295bfb257a5SJan Kara }
296bfb257a5SJan Kara
297bfb257a5SJan Kara brelse(epos.bh);
298bfb257a5SJan Kara return phyblock;
299bfb257a5SJan Kara }
300bfb257a5SJan Kara
udf_get_pblock_meta25(struct super_block * sb,uint32_t block,uint16_t partition,uint32_t offset)301bfb257a5SJan Kara uint32_t udf_get_pblock_meta25(struct super_block *sb, uint32_t block,
302bfb257a5SJan Kara uint16_t partition, uint32_t offset)
303bfb257a5SJan Kara {
304bfb257a5SJan Kara struct udf_sb_info *sbi = UDF_SB(sb);
305bfb257a5SJan Kara struct udf_part_map *map;
306bfb257a5SJan Kara struct udf_meta_data *mdata;
307bfb257a5SJan Kara uint32_t retblk;
308bfb257a5SJan Kara struct inode *inode;
309bfb257a5SJan Kara
310bfb257a5SJan Kara udf_debug("READING from METADATA\n");
311bfb257a5SJan Kara
312bfb257a5SJan Kara map = &sbi->s_partmaps[partition];
313bfb257a5SJan Kara mdata = &map->s_type_specific.s_metadata;
314bfb257a5SJan Kara inode = mdata->s_metadata_fe ? : mdata->s_mirror_fe;
315bfb257a5SJan Kara
316585d7000SAlden Tondettar if (!inode)
317585d7000SAlden Tondettar return 0xFFFFFFFF;
318585d7000SAlden Tondettar
319bfb257a5SJan Kara retblk = udf_try_read_meta(inode, block, partition, offset);
3203080a74eSNamjae Jeon if (retblk == 0xFFFFFFFF && mdata->s_metadata_fe) {
321a40ecd7bSJoe Perches udf_warn(sb, "error reading from METADATA, trying to read from MIRROR\n");
322ed47a7d0SJan Kara if (!(mdata->s_flags & MF_MIRROR_FE_LOADED)) {
3233080a74eSNamjae Jeon mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb,
3247888824bSAlden Tondettar mdata->s_mirror_file_loc,
3257888824bSAlden Tondettar mdata->s_phys_partition_ref);
3263743a03eSAlden Tondettar if (IS_ERR(mdata->s_mirror_fe))
3273743a03eSAlden Tondettar mdata->s_mirror_fe = NULL;
328ed47a7d0SJan Kara mdata->s_flags |= MF_MIRROR_FE_LOADED;
3293080a74eSNamjae Jeon }
3303080a74eSNamjae Jeon
331bfb257a5SJan Kara inode = mdata->s_mirror_fe;
332bfb257a5SJan Kara if (!inode)
333bfb257a5SJan Kara return 0xFFFFFFFF;
334bfb257a5SJan Kara retblk = udf_try_read_meta(inode, block, partition, offset);
335bfb257a5SJan Kara }
336bfb257a5SJan Kara
337bfb257a5SJan Kara return retblk;
338bfb257a5SJan Kara }
339