xref: /linux/fs/udf/partition.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
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