18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * super.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * PURPOSE 58c2ecf20Sopenharmony_ci * Super block routines for the OSTA-UDF(tm) filesystem. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * DESCRIPTION 88c2ecf20Sopenharmony_ci * OSTA-UDF(tm) = Optical Storage Technology Association 98c2ecf20Sopenharmony_ci * Universal Disk Format. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This code is based on version 2.00 of the UDF specification, 128c2ecf20Sopenharmony_ci * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. 138c2ecf20Sopenharmony_ci * http://www.osta.org/ 148c2ecf20Sopenharmony_ci * https://www.ecma.ch/ 158c2ecf20Sopenharmony_ci * https://www.iso.org/ 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * COPYRIGHT 188c2ecf20Sopenharmony_ci * This file is distributed under the terms of the GNU General Public 198c2ecf20Sopenharmony_ci * License (GPL). Copies of the GPL can be obtained from: 208c2ecf20Sopenharmony_ci * ftp://prep.ai.mit.edu/pub/gnu/GPL 218c2ecf20Sopenharmony_ci * Each contributing author retains all rights to their own work. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * (C) 1998 Dave Boynton 248c2ecf20Sopenharmony_ci * (C) 1998-2004 Ben Fennema 258c2ecf20Sopenharmony_ci * (C) 2000 Stelias Computing Inc 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * HISTORY 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * 09/24/98 dgb changed to allow compiling outside of kernel, and 308c2ecf20Sopenharmony_ci * added some debugging. 318c2ecf20Sopenharmony_ci * 10/01/98 dgb updated to allow (some) possibility of compiling w/2.0.34 328c2ecf20Sopenharmony_ci * 10/16/98 attempting some multi-session support 338c2ecf20Sopenharmony_ci * 10/17/98 added freespace count for "df" 348c2ecf20Sopenharmony_ci * 11/11/98 gr added novrs option 358c2ecf20Sopenharmony_ci * 11/26/98 dgb added fileset,anchor mount options 368c2ecf20Sopenharmony_ci * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced 378c2ecf20Sopenharmony_ci * vol descs. rewrote option handling based on isofs 388c2ecf20Sopenharmony_ci * 12/20/98 find the free space bitmap (if it exists) 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "udfdecl.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 448c2ecf20Sopenharmony_ci#include <linux/slab.h> 458c2ecf20Sopenharmony_ci#include <linux/kernel.h> 468c2ecf20Sopenharmony_ci#include <linux/module.h> 478c2ecf20Sopenharmony_ci#include <linux/parser.h> 488c2ecf20Sopenharmony_ci#include <linux/stat.h> 498c2ecf20Sopenharmony_ci#include <linux/cdrom.h> 508c2ecf20Sopenharmony_ci#include <linux/nls.h> 518c2ecf20Sopenharmony_ci#include <linux/vfs.h> 528c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 538c2ecf20Sopenharmony_ci#include <linux/errno.h> 548c2ecf20Sopenharmony_ci#include <linux/mount.h> 558c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 568c2ecf20Sopenharmony_ci#include <linux/bitmap.h> 578c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 588c2ecf20Sopenharmony_ci#include <linux/log2.h> 598c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 608c2ecf20Sopenharmony_ci#include <linux/iversion.h> 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#include "udf_sb.h" 638c2ecf20Sopenharmony_ci#include "udf_i.h" 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#include <linux/init.h> 668c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cienum { 698c2ecf20Sopenharmony_ci VDS_POS_PRIMARY_VOL_DESC, 708c2ecf20Sopenharmony_ci VDS_POS_UNALLOC_SPACE_DESC, 718c2ecf20Sopenharmony_ci VDS_POS_LOGICAL_VOL_DESC, 728c2ecf20Sopenharmony_ci VDS_POS_IMP_USE_VOL_DESC, 738c2ecf20Sopenharmony_ci VDS_POS_LENGTH 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define VSD_FIRST_SECTOR_OFFSET 32768 778c2ecf20Sopenharmony_ci#define VSD_MAX_SECTOR_OFFSET 0x800000 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * Maximum number of Terminating Descriptor / Logical Volume Integrity 818c2ecf20Sopenharmony_ci * Descriptor redirections. The chosen numbers are arbitrary - just that we 828c2ecf20Sopenharmony_ci * hopefully don't limit any real use of rewritten inode on write-once media 838c2ecf20Sopenharmony_ci * but avoid looping for too long on corrupted media. 848c2ecf20Sopenharmony_ci */ 858c2ecf20Sopenharmony_ci#define UDF_MAX_TD_NESTING 64 868c2ecf20Sopenharmony_ci#define UDF_MAX_LVID_NESTING 1000 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cienum { UDF_MAX_LINKS = 0xffff }; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* These are the "meat" - everything else is stuffing */ 918c2ecf20Sopenharmony_cistatic int udf_fill_super(struct super_block *, void *, int); 928c2ecf20Sopenharmony_cistatic void udf_put_super(struct super_block *); 938c2ecf20Sopenharmony_cistatic int udf_sync_fs(struct super_block *, int); 948c2ecf20Sopenharmony_cistatic int udf_remount_fs(struct super_block *, int *, char *); 958c2ecf20Sopenharmony_cistatic void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad); 968c2ecf20Sopenharmony_cistatic void udf_open_lvid(struct super_block *); 978c2ecf20Sopenharmony_cistatic void udf_close_lvid(struct super_block *); 988c2ecf20Sopenharmony_cistatic unsigned int udf_count_free(struct super_block *); 998c2ecf20Sopenharmony_cistatic int udf_statfs(struct dentry *, struct kstatfs *); 1008c2ecf20Sopenharmony_cistatic int udf_show_options(struct seq_file *, struct dentry *); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistruct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 1058c2ecf20Sopenharmony_ci unsigned int partnum; 1068c2ecf20Sopenharmony_ci unsigned int offset; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (!UDF_SB(sb)->s_lvid_bh) 1098c2ecf20Sopenharmony_ci return NULL; 1108c2ecf20Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data; 1118c2ecf20Sopenharmony_ci partnum = le32_to_cpu(lvid->numOfPartitions); 1128c2ecf20Sopenharmony_ci /* The offset is to skip freeSpaceTable and sizeTable arrays */ 1138c2ecf20Sopenharmony_ci offset = partnum * 2 * sizeof(uint32_t); 1148c2ecf20Sopenharmony_ci return (struct logicalVolIntegrityDescImpUse *) 1158c2ecf20Sopenharmony_ci (((uint8_t *)(lvid + 1)) + offset); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* UDF filesystem type */ 1198c2ecf20Sopenharmony_cistatic struct dentry *udf_mount(struct file_system_type *fs_type, 1208c2ecf20Sopenharmony_ci int flags, const char *dev_name, void *data) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, udf_fill_super); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct file_system_type udf_fstype = { 1268c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 1278c2ecf20Sopenharmony_ci .name = "udf", 1288c2ecf20Sopenharmony_ci .mount = udf_mount, 1298c2ecf20Sopenharmony_ci .kill_sb = kill_block_super, 1308c2ecf20Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ciMODULE_ALIAS_FS("udf"); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic struct kmem_cache *udf_inode_cachep; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic struct inode *udf_alloc_inode(struct super_block *sb) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct udf_inode_info *ei; 1398c2ecf20Sopenharmony_ci ei = kmem_cache_alloc(udf_inode_cachep, GFP_KERNEL); 1408c2ecf20Sopenharmony_ci if (!ei) 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci ei->i_unique = 0; 1448c2ecf20Sopenharmony_ci ei->i_lenExtents = 0; 1458c2ecf20Sopenharmony_ci ei->i_lenStreams = 0; 1468c2ecf20Sopenharmony_ci ei->i_next_alloc_block = 0; 1478c2ecf20Sopenharmony_ci ei->i_next_alloc_goal = 0; 1488c2ecf20Sopenharmony_ci ei->i_strat4096 = 0; 1498c2ecf20Sopenharmony_ci ei->i_streamdir = 0; 1508c2ecf20Sopenharmony_ci ei->i_hidden = 0; 1518c2ecf20Sopenharmony_ci init_rwsem(&ei->i_data_sem); 1528c2ecf20Sopenharmony_ci ei->cached_extent.lstart = -1; 1538c2ecf20Sopenharmony_ci spin_lock_init(&ei->i_extent_cache_lock); 1548c2ecf20Sopenharmony_ci inode_set_iversion(&ei->vfs_inode, 1); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return &ei->vfs_inode; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_cistatic void udf_free_in_core_inode(struct inode *inode) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci kmem_cache_free(udf_inode_cachep, UDF_I(inode)); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void init_once(void *foo) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct udf_inode_info *ei = (struct udf_inode_info *)foo; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci ei->i_data = NULL; 1698c2ecf20Sopenharmony_ci inode_init_once(&ei->vfs_inode); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int __init init_inodecache(void) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci udf_inode_cachep = kmem_cache_create("udf_inode_cache", 1758c2ecf20Sopenharmony_ci sizeof(struct udf_inode_info), 1768c2ecf20Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT | 1778c2ecf20Sopenharmony_ci SLAB_MEM_SPREAD | 1788c2ecf20Sopenharmony_ci SLAB_ACCOUNT), 1798c2ecf20Sopenharmony_ci init_once); 1808c2ecf20Sopenharmony_ci if (!udf_inode_cachep) 1818c2ecf20Sopenharmony_ci return -ENOMEM; 1828c2ecf20Sopenharmony_ci return 0; 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic void destroy_inodecache(void) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 1898c2ecf20Sopenharmony_ci * destroy cache. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci rcu_barrier(); 1928c2ecf20Sopenharmony_ci kmem_cache_destroy(udf_inode_cachep); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* Superblock operations */ 1968c2ecf20Sopenharmony_cistatic const struct super_operations udf_sb_ops = { 1978c2ecf20Sopenharmony_ci .alloc_inode = udf_alloc_inode, 1988c2ecf20Sopenharmony_ci .free_inode = udf_free_in_core_inode, 1998c2ecf20Sopenharmony_ci .write_inode = udf_write_inode, 2008c2ecf20Sopenharmony_ci .evict_inode = udf_evict_inode, 2018c2ecf20Sopenharmony_ci .put_super = udf_put_super, 2028c2ecf20Sopenharmony_ci .sync_fs = udf_sync_fs, 2038c2ecf20Sopenharmony_ci .statfs = udf_statfs, 2048c2ecf20Sopenharmony_ci .remount_fs = udf_remount_fs, 2058c2ecf20Sopenharmony_ci .show_options = udf_show_options, 2068c2ecf20Sopenharmony_ci}; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistruct udf_options { 2098c2ecf20Sopenharmony_ci unsigned char novrs; 2108c2ecf20Sopenharmony_ci unsigned int blocksize; 2118c2ecf20Sopenharmony_ci unsigned int session; 2128c2ecf20Sopenharmony_ci unsigned int lastblock; 2138c2ecf20Sopenharmony_ci unsigned int anchor; 2148c2ecf20Sopenharmony_ci unsigned int flags; 2158c2ecf20Sopenharmony_ci umode_t umask; 2168c2ecf20Sopenharmony_ci kgid_t gid; 2178c2ecf20Sopenharmony_ci kuid_t uid; 2188c2ecf20Sopenharmony_ci umode_t fmode; 2198c2ecf20Sopenharmony_ci umode_t dmode; 2208c2ecf20Sopenharmony_ci struct nls_table *nls_map; 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int __init init_udf_fs(void) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci int err; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci err = init_inodecache(); 2288c2ecf20Sopenharmony_ci if (err) 2298c2ecf20Sopenharmony_ci goto out1; 2308c2ecf20Sopenharmony_ci err = register_filesystem(&udf_fstype); 2318c2ecf20Sopenharmony_ci if (err) 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ciout: 2378c2ecf20Sopenharmony_ci destroy_inodecache(); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciout1: 2408c2ecf20Sopenharmony_ci return err; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void __exit exit_udf_fs(void) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci unregister_filesystem(&udf_fstype); 2468c2ecf20Sopenharmony_ci destroy_inodecache(); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci sbi->s_partmaps = kcalloc(count, sizeof(*sbi->s_partmaps), GFP_KERNEL); 2548c2ecf20Sopenharmony_ci if (!sbi->s_partmaps) { 2558c2ecf20Sopenharmony_ci sbi->s_partitions = 0; 2568c2ecf20Sopenharmony_ci return -ENOMEM; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci sbi->s_partitions = count; 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void udf_sb_free_bitmap(struct udf_bitmap *bitmap) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci int i; 2668c2ecf20Sopenharmony_ci int nr_groups = bitmap->s_nr_groups; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci for (i = 0; i < nr_groups; i++) 2698c2ecf20Sopenharmony_ci brelse(bitmap->s_block_bitmap[i]); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci kvfree(bitmap); 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cistatic void udf_free_partition(struct udf_part_map *map) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int i; 2778c2ecf20Sopenharmony_ci struct udf_meta_data *mdata; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) 2808c2ecf20Sopenharmony_ci iput(map->s_uspace.s_table); 2818c2ecf20Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) 2828c2ecf20Sopenharmony_ci udf_sb_free_bitmap(map->s_uspace.s_bitmap); 2838c2ecf20Sopenharmony_ci if (map->s_partition_type == UDF_SPARABLE_MAP15) 2848c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 2858c2ecf20Sopenharmony_ci brelse(map->s_type_specific.s_sparing.s_spar_map[i]); 2868c2ecf20Sopenharmony_ci else if (map->s_partition_type == UDF_METADATA_MAP25) { 2878c2ecf20Sopenharmony_ci mdata = &map->s_type_specific.s_metadata; 2888c2ecf20Sopenharmony_ci iput(mdata->s_metadata_fe); 2898c2ecf20Sopenharmony_ci mdata->s_metadata_fe = NULL; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci iput(mdata->s_mirror_fe); 2928c2ecf20Sopenharmony_ci mdata->s_mirror_fe = NULL; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci iput(mdata->s_bitmap_fe); 2958c2ecf20Sopenharmony_ci mdata->s_bitmap_fe = NULL; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void udf_sb_free_partitions(struct super_block *sb) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 3028c2ecf20Sopenharmony_ci int i; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (!sbi->s_partmaps) 3058c2ecf20Sopenharmony_ci return; 3068c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_partitions; i++) 3078c2ecf20Sopenharmony_ci udf_free_partition(&sbi->s_partmaps[i]); 3088c2ecf20Sopenharmony_ci kfree(sbi->s_partmaps); 3098c2ecf20Sopenharmony_ci sbi->s_partmaps = NULL; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int udf_show_options(struct seq_file *seq, struct dentry *root) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct super_block *sb = root->d_sb; 3158c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) 3188c2ecf20Sopenharmony_ci seq_puts(seq, ",nostrict"); 3198c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET)) 3208c2ecf20Sopenharmony_ci seq_printf(seq, ",bs=%lu", sb->s_blocksize); 3218c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) 3228c2ecf20Sopenharmony_ci seq_puts(seq, ",unhide"); 3238c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) 3248c2ecf20Sopenharmony_ci seq_puts(seq, ",undelete"); 3258c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_USE_AD_IN_ICB)) 3268c2ecf20Sopenharmony_ci seq_puts(seq, ",noadinicb"); 3278c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_USE_SHORT_AD)) 3288c2ecf20Sopenharmony_ci seq_puts(seq, ",shortad"); 3298c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET)) 3308c2ecf20Sopenharmony_ci seq_puts(seq, ",uid=forget"); 3318c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET)) 3328c2ecf20Sopenharmony_ci seq_puts(seq, ",gid=forget"); 3338c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET)) 3348c2ecf20Sopenharmony_ci seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid)); 3358c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET)) 3368c2ecf20Sopenharmony_ci seq_printf(seq, ",gid=%u", from_kgid(&init_user_ns, sbi->s_gid)); 3378c2ecf20Sopenharmony_ci if (sbi->s_umask != 0) 3388c2ecf20Sopenharmony_ci seq_printf(seq, ",umask=%ho", sbi->s_umask); 3398c2ecf20Sopenharmony_ci if (sbi->s_fmode != UDF_INVALID_MODE) 3408c2ecf20Sopenharmony_ci seq_printf(seq, ",mode=%ho", sbi->s_fmode); 3418c2ecf20Sopenharmony_ci if (sbi->s_dmode != UDF_INVALID_MODE) 3428c2ecf20Sopenharmony_ci seq_printf(seq, ",dmode=%ho", sbi->s_dmode); 3438c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET)) 3448c2ecf20Sopenharmony_ci seq_printf(seq, ",session=%d", sbi->s_session); 3458c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET)) 3468c2ecf20Sopenharmony_ci seq_printf(seq, ",lastblock=%u", sbi->s_last_block); 3478c2ecf20Sopenharmony_ci if (sbi->s_anchor != 0) 3488c2ecf20Sopenharmony_ci seq_printf(seq, ",anchor=%u", sbi->s_anchor); 3498c2ecf20Sopenharmony_ci if (sbi->s_nls_map) 3508c2ecf20Sopenharmony_ci seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset); 3518c2ecf20Sopenharmony_ci else 3528c2ecf20Sopenharmony_ci seq_puts(seq, ",iocharset=utf8"); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* 3588c2ecf20Sopenharmony_ci * udf_parse_options 3598c2ecf20Sopenharmony_ci * 3608c2ecf20Sopenharmony_ci * PURPOSE 3618c2ecf20Sopenharmony_ci * Parse mount options. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * DESCRIPTION 3648c2ecf20Sopenharmony_ci * The following mount options are supported: 3658c2ecf20Sopenharmony_ci * 3668c2ecf20Sopenharmony_ci * gid= Set the default group. 3678c2ecf20Sopenharmony_ci * umask= Set the default umask. 3688c2ecf20Sopenharmony_ci * mode= Set the default file permissions. 3698c2ecf20Sopenharmony_ci * dmode= Set the default directory permissions. 3708c2ecf20Sopenharmony_ci * uid= Set the default user. 3718c2ecf20Sopenharmony_ci * bs= Set the block size. 3728c2ecf20Sopenharmony_ci * unhide Show otherwise hidden files. 3738c2ecf20Sopenharmony_ci * undelete Show deleted files in lists. 3748c2ecf20Sopenharmony_ci * adinicb Embed data in the inode (default) 3758c2ecf20Sopenharmony_ci * noadinicb Don't embed data in the inode 3768c2ecf20Sopenharmony_ci * shortad Use short ad's 3778c2ecf20Sopenharmony_ci * longad Use long ad's (default) 3788c2ecf20Sopenharmony_ci * nostrict Unset strict conformance 3798c2ecf20Sopenharmony_ci * iocharset= Set the NLS character set 3808c2ecf20Sopenharmony_ci * 3818c2ecf20Sopenharmony_ci * The remaining are for debugging and disaster recovery: 3828c2ecf20Sopenharmony_ci * 3838c2ecf20Sopenharmony_ci * novrs Skip volume sequence recognition 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * The following expect a offset from 0. 3868c2ecf20Sopenharmony_ci * 3878c2ecf20Sopenharmony_ci * session= Set the CDROM session (default= last session) 3888c2ecf20Sopenharmony_ci * anchor= Override standard anchor location. (default= 256) 3898c2ecf20Sopenharmony_ci * volume= Override the VolumeDesc location. (unused) 3908c2ecf20Sopenharmony_ci * partition= Override the PartitionDesc location. (unused) 3918c2ecf20Sopenharmony_ci * lastblock= Set the last block of the filesystem/ 3928c2ecf20Sopenharmony_ci * 3938c2ecf20Sopenharmony_ci * The following expect a offset from the partition root. 3948c2ecf20Sopenharmony_ci * 3958c2ecf20Sopenharmony_ci * fileset= Override the fileset block location. (unused) 3968c2ecf20Sopenharmony_ci * rootdir= Override the root directory location. (unused) 3978c2ecf20Sopenharmony_ci * WARNING: overriding the rootdir to a non-directory may 3988c2ecf20Sopenharmony_ci * yield highly unpredictable results. 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * PRE-CONDITIONS 4018c2ecf20Sopenharmony_ci * options Pointer to mount options string. 4028c2ecf20Sopenharmony_ci * uopts Pointer to mount options variable. 4038c2ecf20Sopenharmony_ci * 4048c2ecf20Sopenharmony_ci * POST-CONDITIONS 4058c2ecf20Sopenharmony_ci * <return> 1 Mount options parsed okay. 4068c2ecf20Sopenharmony_ci * <return> 0 Error parsing mount options. 4078c2ecf20Sopenharmony_ci * 4088c2ecf20Sopenharmony_ci * HISTORY 4098c2ecf20Sopenharmony_ci * July 1, 1997 - Andrew E. Mileski 4108c2ecf20Sopenharmony_ci * Written, tested, and released. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cienum { 4148c2ecf20Sopenharmony_ci Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete, 4158c2ecf20Sopenharmony_ci Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad, 4168c2ecf20Sopenharmony_ci Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock, 4178c2ecf20Sopenharmony_ci Opt_anchor, Opt_volume, Opt_partition, Opt_fileset, 4188c2ecf20Sopenharmony_ci Opt_rootdir, Opt_utf8, Opt_iocharset, 4198c2ecf20Sopenharmony_ci Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore, 4208c2ecf20Sopenharmony_ci Opt_fmode, Opt_dmode 4218c2ecf20Sopenharmony_ci}; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic const match_table_t tokens = { 4248c2ecf20Sopenharmony_ci {Opt_novrs, "novrs"}, 4258c2ecf20Sopenharmony_ci {Opt_nostrict, "nostrict"}, 4268c2ecf20Sopenharmony_ci {Opt_bs, "bs=%u"}, 4278c2ecf20Sopenharmony_ci {Opt_unhide, "unhide"}, 4288c2ecf20Sopenharmony_ci {Opt_undelete, "undelete"}, 4298c2ecf20Sopenharmony_ci {Opt_noadinicb, "noadinicb"}, 4308c2ecf20Sopenharmony_ci {Opt_adinicb, "adinicb"}, 4318c2ecf20Sopenharmony_ci {Opt_shortad, "shortad"}, 4328c2ecf20Sopenharmony_ci {Opt_longad, "longad"}, 4338c2ecf20Sopenharmony_ci {Opt_uforget, "uid=forget"}, 4348c2ecf20Sopenharmony_ci {Opt_uignore, "uid=ignore"}, 4358c2ecf20Sopenharmony_ci {Opt_gforget, "gid=forget"}, 4368c2ecf20Sopenharmony_ci {Opt_gignore, "gid=ignore"}, 4378c2ecf20Sopenharmony_ci {Opt_gid, "gid=%u"}, 4388c2ecf20Sopenharmony_ci {Opt_uid, "uid=%u"}, 4398c2ecf20Sopenharmony_ci {Opt_umask, "umask=%o"}, 4408c2ecf20Sopenharmony_ci {Opt_session, "session=%u"}, 4418c2ecf20Sopenharmony_ci {Opt_lastblock, "lastblock=%u"}, 4428c2ecf20Sopenharmony_ci {Opt_anchor, "anchor=%u"}, 4438c2ecf20Sopenharmony_ci {Opt_volume, "volume=%u"}, 4448c2ecf20Sopenharmony_ci {Opt_partition, "partition=%u"}, 4458c2ecf20Sopenharmony_ci {Opt_fileset, "fileset=%u"}, 4468c2ecf20Sopenharmony_ci {Opt_rootdir, "rootdir=%u"}, 4478c2ecf20Sopenharmony_ci {Opt_utf8, "utf8"}, 4488c2ecf20Sopenharmony_ci {Opt_iocharset, "iocharset=%s"}, 4498c2ecf20Sopenharmony_ci {Opt_fmode, "mode=%o"}, 4508c2ecf20Sopenharmony_ci {Opt_dmode, "dmode=%o"}, 4518c2ecf20Sopenharmony_ci {Opt_err, NULL} 4528c2ecf20Sopenharmony_ci}; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int udf_parse_options(char *options, struct udf_options *uopt, 4558c2ecf20Sopenharmony_ci bool remount) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci char *p; 4588c2ecf20Sopenharmony_ci int option; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci uopt->novrs = 0; 4618c2ecf20Sopenharmony_ci uopt->session = 0xFFFFFFFF; 4628c2ecf20Sopenharmony_ci uopt->lastblock = 0; 4638c2ecf20Sopenharmony_ci uopt->anchor = 0; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (!options) 4668c2ecf20Sopenharmony_ci return 1; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 4698c2ecf20Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 4708c2ecf20Sopenharmony_ci int token; 4718c2ecf20Sopenharmony_ci unsigned n; 4728c2ecf20Sopenharmony_ci if (!*p) 4738c2ecf20Sopenharmony_ci continue; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci token = match_token(p, tokens, args); 4768c2ecf20Sopenharmony_ci switch (token) { 4778c2ecf20Sopenharmony_ci case Opt_novrs: 4788c2ecf20Sopenharmony_ci uopt->novrs = 1; 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case Opt_bs: 4818c2ecf20Sopenharmony_ci if (match_int(&args[0], &option)) 4828c2ecf20Sopenharmony_ci return 0; 4838c2ecf20Sopenharmony_ci n = option; 4848c2ecf20Sopenharmony_ci if (n != 512 && n != 1024 && n != 2048 && n != 4096) 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci uopt->blocksize = n; 4878c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET); 4888c2ecf20Sopenharmony_ci break; 4898c2ecf20Sopenharmony_ci case Opt_unhide: 4908c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UNHIDE); 4918c2ecf20Sopenharmony_ci break; 4928c2ecf20Sopenharmony_ci case Opt_undelete: 4938c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UNDELETE); 4948c2ecf20Sopenharmony_ci break; 4958c2ecf20Sopenharmony_ci case Opt_noadinicb: 4968c2ecf20Sopenharmony_ci uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case Opt_adinicb: 4998c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB); 5008c2ecf20Sopenharmony_ci break; 5018c2ecf20Sopenharmony_ci case Opt_shortad: 5028c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD); 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci case Opt_longad: 5058c2ecf20Sopenharmony_ci uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci case Opt_gid: 5088c2ecf20Sopenharmony_ci if (match_int(args, &option)) 5098c2ecf20Sopenharmony_ci return 0; 5108c2ecf20Sopenharmony_ci uopt->gid = make_kgid(current_user_ns(), option); 5118c2ecf20Sopenharmony_ci if (!gid_valid(uopt->gid)) 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_GID_SET); 5148c2ecf20Sopenharmony_ci break; 5158c2ecf20Sopenharmony_ci case Opt_uid: 5168c2ecf20Sopenharmony_ci if (match_int(args, &option)) 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci uopt->uid = make_kuid(current_user_ns(), option); 5198c2ecf20Sopenharmony_ci if (!uid_valid(uopt->uid)) 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UID_SET); 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case Opt_umask: 5248c2ecf20Sopenharmony_ci if (match_octal(args, &option)) 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci uopt->umask = option; 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci case Opt_nostrict: 5298c2ecf20Sopenharmony_ci uopt->flags &= ~(1 << UDF_FLAG_STRICT); 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci case Opt_session: 5328c2ecf20Sopenharmony_ci if (match_int(args, &option)) 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci uopt->session = option; 5358c2ecf20Sopenharmony_ci if (!remount) 5368c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_SESSION_SET); 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci case Opt_lastblock: 5398c2ecf20Sopenharmony_ci if (match_int(args, &option)) 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci uopt->lastblock = option; 5428c2ecf20Sopenharmony_ci if (!remount) 5438c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET); 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci case Opt_anchor: 5468c2ecf20Sopenharmony_ci if (match_int(args, &option)) 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci uopt->anchor = option; 5498c2ecf20Sopenharmony_ci break; 5508c2ecf20Sopenharmony_ci case Opt_volume: 5518c2ecf20Sopenharmony_ci case Opt_partition: 5528c2ecf20Sopenharmony_ci case Opt_fileset: 5538c2ecf20Sopenharmony_ci case Opt_rootdir: 5548c2ecf20Sopenharmony_ci /* Ignored (never implemented properly) */ 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci case Opt_utf8: 5578c2ecf20Sopenharmony_ci if (!remount) { 5588c2ecf20Sopenharmony_ci unload_nls(uopt->nls_map); 5598c2ecf20Sopenharmony_ci uopt->nls_map = NULL; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci break; 5628c2ecf20Sopenharmony_ci case Opt_iocharset: 5638c2ecf20Sopenharmony_ci if (!remount) { 5648c2ecf20Sopenharmony_ci unload_nls(uopt->nls_map); 5658c2ecf20Sopenharmony_ci uopt->nls_map = NULL; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci /* When nls_map is not loaded then UTF-8 is used */ 5688c2ecf20Sopenharmony_ci if (!remount && strcmp(args[0].from, "utf8") != 0) { 5698c2ecf20Sopenharmony_ci uopt->nls_map = load_nls(args[0].from); 5708c2ecf20Sopenharmony_ci if (!uopt->nls_map) { 5718c2ecf20Sopenharmony_ci pr_err("iocharset %s not found\n", 5728c2ecf20Sopenharmony_ci args[0].from); 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci case Opt_uforget: 5788c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UID_FORGET); 5798c2ecf20Sopenharmony_ci break; 5808c2ecf20Sopenharmony_ci case Opt_uignore: 5818c2ecf20Sopenharmony_ci case Opt_gignore: 5828c2ecf20Sopenharmony_ci /* These options are superseeded by uid=<number> */ 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci case Opt_gforget: 5858c2ecf20Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_GID_FORGET); 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci case Opt_fmode: 5888c2ecf20Sopenharmony_ci if (match_octal(args, &option)) 5898c2ecf20Sopenharmony_ci return 0; 5908c2ecf20Sopenharmony_ci uopt->fmode = option & 0777; 5918c2ecf20Sopenharmony_ci break; 5928c2ecf20Sopenharmony_ci case Opt_dmode: 5938c2ecf20Sopenharmony_ci if (match_octal(args, &option)) 5948c2ecf20Sopenharmony_ci return 0; 5958c2ecf20Sopenharmony_ci uopt->dmode = option & 0777; 5968c2ecf20Sopenharmony_ci break; 5978c2ecf20Sopenharmony_ci default: 5988c2ecf20Sopenharmony_ci pr_err("bad mount option \"%s\" or missing value\n", p); 5998c2ecf20Sopenharmony_ci return 0; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci return 1; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int udf_remount_fs(struct super_block *sb, int *flags, char *options) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct udf_options uopt; 6088c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 6098c2ecf20Sopenharmony_ci int error = 0; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (!(*flags & SB_RDONLY) && UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT)) 6128c2ecf20Sopenharmony_ci return -EACCES; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci sync_filesystem(sb); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci uopt.flags = sbi->s_flags; 6178c2ecf20Sopenharmony_ci uopt.uid = sbi->s_uid; 6188c2ecf20Sopenharmony_ci uopt.gid = sbi->s_gid; 6198c2ecf20Sopenharmony_ci uopt.umask = sbi->s_umask; 6208c2ecf20Sopenharmony_ci uopt.fmode = sbi->s_fmode; 6218c2ecf20Sopenharmony_ci uopt.dmode = sbi->s_dmode; 6228c2ecf20Sopenharmony_ci uopt.nls_map = NULL; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci if (!udf_parse_options(options, &uopt, true)) 6258c2ecf20Sopenharmony_ci return -EINVAL; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci write_lock(&sbi->s_cred_lock); 6288c2ecf20Sopenharmony_ci sbi->s_flags = uopt.flags; 6298c2ecf20Sopenharmony_ci sbi->s_uid = uopt.uid; 6308c2ecf20Sopenharmony_ci sbi->s_gid = uopt.gid; 6318c2ecf20Sopenharmony_ci sbi->s_umask = uopt.umask; 6328c2ecf20Sopenharmony_ci sbi->s_fmode = uopt.fmode; 6338c2ecf20Sopenharmony_ci sbi->s_dmode = uopt.dmode; 6348c2ecf20Sopenharmony_ci write_unlock(&sbi->s_cred_lock); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) 6378c2ecf20Sopenharmony_ci goto out_unlock; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (*flags & SB_RDONLY) 6408c2ecf20Sopenharmony_ci udf_close_lvid(sb); 6418c2ecf20Sopenharmony_ci else 6428c2ecf20Sopenharmony_ci udf_open_lvid(sb); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ciout_unlock: 6458c2ecf20Sopenharmony_ci return error; 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci/* 6498c2ecf20Sopenharmony_ci * Check VSD descriptor. Returns -1 in case we are at the end of volume 6508c2ecf20Sopenharmony_ci * recognition area, 0 if the descriptor is valid but non-interesting, 1 if 6518c2ecf20Sopenharmony_ci * we found one of NSR descriptors we are looking for. 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_cistatic int identify_vsd(const struct volStructDesc *vsd) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci int ret = 0; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (!memcmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) { 6588c2ecf20Sopenharmony_ci switch (vsd->structType) { 6598c2ecf20Sopenharmony_ci case 0: 6608c2ecf20Sopenharmony_ci udf_debug("ISO9660 Boot Record found\n"); 6618c2ecf20Sopenharmony_ci break; 6628c2ecf20Sopenharmony_ci case 1: 6638c2ecf20Sopenharmony_ci udf_debug("ISO9660 Primary Volume Descriptor found\n"); 6648c2ecf20Sopenharmony_ci break; 6658c2ecf20Sopenharmony_ci case 2: 6668c2ecf20Sopenharmony_ci udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); 6678c2ecf20Sopenharmony_ci break; 6688c2ecf20Sopenharmony_ci case 3: 6698c2ecf20Sopenharmony_ci udf_debug("ISO9660 Volume Partition Descriptor found\n"); 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci case 255: 6728c2ecf20Sopenharmony_ci udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); 6738c2ecf20Sopenharmony_ci break; 6748c2ecf20Sopenharmony_ci default: 6758c2ecf20Sopenharmony_ci udf_debug("ISO9660 VRS (%u) found\n", vsd->structType); 6768c2ecf20Sopenharmony_ci break; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci } else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) 6798c2ecf20Sopenharmony_ci ; /* ret = 0 */ 6808c2ecf20Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) 6818c2ecf20Sopenharmony_ci ret = 1; 6828c2ecf20Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) 6838c2ecf20Sopenharmony_ci ret = 1; 6848c2ecf20Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BOOT2, VSD_STD_ID_LEN)) 6858c2ecf20Sopenharmony_ci ; /* ret = 0 */ 6868c2ecf20Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_CDW02, VSD_STD_ID_LEN)) 6878c2ecf20Sopenharmony_ci ; /* ret = 0 */ 6888c2ecf20Sopenharmony_ci else { 6898c2ecf20Sopenharmony_ci /* TEA01 or invalid id : end of volume recognition area */ 6908c2ecf20Sopenharmony_ci ret = -1; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci return ret; 6948c2ecf20Sopenharmony_ci} 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci/* 6978c2ecf20Sopenharmony_ci * Check Volume Structure Descriptors (ECMA 167 2/9.1) 6988c2ecf20Sopenharmony_ci * We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) 6998c2ecf20Sopenharmony_ci * @return 1 if NSR02 or NSR03 found, 7008c2ecf20Sopenharmony_ci * -1 if first sector read error, 0 otherwise 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_cistatic int udf_check_vsd(struct super_block *sb) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci struct volStructDesc *vsd = NULL; 7058c2ecf20Sopenharmony_ci loff_t sector = VSD_FIRST_SECTOR_OFFSET; 7068c2ecf20Sopenharmony_ci int sectorsize; 7078c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 7088c2ecf20Sopenharmony_ci int nsr = 0; 7098c2ecf20Sopenharmony_ci struct udf_sb_info *sbi; 7108c2ecf20Sopenharmony_ci loff_t session_offset; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci sbi = UDF_SB(sb); 7138c2ecf20Sopenharmony_ci if (sb->s_blocksize < sizeof(struct volStructDesc)) 7148c2ecf20Sopenharmony_ci sectorsize = sizeof(struct volStructDesc); 7158c2ecf20Sopenharmony_ci else 7168c2ecf20Sopenharmony_ci sectorsize = sb->s_blocksize; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci session_offset = (loff_t)sbi->s_session << sb->s_blocksize_bits; 7198c2ecf20Sopenharmony_ci sector += session_offset; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci udf_debug("Starting at sector %u (%lu byte sectors)\n", 7228c2ecf20Sopenharmony_ci (unsigned int)(sector >> sb->s_blocksize_bits), 7238c2ecf20Sopenharmony_ci sb->s_blocksize); 7248c2ecf20Sopenharmony_ci /* Process the sequence (if applicable). The hard limit on the sector 7258c2ecf20Sopenharmony_ci * offset is arbitrary, hopefully large enough so that all valid UDF 7268c2ecf20Sopenharmony_ci * filesystems will be recognised. There is no mention of an upper 7278c2ecf20Sopenharmony_ci * bound to the size of the volume recognition area in the standard. 7288c2ecf20Sopenharmony_ci * The limit will prevent the code to read all the sectors of a 7298c2ecf20Sopenharmony_ci * specially crafted image (like a bluray disc full of CD001 sectors), 7308c2ecf20Sopenharmony_ci * potentially causing minutes or even hours of uninterruptible I/O 7318c2ecf20Sopenharmony_ci * activity. This actually happened with uninitialised SSD partitions 7328c2ecf20Sopenharmony_ci * (all 0xFF) before the check for the limit and all valid IDs were 7338c2ecf20Sopenharmony_ci * added */ 7348c2ecf20Sopenharmony_ci for (; !nsr && sector < VSD_MAX_SECTOR_OFFSET; sector += sectorsize) { 7358c2ecf20Sopenharmony_ci /* Read a block */ 7368c2ecf20Sopenharmony_ci bh = udf_tread(sb, sector >> sb->s_blocksize_bits); 7378c2ecf20Sopenharmony_ci if (!bh) 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci vsd = (struct volStructDesc *)(bh->b_data + 7418c2ecf20Sopenharmony_ci (sector & (sb->s_blocksize - 1))); 7428c2ecf20Sopenharmony_ci nsr = identify_vsd(vsd); 7438c2ecf20Sopenharmony_ci /* Found NSR or end? */ 7448c2ecf20Sopenharmony_ci if (nsr) { 7458c2ecf20Sopenharmony_ci brelse(bh); 7468c2ecf20Sopenharmony_ci break; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci /* 7498c2ecf20Sopenharmony_ci * Special handling for improperly formatted VRS (e.g., Win10) 7508c2ecf20Sopenharmony_ci * where components are separated by 2048 bytes even though 7518c2ecf20Sopenharmony_ci * sectors are 4K 7528c2ecf20Sopenharmony_ci */ 7538c2ecf20Sopenharmony_ci if (sb->s_blocksize == 4096) { 7548c2ecf20Sopenharmony_ci nsr = identify_vsd(vsd + 1); 7558c2ecf20Sopenharmony_ci /* Ignore unknown IDs... */ 7568c2ecf20Sopenharmony_ci if (nsr < 0) 7578c2ecf20Sopenharmony_ci nsr = 0; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci brelse(bh); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (nsr > 0) 7638c2ecf20Sopenharmony_ci return 1; 7648c2ecf20Sopenharmony_ci else if (!bh && sector - session_offset == VSD_FIRST_SECTOR_OFFSET) 7658c2ecf20Sopenharmony_ci return -1; 7668c2ecf20Sopenharmony_ci else 7678c2ecf20Sopenharmony_ci return 0; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_cistatic int udf_verify_domain_identifier(struct super_block *sb, 7718c2ecf20Sopenharmony_ci struct regid *ident, char *dname) 7728c2ecf20Sopenharmony_ci{ 7738c2ecf20Sopenharmony_ci struct domainIdentSuffix *suffix; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (memcmp(ident->ident, UDF_ID_COMPLIANT, strlen(UDF_ID_COMPLIANT))) { 7768c2ecf20Sopenharmony_ci udf_warn(sb, "Not OSTA UDF compliant %s descriptor.\n", dname); 7778c2ecf20Sopenharmony_ci goto force_ro; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci if (ident->flags & ENTITYID_FLAGS_DIRTY) { 7808c2ecf20Sopenharmony_ci udf_warn(sb, "Possibly not OSTA UDF compliant %s descriptor.\n", 7818c2ecf20Sopenharmony_ci dname); 7828c2ecf20Sopenharmony_ci goto force_ro; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci suffix = (struct domainIdentSuffix *)ident->identSuffix; 7858c2ecf20Sopenharmony_ci if ((suffix->domainFlags & DOMAIN_FLAGS_HARD_WRITE_PROTECT) || 7868c2ecf20Sopenharmony_ci (suffix->domainFlags & DOMAIN_FLAGS_SOFT_WRITE_PROTECT)) { 7878c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 7888c2ecf20Sopenharmony_ci udf_warn(sb, "Descriptor for %s marked write protected." 7898c2ecf20Sopenharmony_ci " Forcing read only mount.\n", dname); 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci goto force_ro; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci return 0; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ciforce_ro: 7968c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 7978c2ecf20Sopenharmony_ci return -EACCES; 7988c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_cistatic int udf_load_fileset(struct super_block *sb, struct fileSetDesc *fset, 8038c2ecf20Sopenharmony_ci struct kernel_lb_addr *root) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci int ret; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci ret = udf_verify_domain_identifier(sb, &fset->domainIdent, "file set"); 8088c2ecf20Sopenharmony_ci if (ret < 0) 8098c2ecf20Sopenharmony_ci return ret; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); 8128c2ecf20Sopenharmony_ci UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci udf_debug("Rootdir at block=%u, partition=%u\n", 8158c2ecf20Sopenharmony_ci root->logicalBlockNum, root->partitionReferenceNum); 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic int udf_find_fileset(struct super_block *sb, 8208c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset, 8218c2ecf20Sopenharmony_ci struct kernel_lb_addr *root) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 8248c2ecf20Sopenharmony_ci uint16_t ident; 8258c2ecf20Sopenharmony_ci int ret; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci if (fileset->logicalBlockNum == 0xFFFFFFFF && 8288c2ecf20Sopenharmony_ci fileset->partitionReferenceNum == 0xFFFF) 8298c2ecf20Sopenharmony_ci return -EINVAL; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci bh = udf_read_ptagged(sb, fileset, 0, &ident); 8328c2ecf20Sopenharmony_ci if (!bh) 8338c2ecf20Sopenharmony_ci return -EIO; 8348c2ecf20Sopenharmony_ci if (ident != TAG_IDENT_FSD) { 8358c2ecf20Sopenharmony_ci brelse(bh); 8368c2ecf20Sopenharmony_ci return -EINVAL; 8378c2ecf20Sopenharmony_ci } 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci udf_debug("Fileset at block=%u, partition=%u\n", 8408c2ecf20Sopenharmony_ci fileset->logicalBlockNum, fileset->partitionReferenceNum); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci UDF_SB(sb)->s_partition = fileset->partitionReferenceNum; 8438c2ecf20Sopenharmony_ci ret = udf_load_fileset(sb, (struct fileSetDesc *)bh->b_data, root); 8448c2ecf20Sopenharmony_ci brelse(bh); 8458c2ecf20Sopenharmony_ci return ret; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci/* 8498c2ecf20Sopenharmony_ci * Load primary Volume Descriptor Sequence 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence 8528c2ecf20Sopenharmony_ci * should be tried. 8538c2ecf20Sopenharmony_ci */ 8548c2ecf20Sopenharmony_cistatic int udf_load_pvoldesc(struct super_block *sb, sector_t block) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci struct primaryVolDesc *pvoldesc; 8578c2ecf20Sopenharmony_ci uint8_t *outstr; 8588c2ecf20Sopenharmony_ci struct buffer_head *bh; 8598c2ecf20Sopenharmony_ci uint16_t ident; 8608c2ecf20Sopenharmony_ci int ret; 8618c2ecf20Sopenharmony_ci struct timestamp *ts; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci outstr = kmalloc(128, GFP_NOFS); 8648c2ecf20Sopenharmony_ci if (!outstr) 8658c2ecf20Sopenharmony_ci return -ENOMEM; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 8688c2ecf20Sopenharmony_ci if (!bh) { 8698c2ecf20Sopenharmony_ci ret = -EAGAIN; 8708c2ecf20Sopenharmony_ci goto out2; 8718c2ecf20Sopenharmony_ci } 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci if (ident != TAG_IDENT_PVD) { 8748c2ecf20Sopenharmony_ci ret = -EIO; 8758c2ecf20Sopenharmony_ci goto out_bh; 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci pvoldesc = (struct primaryVolDesc *)bh->b_data; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, 8818c2ecf20Sopenharmony_ci pvoldesc->recordingDateAndTime); 8828c2ecf20Sopenharmony_ci ts = &pvoldesc->recordingDateAndTime; 8838c2ecf20Sopenharmony_ci udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n", 8848c2ecf20Sopenharmony_ci le16_to_cpu(ts->year), ts->month, ts->day, ts->hour, 8858c2ecf20Sopenharmony_ci ts->minute, le16_to_cpu(ts->typeAndTimezone)); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci ret = udf_dstrCS0toChar(sb, outstr, 31, pvoldesc->volIdent, 32); 8888c2ecf20Sopenharmony_ci if (ret < 0) { 8898c2ecf20Sopenharmony_ci strcpy(UDF_SB(sb)->s_volume_ident, "InvalidName"); 8908c2ecf20Sopenharmony_ci pr_warn("incorrect volume identification, setting to " 8918c2ecf20Sopenharmony_ci "'InvalidName'\n"); 8928c2ecf20Sopenharmony_ci } else { 8938c2ecf20Sopenharmony_ci strncpy(UDF_SB(sb)->s_volume_ident, outstr, ret); 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci ret = udf_dstrCS0toChar(sb, outstr, 127, pvoldesc->volSetIdent, 128); 8988c2ecf20Sopenharmony_ci if (ret < 0) { 8998c2ecf20Sopenharmony_ci ret = 0; 9008c2ecf20Sopenharmony_ci goto out_bh; 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci outstr[ret] = 0; 9038c2ecf20Sopenharmony_ci udf_debug("volSetIdent[] = '%s'\n", outstr); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci ret = 0; 9068c2ecf20Sopenharmony_ciout_bh: 9078c2ecf20Sopenharmony_ci brelse(bh); 9088c2ecf20Sopenharmony_ciout2: 9098c2ecf20Sopenharmony_ci kfree(outstr); 9108c2ecf20Sopenharmony_ci return ret; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistruct inode *udf_find_metadata_inode_efe(struct super_block *sb, 9148c2ecf20Sopenharmony_ci u32 meta_file_loc, u32 partition_ref) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci struct kernel_lb_addr addr; 9178c2ecf20Sopenharmony_ci struct inode *metadata_fe; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci addr.logicalBlockNum = meta_file_loc; 9208c2ecf20Sopenharmony_ci addr.partitionReferenceNum = partition_ref; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci metadata_fe = udf_iget_special(sb, &addr); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci if (IS_ERR(metadata_fe)) { 9258c2ecf20Sopenharmony_ci udf_warn(sb, "metadata inode efe not found\n"); 9268c2ecf20Sopenharmony_ci return metadata_fe; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci if (UDF_I(metadata_fe)->i_alloc_type != ICBTAG_FLAG_AD_SHORT) { 9298c2ecf20Sopenharmony_ci udf_warn(sb, "metadata inode efe does not have short allocation descriptors!\n"); 9308c2ecf20Sopenharmony_ci iput(metadata_fe); 9318c2ecf20Sopenharmony_ci return ERR_PTR(-EIO); 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci return metadata_fe; 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_cistatic int udf_load_metadata_files(struct super_block *sb, int partition, 9388c2ecf20Sopenharmony_ci int type1_index) 9398c2ecf20Sopenharmony_ci{ 9408c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 9418c2ecf20Sopenharmony_ci struct udf_part_map *map; 9428c2ecf20Sopenharmony_ci struct udf_meta_data *mdata; 9438c2ecf20Sopenharmony_ci struct kernel_lb_addr addr; 9448c2ecf20Sopenharmony_ci struct inode *fe; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci map = &sbi->s_partmaps[partition]; 9478c2ecf20Sopenharmony_ci mdata = &map->s_type_specific.s_metadata; 9488c2ecf20Sopenharmony_ci mdata->s_phys_partition_ref = type1_index; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* metadata address */ 9518c2ecf20Sopenharmony_ci udf_debug("Metadata file location: block = %u part = %u\n", 9528c2ecf20Sopenharmony_ci mdata->s_meta_file_loc, mdata->s_phys_partition_ref); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci fe = udf_find_metadata_inode_efe(sb, mdata->s_meta_file_loc, 9558c2ecf20Sopenharmony_ci mdata->s_phys_partition_ref); 9568c2ecf20Sopenharmony_ci if (IS_ERR(fe)) { 9578c2ecf20Sopenharmony_ci /* mirror file entry */ 9588c2ecf20Sopenharmony_ci udf_debug("Mirror metadata file location: block = %u part = %u\n", 9598c2ecf20Sopenharmony_ci mdata->s_mirror_file_loc, mdata->s_phys_partition_ref); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci fe = udf_find_metadata_inode_efe(sb, mdata->s_mirror_file_loc, 9628c2ecf20Sopenharmony_ci mdata->s_phys_partition_ref); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci if (IS_ERR(fe)) { 9658c2ecf20Sopenharmony_ci udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n"); 9668c2ecf20Sopenharmony_ci return PTR_ERR(fe); 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci mdata->s_mirror_fe = fe; 9698c2ecf20Sopenharmony_ci } else 9708c2ecf20Sopenharmony_ci mdata->s_metadata_fe = fe; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci /* 9748c2ecf20Sopenharmony_ci * bitmap file entry 9758c2ecf20Sopenharmony_ci * Note: 9768c2ecf20Sopenharmony_ci * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102) 9778c2ecf20Sopenharmony_ci */ 9788c2ecf20Sopenharmony_ci if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) { 9798c2ecf20Sopenharmony_ci addr.logicalBlockNum = mdata->s_bitmap_file_loc; 9808c2ecf20Sopenharmony_ci addr.partitionReferenceNum = mdata->s_phys_partition_ref; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci udf_debug("Bitmap file location: block = %u part = %u\n", 9838c2ecf20Sopenharmony_ci addr.logicalBlockNum, addr.partitionReferenceNum); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci fe = udf_iget_special(sb, &addr); 9868c2ecf20Sopenharmony_ci if (IS_ERR(fe)) { 9878c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) 9888c2ecf20Sopenharmony_ci udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); 9898c2ecf20Sopenharmony_ci else { 9908c2ecf20Sopenharmony_ci udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n"); 9918c2ecf20Sopenharmony_ci return PTR_ERR(fe); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci } else 9948c2ecf20Sopenharmony_ci mdata->s_bitmap_fe = fe; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci udf_debug("udf_load_metadata_files Ok\n"); 9988c2ecf20Sopenharmony_ci return 0; 9998c2ecf20Sopenharmony_ci} 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ciint udf_compute_nr_groups(struct super_block *sb, u32 partition) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; 10048c2ecf20Sopenharmony_ci return DIV_ROUND_UP(map->s_partition_len + 10058c2ecf20Sopenharmony_ci (sizeof(struct spaceBitmapDesc) << 3), 10068c2ecf20Sopenharmony_ci sb->s_blocksize * 8); 10078c2ecf20Sopenharmony_ci} 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_cistatic struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) 10108c2ecf20Sopenharmony_ci{ 10118c2ecf20Sopenharmony_ci struct udf_bitmap *bitmap; 10128c2ecf20Sopenharmony_ci int nr_groups = udf_compute_nr_groups(sb, index); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci bitmap = kvzalloc(struct_size(bitmap, s_block_bitmap, nr_groups), 10158c2ecf20Sopenharmony_ci GFP_KERNEL); 10168c2ecf20Sopenharmony_ci if (!bitmap) 10178c2ecf20Sopenharmony_ci return NULL; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci bitmap->s_nr_groups = nr_groups; 10208c2ecf20Sopenharmony_ci return bitmap; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_cistatic int check_partition_desc(struct super_block *sb, 10248c2ecf20Sopenharmony_ci struct partitionDesc *p, 10258c2ecf20Sopenharmony_ci struct udf_part_map *map) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci bool umap, utable, fmap, ftable; 10288c2ecf20Sopenharmony_ci struct partitionHeaderDesc *phd; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci switch (le32_to_cpu(p->accessType)) { 10318c2ecf20Sopenharmony_ci case PD_ACCESS_TYPE_READ_ONLY: 10328c2ecf20Sopenharmony_ci case PD_ACCESS_TYPE_WRITE_ONCE: 10338c2ecf20Sopenharmony_ci case PD_ACCESS_TYPE_NONE: 10348c2ecf20Sopenharmony_ci goto force_ro; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci /* No Partition Header Descriptor? */ 10388c2ecf20Sopenharmony_ci if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && 10398c2ecf20Sopenharmony_ci strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) 10408c2ecf20Sopenharmony_ci goto force_ro; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci phd = (struct partitionHeaderDesc *)p->partitionContentsUse; 10438c2ecf20Sopenharmony_ci utable = phd->unallocSpaceTable.extLength; 10448c2ecf20Sopenharmony_ci umap = phd->unallocSpaceBitmap.extLength; 10458c2ecf20Sopenharmony_ci ftable = phd->freedSpaceTable.extLength; 10468c2ecf20Sopenharmony_ci fmap = phd->freedSpaceBitmap.extLength; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci /* No allocation info? */ 10498c2ecf20Sopenharmony_ci if (!utable && !umap && !ftable && !fmap) 10508c2ecf20Sopenharmony_ci goto force_ro; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* We don't support blocks that require erasing before overwrite */ 10538c2ecf20Sopenharmony_ci if (ftable || fmap) 10548c2ecf20Sopenharmony_ci goto force_ro; 10558c2ecf20Sopenharmony_ci /* UDF 2.60: 2.3.3 - no mixing of tables & bitmaps, no VAT. */ 10568c2ecf20Sopenharmony_ci if (utable && umap) 10578c2ecf20Sopenharmony_ci goto force_ro; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (map->s_partition_type == UDF_VIRTUAL_MAP15 || 10608c2ecf20Sopenharmony_ci map->s_partition_type == UDF_VIRTUAL_MAP20 || 10618c2ecf20Sopenharmony_ci map->s_partition_type == UDF_METADATA_MAP25) 10628c2ecf20Sopenharmony_ci goto force_ro; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci return 0; 10658c2ecf20Sopenharmony_ciforce_ro: 10668c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 10678c2ecf20Sopenharmony_ci return -EACCES; 10688c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 10698c2ecf20Sopenharmony_ci return 0; 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic int udf_fill_partdesc_info(struct super_block *sb, 10738c2ecf20Sopenharmony_ci struct partitionDesc *p, int p_index) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci struct udf_part_map *map; 10768c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 10778c2ecf20Sopenharmony_ci struct partitionHeaderDesc *phd; 10788c2ecf20Sopenharmony_ci int err; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci map = &sbi->s_partmaps[p_index]; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ 10838c2ecf20Sopenharmony_ci map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) 10868c2ecf20Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; 10878c2ecf20Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) 10888c2ecf20Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; 10898c2ecf20Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) 10908c2ecf20Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; 10918c2ecf20Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) 10928c2ecf20Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci udf_debug("Partition (%d type %x) starts at physical %u, block length %u\n", 10958c2ecf20Sopenharmony_ci p_index, map->s_partition_type, 10968c2ecf20Sopenharmony_ci map->s_partition_root, map->s_partition_len); 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_ci err = check_partition_desc(sb, p, map); 10998c2ecf20Sopenharmony_ci if (err) 11008c2ecf20Sopenharmony_ci return err; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* 11038c2ecf20Sopenharmony_ci * Skip loading allocation info it we cannot ever write to the fs. 11048c2ecf20Sopenharmony_ci * This is a correctness thing as we may have decided to force ro mount 11058c2ecf20Sopenharmony_ci * to avoid allocation info we don't support. 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT)) 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci phd = (struct partitionHeaderDesc *)p->partitionContentsUse; 11118c2ecf20Sopenharmony_ci if (phd->unallocSpaceTable.extLength) { 11128c2ecf20Sopenharmony_ci struct kernel_lb_addr loc = { 11138c2ecf20Sopenharmony_ci .logicalBlockNum = le32_to_cpu( 11148c2ecf20Sopenharmony_ci phd->unallocSpaceTable.extPosition), 11158c2ecf20Sopenharmony_ci .partitionReferenceNum = p_index, 11168c2ecf20Sopenharmony_ci }; 11178c2ecf20Sopenharmony_ci struct inode *inode; 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci inode = udf_iget_special(sb, &loc); 11208c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 11218c2ecf20Sopenharmony_ci udf_debug("cannot load unallocSpaceTable (part %d)\n", 11228c2ecf20Sopenharmony_ci p_index); 11238c2ecf20Sopenharmony_ci return PTR_ERR(inode); 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci map->s_uspace.s_table = inode; 11268c2ecf20Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; 11278c2ecf20Sopenharmony_ci udf_debug("unallocSpaceTable (part %d) @ %lu\n", 11288c2ecf20Sopenharmony_ci p_index, map->s_uspace.s_table->i_ino); 11298c2ecf20Sopenharmony_ci } 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci if (phd->unallocSpaceBitmap.extLength) { 11328c2ecf20Sopenharmony_ci struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); 11338c2ecf20Sopenharmony_ci if (!bitmap) 11348c2ecf20Sopenharmony_ci return -ENOMEM; 11358c2ecf20Sopenharmony_ci map->s_uspace.s_bitmap = bitmap; 11368c2ecf20Sopenharmony_ci bitmap->s_extPosition = le32_to_cpu( 11378c2ecf20Sopenharmony_ci phd->unallocSpaceBitmap.extPosition); 11388c2ecf20Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; 11398c2ecf20Sopenharmony_ci udf_debug("unallocSpaceBitmap (part %d) @ %u\n", 11408c2ecf20Sopenharmony_ci p_index, bitmap->s_extPosition); 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci return 0; 11448c2ecf20Sopenharmony_ci} 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_cistatic void udf_find_vat_block(struct super_block *sb, int p_index, 11478c2ecf20Sopenharmony_ci int type1_index, sector_t start_block) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 11508c2ecf20Sopenharmony_ci struct udf_part_map *map = &sbi->s_partmaps[p_index]; 11518c2ecf20Sopenharmony_ci sector_t vat_block; 11528c2ecf20Sopenharmony_ci struct kernel_lb_addr ino; 11538c2ecf20Sopenharmony_ci struct inode *inode; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * VAT file entry is in the last recorded block. Some broken disks have 11578c2ecf20Sopenharmony_ci * it a few blocks before so try a bit harder... 11588c2ecf20Sopenharmony_ci */ 11598c2ecf20Sopenharmony_ci ino.partitionReferenceNum = type1_index; 11608c2ecf20Sopenharmony_ci for (vat_block = start_block; 11618c2ecf20Sopenharmony_ci vat_block >= map->s_partition_root && 11628c2ecf20Sopenharmony_ci vat_block >= start_block - 3; vat_block--) { 11638c2ecf20Sopenharmony_ci ino.logicalBlockNum = vat_block - map->s_partition_root; 11648c2ecf20Sopenharmony_ci inode = udf_iget_special(sb, &ino); 11658c2ecf20Sopenharmony_ci if (!IS_ERR(inode)) { 11668c2ecf20Sopenharmony_ci sbi->s_vat_inode = inode; 11678c2ecf20Sopenharmony_ci break; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic int udf_load_vat(struct super_block *sb, int p_index, int type1_index) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 11758c2ecf20Sopenharmony_ci struct udf_part_map *map = &sbi->s_partmaps[p_index]; 11768c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 11778c2ecf20Sopenharmony_ci struct udf_inode_info *vati; 11788c2ecf20Sopenharmony_ci uint32_t pos; 11798c2ecf20Sopenharmony_ci struct virtualAllocationTable20 *vat20; 11808c2ecf20Sopenharmony_ci sector_t blocks = i_size_read(sb->s_bdev->bd_inode) >> 11818c2ecf20Sopenharmony_ci sb->s_blocksize_bits; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block); 11848c2ecf20Sopenharmony_ci if (!sbi->s_vat_inode && 11858c2ecf20Sopenharmony_ci sbi->s_last_block != blocks - 1) { 11868c2ecf20Sopenharmony_ci pr_notice("Failed to read VAT inode from the last recorded block (%lu), retrying with the last block of the device (%lu).\n", 11878c2ecf20Sopenharmony_ci (unsigned long)sbi->s_last_block, 11888c2ecf20Sopenharmony_ci (unsigned long)blocks - 1); 11898c2ecf20Sopenharmony_ci udf_find_vat_block(sb, p_index, type1_index, blocks - 1); 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci if (!sbi->s_vat_inode) 11928c2ecf20Sopenharmony_ci return -EIO; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (map->s_partition_type == UDF_VIRTUAL_MAP15) { 11958c2ecf20Sopenharmony_ci map->s_type_specific.s_virtual.s_start_offset = 0; 11968c2ecf20Sopenharmony_ci map->s_type_specific.s_virtual.s_num_entries = 11978c2ecf20Sopenharmony_ci (sbi->s_vat_inode->i_size - 36) >> 2; 11988c2ecf20Sopenharmony_ci } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { 11998c2ecf20Sopenharmony_ci vati = UDF_I(sbi->s_vat_inode); 12008c2ecf20Sopenharmony_ci if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 12018c2ecf20Sopenharmony_ci pos = udf_block_map(sbi->s_vat_inode, 0); 12028c2ecf20Sopenharmony_ci bh = sb_bread(sb, pos); 12038c2ecf20Sopenharmony_ci if (!bh) 12048c2ecf20Sopenharmony_ci return -EIO; 12058c2ecf20Sopenharmony_ci vat20 = (struct virtualAllocationTable20 *)bh->b_data; 12068c2ecf20Sopenharmony_ci } else { 12078c2ecf20Sopenharmony_ci vat20 = (struct virtualAllocationTable20 *) 12088c2ecf20Sopenharmony_ci vati->i_data; 12098c2ecf20Sopenharmony_ci } 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci map->s_type_specific.s_virtual.s_start_offset = 12128c2ecf20Sopenharmony_ci le16_to_cpu(vat20->lengthHeader); 12138c2ecf20Sopenharmony_ci map->s_type_specific.s_virtual.s_num_entries = 12148c2ecf20Sopenharmony_ci (sbi->s_vat_inode->i_size - 12158c2ecf20Sopenharmony_ci map->s_type_specific.s_virtual. 12168c2ecf20Sopenharmony_ci s_start_offset) >> 2; 12178c2ecf20Sopenharmony_ci brelse(bh); 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci return 0; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci/* 12238c2ecf20Sopenharmony_ci * Load partition descriptor block 12248c2ecf20Sopenharmony_ci * 12258c2ecf20Sopenharmony_ci * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor 12268c2ecf20Sopenharmony_ci * sequence. 12278c2ecf20Sopenharmony_ci */ 12288c2ecf20Sopenharmony_cistatic int udf_load_partdesc(struct super_block *sb, sector_t block) 12298c2ecf20Sopenharmony_ci{ 12308c2ecf20Sopenharmony_ci struct buffer_head *bh; 12318c2ecf20Sopenharmony_ci struct partitionDesc *p; 12328c2ecf20Sopenharmony_ci struct udf_part_map *map; 12338c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 12348c2ecf20Sopenharmony_ci int i, type1_idx; 12358c2ecf20Sopenharmony_ci uint16_t partitionNumber; 12368c2ecf20Sopenharmony_ci uint16_t ident; 12378c2ecf20Sopenharmony_ci int ret; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 12408c2ecf20Sopenharmony_ci if (!bh) 12418c2ecf20Sopenharmony_ci return -EAGAIN; 12428c2ecf20Sopenharmony_ci if (ident != TAG_IDENT_PD) { 12438c2ecf20Sopenharmony_ci ret = 0; 12448c2ecf20Sopenharmony_ci goto out_bh; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci p = (struct partitionDesc *)bh->b_data; 12488c2ecf20Sopenharmony_ci partitionNumber = le16_to_cpu(p->partitionNumber); 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* First scan for TYPE1 and SPARABLE partitions */ 12518c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_partitions; i++) { 12528c2ecf20Sopenharmony_ci map = &sbi->s_partmaps[i]; 12538c2ecf20Sopenharmony_ci udf_debug("Searching map: (%u == %u)\n", 12548c2ecf20Sopenharmony_ci map->s_partition_num, partitionNumber); 12558c2ecf20Sopenharmony_ci if (map->s_partition_num == partitionNumber && 12568c2ecf20Sopenharmony_ci (map->s_partition_type == UDF_TYPE1_MAP15 || 12578c2ecf20Sopenharmony_ci map->s_partition_type == UDF_SPARABLE_MAP15)) 12588c2ecf20Sopenharmony_ci break; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (i >= sbi->s_partitions) { 12628c2ecf20Sopenharmony_ci udf_debug("Partition (%u) not found in partition map\n", 12638c2ecf20Sopenharmony_ci partitionNumber); 12648c2ecf20Sopenharmony_ci ret = 0; 12658c2ecf20Sopenharmony_ci goto out_bh; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci ret = udf_fill_partdesc_info(sb, p, i); 12698c2ecf20Sopenharmony_ci if (ret < 0) 12708c2ecf20Sopenharmony_ci goto out_bh; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* 12738c2ecf20Sopenharmony_ci * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and 12748c2ecf20Sopenharmony_ci * PHYSICAL partitions are already set up 12758c2ecf20Sopenharmony_ci */ 12768c2ecf20Sopenharmony_ci type1_idx = i; 12778c2ecf20Sopenharmony_ci map = NULL; /* supress 'maybe used uninitialized' warning */ 12788c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_partitions; i++) { 12798c2ecf20Sopenharmony_ci map = &sbi->s_partmaps[i]; 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci if (map->s_partition_num == partitionNumber && 12828c2ecf20Sopenharmony_ci (map->s_partition_type == UDF_VIRTUAL_MAP15 || 12838c2ecf20Sopenharmony_ci map->s_partition_type == UDF_VIRTUAL_MAP20 || 12848c2ecf20Sopenharmony_ci map->s_partition_type == UDF_METADATA_MAP25)) 12858c2ecf20Sopenharmony_ci break; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci if (i >= sbi->s_partitions) { 12898c2ecf20Sopenharmony_ci ret = 0; 12908c2ecf20Sopenharmony_ci goto out_bh; 12918c2ecf20Sopenharmony_ci } 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci ret = udf_fill_partdesc_info(sb, p, i); 12948c2ecf20Sopenharmony_ci if (ret < 0) 12958c2ecf20Sopenharmony_ci goto out_bh; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (map->s_partition_type == UDF_METADATA_MAP25) { 12988c2ecf20Sopenharmony_ci ret = udf_load_metadata_files(sb, i, type1_idx); 12998c2ecf20Sopenharmony_ci if (ret < 0) { 13008c2ecf20Sopenharmony_ci udf_err(sb, "error loading MetaData partition map %d\n", 13018c2ecf20Sopenharmony_ci i); 13028c2ecf20Sopenharmony_ci goto out_bh; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci } else { 13058c2ecf20Sopenharmony_ci /* 13068c2ecf20Sopenharmony_ci * If we have a partition with virtual map, we don't handle 13078c2ecf20Sopenharmony_ci * writing to it (we overwrite blocks instead of relocating 13088c2ecf20Sopenharmony_ci * them). 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 13118c2ecf20Sopenharmony_ci ret = -EACCES; 13128c2ecf20Sopenharmony_ci goto out_bh; 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 13158c2ecf20Sopenharmony_ci ret = udf_load_vat(sb, i, type1_idx); 13168c2ecf20Sopenharmony_ci if (ret < 0) 13178c2ecf20Sopenharmony_ci goto out_bh; 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci ret = 0; 13208c2ecf20Sopenharmony_ciout_bh: 13218c2ecf20Sopenharmony_ci /* In case loading failed, we handle cleanup in udf_fill_super */ 13228c2ecf20Sopenharmony_ci brelse(bh); 13238c2ecf20Sopenharmony_ci return ret; 13248c2ecf20Sopenharmony_ci} 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_cistatic int udf_load_sparable_map(struct super_block *sb, 13278c2ecf20Sopenharmony_ci struct udf_part_map *map, 13288c2ecf20Sopenharmony_ci struct sparablePartitionMap *spm) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci uint32_t loc; 13318c2ecf20Sopenharmony_ci uint16_t ident; 13328c2ecf20Sopenharmony_ci struct sparingTable *st; 13338c2ecf20Sopenharmony_ci struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing; 13348c2ecf20Sopenharmony_ci int i; 13358c2ecf20Sopenharmony_ci struct buffer_head *bh; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci map->s_partition_type = UDF_SPARABLE_MAP15; 13388c2ecf20Sopenharmony_ci sdata->s_packet_len = le16_to_cpu(spm->packetLength); 13398c2ecf20Sopenharmony_ci if (!is_power_of_2(sdata->s_packet_len)) { 13408c2ecf20Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 13418c2ecf20Sopenharmony_ci "Invalid packet length %u\n", 13428c2ecf20Sopenharmony_ci (unsigned)sdata->s_packet_len); 13438c2ecf20Sopenharmony_ci return -EIO; 13448c2ecf20Sopenharmony_ci } 13458c2ecf20Sopenharmony_ci if (spm->numSparingTables > 4) { 13468c2ecf20Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 13478c2ecf20Sopenharmony_ci "Too many sparing tables (%d)\n", 13488c2ecf20Sopenharmony_ci (int)spm->numSparingTables); 13498c2ecf20Sopenharmony_ci return -EIO; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci if (le32_to_cpu(spm->sizeSparingTable) > sb->s_blocksize) { 13528c2ecf20Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 13538c2ecf20Sopenharmony_ci "Too big sparing table size (%u)\n", 13548c2ecf20Sopenharmony_ci le32_to_cpu(spm->sizeSparingTable)); 13558c2ecf20Sopenharmony_ci return -EIO; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci for (i = 0; i < spm->numSparingTables; i++) { 13598c2ecf20Sopenharmony_ci loc = le32_to_cpu(spm->locSparingTable[i]); 13608c2ecf20Sopenharmony_ci bh = udf_read_tagged(sb, loc, loc, &ident); 13618c2ecf20Sopenharmony_ci if (!bh) 13628c2ecf20Sopenharmony_ci continue; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci st = (struct sparingTable *)bh->b_data; 13658c2ecf20Sopenharmony_ci if (ident != 0 || 13668c2ecf20Sopenharmony_ci strncmp(st->sparingIdent.ident, UDF_ID_SPARING, 13678c2ecf20Sopenharmony_ci strlen(UDF_ID_SPARING)) || 13688c2ecf20Sopenharmony_ci sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > 13698c2ecf20Sopenharmony_ci sb->s_blocksize) { 13708c2ecf20Sopenharmony_ci brelse(bh); 13718c2ecf20Sopenharmony_ci continue; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci sdata->s_spar_map[i] = bh; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci map->s_partition_func = udf_get_pblock_spar15; 13778c2ecf20Sopenharmony_ci return 0; 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cistatic int udf_load_logicalvol(struct super_block *sb, sector_t block, 13818c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci struct logicalVolDesc *lvd; 13848c2ecf20Sopenharmony_ci int i, offset; 13858c2ecf20Sopenharmony_ci uint8_t type; 13868c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 13878c2ecf20Sopenharmony_ci struct genericPartitionMap *gpm; 13888c2ecf20Sopenharmony_ci uint16_t ident; 13898c2ecf20Sopenharmony_ci struct buffer_head *bh; 13908c2ecf20Sopenharmony_ci unsigned int table_len; 13918c2ecf20Sopenharmony_ci int ret; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 13948c2ecf20Sopenharmony_ci if (!bh) 13958c2ecf20Sopenharmony_ci return -EAGAIN; 13968c2ecf20Sopenharmony_ci BUG_ON(ident != TAG_IDENT_LVD); 13978c2ecf20Sopenharmony_ci lvd = (struct logicalVolDesc *)bh->b_data; 13988c2ecf20Sopenharmony_ci table_len = le32_to_cpu(lvd->mapTableLength); 13998c2ecf20Sopenharmony_ci if (table_len > sb->s_blocksize - sizeof(*lvd)) { 14008c2ecf20Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 14018c2ecf20Sopenharmony_ci "Partition table too long (%u > %lu)\n", table_len, 14028c2ecf20Sopenharmony_ci sb->s_blocksize - sizeof(*lvd)); 14038c2ecf20Sopenharmony_ci ret = -EIO; 14048c2ecf20Sopenharmony_ci goto out_bh; 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci ret = udf_verify_domain_identifier(sb, &lvd->domainIdent, 14088c2ecf20Sopenharmony_ci "logical volume"); 14098c2ecf20Sopenharmony_ci if (ret) 14108c2ecf20Sopenharmony_ci goto out_bh; 14118c2ecf20Sopenharmony_ci ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); 14128c2ecf20Sopenharmony_ci if (ret) 14138c2ecf20Sopenharmony_ci goto out_bh; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci for (i = 0, offset = 0; 14168c2ecf20Sopenharmony_ci i < sbi->s_partitions && offset < table_len; 14178c2ecf20Sopenharmony_ci i++, offset += gpm->partitionMapLength) { 14188c2ecf20Sopenharmony_ci struct udf_part_map *map = &sbi->s_partmaps[i]; 14198c2ecf20Sopenharmony_ci gpm = (struct genericPartitionMap *) 14208c2ecf20Sopenharmony_ci &(lvd->partitionMaps[offset]); 14218c2ecf20Sopenharmony_ci type = gpm->partitionMapType; 14228c2ecf20Sopenharmony_ci if (type == 1) { 14238c2ecf20Sopenharmony_ci struct genericPartitionMap1 *gpm1 = 14248c2ecf20Sopenharmony_ci (struct genericPartitionMap1 *)gpm; 14258c2ecf20Sopenharmony_ci map->s_partition_type = UDF_TYPE1_MAP15; 14268c2ecf20Sopenharmony_ci map->s_volumeseqnum = le16_to_cpu(gpm1->volSeqNum); 14278c2ecf20Sopenharmony_ci map->s_partition_num = le16_to_cpu(gpm1->partitionNum); 14288c2ecf20Sopenharmony_ci map->s_partition_func = NULL; 14298c2ecf20Sopenharmony_ci } else if (type == 2) { 14308c2ecf20Sopenharmony_ci struct udfPartitionMap2 *upm2 = 14318c2ecf20Sopenharmony_ci (struct udfPartitionMap2 *)gpm; 14328c2ecf20Sopenharmony_ci if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, 14338c2ecf20Sopenharmony_ci strlen(UDF_ID_VIRTUAL))) { 14348c2ecf20Sopenharmony_ci u16 suf = 14358c2ecf20Sopenharmony_ci le16_to_cpu(((__le16 *)upm2->partIdent. 14368c2ecf20Sopenharmony_ci identSuffix)[0]); 14378c2ecf20Sopenharmony_ci if (suf < 0x0200) { 14388c2ecf20Sopenharmony_ci map->s_partition_type = 14398c2ecf20Sopenharmony_ci UDF_VIRTUAL_MAP15; 14408c2ecf20Sopenharmony_ci map->s_partition_func = 14418c2ecf20Sopenharmony_ci udf_get_pblock_virt15; 14428c2ecf20Sopenharmony_ci } else { 14438c2ecf20Sopenharmony_ci map->s_partition_type = 14448c2ecf20Sopenharmony_ci UDF_VIRTUAL_MAP20; 14458c2ecf20Sopenharmony_ci map->s_partition_func = 14468c2ecf20Sopenharmony_ci udf_get_pblock_virt20; 14478c2ecf20Sopenharmony_ci } 14488c2ecf20Sopenharmony_ci } else if (!strncmp(upm2->partIdent.ident, 14498c2ecf20Sopenharmony_ci UDF_ID_SPARABLE, 14508c2ecf20Sopenharmony_ci strlen(UDF_ID_SPARABLE))) { 14518c2ecf20Sopenharmony_ci ret = udf_load_sparable_map(sb, map, 14528c2ecf20Sopenharmony_ci (struct sparablePartitionMap *)gpm); 14538c2ecf20Sopenharmony_ci if (ret < 0) 14548c2ecf20Sopenharmony_ci goto out_bh; 14558c2ecf20Sopenharmony_ci } else if (!strncmp(upm2->partIdent.ident, 14568c2ecf20Sopenharmony_ci UDF_ID_METADATA, 14578c2ecf20Sopenharmony_ci strlen(UDF_ID_METADATA))) { 14588c2ecf20Sopenharmony_ci struct udf_meta_data *mdata = 14598c2ecf20Sopenharmony_ci &map->s_type_specific.s_metadata; 14608c2ecf20Sopenharmony_ci struct metadataPartitionMap *mdm = 14618c2ecf20Sopenharmony_ci (struct metadataPartitionMap *) 14628c2ecf20Sopenharmony_ci &(lvd->partitionMaps[offset]); 14638c2ecf20Sopenharmony_ci udf_debug("Parsing Logical vol part %d type %u id=%s\n", 14648c2ecf20Sopenharmony_ci i, type, UDF_ID_METADATA); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci map->s_partition_type = UDF_METADATA_MAP25; 14678c2ecf20Sopenharmony_ci map->s_partition_func = udf_get_pblock_meta25; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci mdata->s_meta_file_loc = 14708c2ecf20Sopenharmony_ci le32_to_cpu(mdm->metadataFileLoc); 14718c2ecf20Sopenharmony_ci mdata->s_mirror_file_loc = 14728c2ecf20Sopenharmony_ci le32_to_cpu(mdm->metadataMirrorFileLoc); 14738c2ecf20Sopenharmony_ci mdata->s_bitmap_file_loc = 14748c2ecf20Sopenharmony_ci le32_to_cpu(mdm->metadataBitmapFileLoc); 14758c2ecf20Sopenharmony_ci mdata->s_alloc_unit_size = 14768c2ecf20Sopenharmony_ci le32_to_cpu(mdm->allocUnitSize); 14778c2ecf20Sopenharmony_ci mdata->s_align_unit_size = 14788c2ecf20Sopenharmony_ci le16_to_cpu(mdm->alignUnitSize); 14798c2ecf20Sopenharmony_ci if (mdm->flags & 0x01) 14808c2ecf20Sopenharmony_ci mdata->s_flags |= MF_DUPLICATE_MD; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci udf_debug("Metadata Ident suffix=0x%x\n", 14838c2ecf20Sopenharmony_ci le16_to_cpu(*(__le16 *) 14848c2ecf20Sopenharmony_ci mdm->partIdent.identSuffix)); 14858c2ecf20Sopenharmony_ci udf_debug("Metadata part num=%u\n", 14868c2ecf20Sopenharmony_ci le16_to_cpu(mdm->partitionNum)); 14878c2ecf20Sopenharmony_ci udf_debug("Metadata part alloc unit size=%u\n", 14888c2ecf20Sopenharmony_ci le32_to_cpu(mdm->allocUnitSize)); 14898c2ecf20Sopenharmony_ci udf_debug("Metadata file loc=%u\n", 14908c2ecf20Sopenharmony_ci le32_to_cpu(mdm->metadataFileLoc)); 14918c2ecf20Sopenharmony_ci udf_debug("Mirror file loc=%u\n", 14928c2ecf20Sopenharmony_ci le32_to_cpu(mdm->metadataMirrorFileLoc)); 14938c2ecf20Sopenharmony_ci udf_debug("Bitmap file loc=%u\n", 14948c2ecf20Sopenharmony_ci le32_to_cpu(mdm->metadataBitmapFileLoc)); 14958c2ecf20Sopenharmony_ci udf_debug("Flags: %d %u\n", 14968c2ecf20Sopenharmony_ci mdata->s_flags, mdm->flags); 14978c2ecf20Sopenharmony_ci } else { 14988c2ecf20Sopenharmony_ci udf_debug("Unknown ident: %s\n", 14998c2ecf20Sopenharmony_ci upm2->partIdent.ident); 15008c2ecf20Sopenharmony_ci continue; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci map->s_volumeseqnum = le16_to_cpu(upm2->volSeqNum); 15038c2ecf20Sopenharmony_ci map->s_partition_num = le16_to_cpu(upm2->partitionNum); 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci udf_debug("Partition (%d:%u) type %u on volume %u\n", 15068c2ecf20Sopenharmony_ci i, map->s_partition_num, type, map->s_volumeseqnum); 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if (fileset) { 15108c2ecf20Sopenharmony_ci struct long_ad *la = (struct long_ad *)&(lvd->logicalVolContentsUse[0]); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci *fileset = lelb_to_cpu(la->extLocation); 15138c2ecf20Sopenharmony_ci udf_debug("FileSet found in LogicalVolDesc at block=%u, partition=%u\n", 15148c2ecf20Sopenharmony_ci fileset->logicalBlockNum, 15158c2ecf20Sopenharmony_ci fileset->partitionReferenceNum); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci if (lvd->integritySeqExt.extLength) 15188c2ecf20Sopenharmony_ci udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); 15198c2ecf20Sopenharmony_ci ret = 0; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci if (!sbi->s_lvid_bh) { 15228c2ecf20Sopenharmony_ci /* We can't generate unique IDs without a valid LVID */ 15238c2ecf20Sopenharmony_ci if (sb_rdonly(sb)) { 15248c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 15258c2ecf20Sopenharmony_ci } else { 15268c2ecf20Sopenharmony_ci udf_warn(sb, "Damaged or missing LVID, forcing " 15278c2ecf20Sopenharmony_ci "readonly mount\n"); 15288c2ecf20Sopenharmony_ci ret = -EACCES; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci } 15318c2ecf20Sopenharmony_ciout_bh: 15328c2ecf20Sopenharmony_ci brelse(bh); 15338c2ecf20Sopenharmony_ci return ret; 15348c2ecf20Sopenharmony_ci} 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci/* 15378c2ecf20Sopenharmony_ci * Find the prevailing Logical Volume Integrity Descriptor. 15388c2ecf20Sopenharmony_ci */ 15398c2ecf20Sopenharmony_cistatic void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci struct buffer_head *bh, *final_bh; 15428c2ecf20Sopenharmony_ci uint16_t ident; 15438c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 15448c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 15458c2ecf20Sopenharmony_ci int indirections = 0; 15468c2ecf20Sopenharmony_ci u32 parts, impuselen; 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci while (++indirections <= UDF_MAX_LVID_NESTING) { 15498c2ecf20Sopenharmony_ci final_bh = NULL; 15508c2ecf20Sopenharmony_ci while (loc.extLength > 0 && 15518c2ecf20Sopenharmony_ci (bh = udf_read_tagged(sb, loc.extLocation, 15528c2ecf20Sopenharmony_ci loc.extLocation, &ident))) { 15538c2ecf20Sopenharmony_ci if (ident != TAG_IDENT_LVID) { 15548c2ecf20Sopenharmony_ci brelse(bh); 15558c2ecf20Sopenharmony_ci break; 15568c2ecf20Sopenharmony_ci } 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci brelse(final_bh); 15598c2ecf20Sopenharmony_ci final_bh = bh; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci loc.extLength -= sb->s_blocksize; 15628c2ecf20Sopenharmony_ci loc.extLocation++; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci if (!final_bh) 15668c2ecf20Sopenharmony_ci return; 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci brelse(sbi->s_lvid_bh); 15698c2ecf20Sopenharmony_ci sbi->s_lvid_bh = final_bh; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data; 15728c2ecf20Sopenharmony_ci if (lvid->nextIntegrityExt.extLength == 0) 15738c2ecf20Sopenharmony_ci goto check; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci loc = leea_to_cpu(lvid->nextIntegrityExt); 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n", 15798c2ecf20Sopenharmony_ci UDF_MAX_LVID_NESTING); 15808c2ecf20Sopenharmony_ciout_err: 15818c2ecf20Sopenharmony_ci brelse(sbi->s_lvid_bh); 15828c2ecf20Sopenharmony_ci sbi->s_lvid_bh = NULL; 15838c2ecf20Sopenharmony_ci return; 15848c2ecf20Sopenharmony_cicheck: 15858c2ecf20Sopenharmony_ci parts = le32_to_cpu(lvid->numOfPartitions); 15868c2ecf20Sopenharmony_ci impuselen = le32_to_cpu(lvid->lengthOfImpUse); 15878c2ecf20Sopenharmony_ci if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize || 15888c2ecf20Sopenharmony_ci sizeof(struct logicalVolIntegrityDesc) + impuselen + 15898c2ecf20Sopenharmony_ci 2 * parts * sizeof(u32) > sb->s_blocksize) { 15908c2ecf20Sopenharmony_ci udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), " 15918c2ecf20Sopenharmony_ci "ignoring.\n", parts, impuselen); 15928c2ecf20Sopenharmony_ci goto out_err; 15938c2ecf20Sopenharmony_ci } 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci/* 15978c2ecf20Sopenharmony_ci * Step for reallocation of table of partition descriptor sequence numbers. 15988c2ecf20Sopenharmony_ci * Must be power of 2. 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_ci#define PART_DESC_ALLOC_STEP 32 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_cistruct part_desc_seq_scan_data { 16038c2ecf20Sopenharmony_ci struct udf_vds_record rec; 16048c2ecf20Sopenharmony_ci u32 partnum; 16058c2ecf20Sopenharmony_ci}; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_cistruct desc_seq_scan_data { 16088c2ecf20Sopenharmony_ci struct udf_vds_record vds[VDS_POS_LENGTH]; 16098c2ecf20Sopenharmony_ci unsigned int size_part_descs; 16108c2ecf20Sopenharmony_ci unsigned int num_part_descs; 16118c2ecf20Sopenharmony_ci struct part_desc_seq_scan_data *part_descs_loc; 16128c2ecf20Sopenharmony_ci}; 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_cistatic struct udf_vds_record *handle_partition_descriptor( 16158c2ecf20Sopenharmony_ci struct buffer_head *bh, 16168c2ecf20Sopenharmony_ci struct desc_seq_scan_data *data) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci struct partitionDesc *desc = (struct partitionDesc *)bh->b_data; 16198c2ecf20Sopenharmony_ci int partnum; 16208c2ecf20Sopenharmony_ci int i; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci partnum = le16_to_cpu(desc->partitionNumber); 16238c2ecf20Sopenharmony_ci for (i = 0; i < data->num_part_descs; i++) 16248c2ecf20Sopenharmony_ci if (partnum == data->part_descs_loc[i].partnum) 16258c2ecf20Sopenharmony_ci return &(data->part_descs_loc[i].rec); 16268c2ecf20Sopenharmony_ci if (data->num_part_descs >= data->size_part_descs) { 16278c2ecf20Sopenharmony_ci struct part_desc_seq_scan_data *new_loc; 16288c2ecf20Sopenharmony_ci unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci new_loc = kcalloc(new_size, sizeof(*new_loc), GFP_KERNEL); 16318c2ecf20Sopenharmony_ci if (!new_loc) 16328c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 16338c2ecf20Sopenharmony_ci memcpy(new_loc, data->part_descs_loc, 16348c2ecf20Sopenharmony_ci data->size_part_descs * sizeof(*new_loc)); 16358c2ecf20Sopenharmony_ci kfree(data->part_descs_loc); 16368c2ecf20Sopenharmony_ci data->part_descs_loc = new_loc; 16378c2ecf20Sopenharmony_ci data->size_part_descs = new_size; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci return &(data->part_descs_loc[data->num_part_descs++].rec); 16408c2ecf20Sopenharmony_ci} 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic struct udf_vds_record *get_volume_descriptor_record(uint16_t ident, 16448c2ecf20Sopenharmony_ci struct buffer_head *bh, struct desc_seq_scan_data *data) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci switch (ident) { 16478c2ecf20Sopenharmony_ci case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ 16488c2ecf20Sopenharmony_ci return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]); 16498c2ecf20Sopenharmony_ci case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ 16508c2ecf20Sopenharmony_ci return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]); 16518c2ecf20Sopenharmony_ci case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ 16528c2ecf20Sopenharmony_ci return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]); 16538c2ecf20Sopenharmony_ci case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ 16548c2ecf20Sopenharmony_ci return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]); 16558c2ecf20Sopenharmony_ci case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 16568c2ecf20Sopenharmony_ci return handle_partition_descriptor(bh, data); 16578c2ecf20Sopenharmony_ci } 16588c2ecf20Sopenharmony_ci return NULL; 16598c2ecf20Sopenharmony_ci} 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci/* 16628c2ecf20Sopenharmony_ci * Process a main/reserve volume descriptor sequence. 16638c2ecf20Sopenharmony_ci * @block First block of first extent of the sequence. 16648c2ecf20Sopenharmony_ci * @lastblock Lastblock of first extent of the sequence. 16658c2ecf20Sopenharmony_ci * @fileset There we store extent containing root fileset 16668c2ecf20Sopenharmony_ci * 16678c2ecf20Sopenharmony_ci * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor 16688c2ecf20Sopenharmony_ci * sequence 16698c2ecf20Sopenharmony_ci */ 16708c2ecf20Sopenharmony_cistatic noinline int udf_process_sequence( 16718c2ecf20Sopenharmony_ci struct super_block *sb, 16728c2ecf20Sopenharmony_ci sector_t block, sector_t lastblock, 16738c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset) 16748c2ecf20Sopenharmony_ci{ 16758c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 16768c2ecf20Sopenharmony_ci struct udf_vds_record *curr; 16778c2ecf20Sopenharmony_ci struct generic_desc *gd; 16788c2ecf20Sopenharmony_ci struct volDescPtr *vdp; 16798c2ecf20Sopenharmony_ci bool done = false; 16808c2ecf20Sopenharmony_ci uint32_t vdsn; 16818c2ecf20Sopenharmony_ci uint16_t ident; 16828c2ecf20Sopenharmony_ci int ret; 16838c2ecf20Sopenharmony_ci unsigned int indirections = 0; 16848c2ecf20Sopenharmony_ci struct desc_seq_scan_data data; 16858c2ecf20Sopenharmony_ci unsigned int i; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); 16888c2ecf20Sopenharmony_ci data.size_part_descs = PART_DESC_ALLOC_STEP; 16898c2ecf20Sopenharmony_ci data.num_part_descs = 0; 16908c2ecf20Sopenharmony_ci data.part_descs_loc = kcalloc(data.size_part_descs, 16918c2ecf20Sopenharmony_ci sizeof(*data.part_descs_loc), 16928c2ecf20Sopenharmony_ci GFP_KERNEL); 16938c2ecf20Sopenharmony_ci if (!data.part_descs_loc) 16948c2ecf20Sopenharmony_ci return -ENOMEM; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci /* 16978c2ecf20Sopenharmony_ci * Read the main descriptor sequence and find which descriptors 16988c2ecf20Sopenharmony_ci * are in it. 16998c2ecf20Sopenharmony_ci */ 17008c2ecf20Sopenharmony_ci for (; (!done && block <= lastblock); block++) { 17018c2ecf20Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 17028c2ecf20Sopenharmony_ci if (!bh) 17038c2ecf20Sopenharmony_ci break; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* Process each descriptor (ISO 13346 3/8.3-8.4) */ 17068c2ecf20Sopenharmony_ci gd = (struct generic_desc *)bh->b_data; 17078c2ecf20Sopenharmony_ci vdsn = le32_to_cpu(gd->volDescSeqNum); 17088c2ecf20Sopenharmony_ci switch (ident) { 17098c2ecf20Sopenharmony_ci case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */ 17108c2ecf20Sopenharmony_ci if (++indirections > UDF_MAX_TD_NESTING) { 17118c2ecf20Sopenharmony_ci udf_err(sb, "too many Volume Descriptor " 17128c2ecf20Sopenharmony_ci "Pointers (max %u supported)\n", 17138c2ecf20Sopenharmony_ci UDF_MAX_TD_NESTING); 17148c2ecf20Sopenharmony_ci brelse(bh); 17158c2ecf20Sopenharmony_ci ret = -EIO; 17168c2ecf20Sopenharmony_ci goto out; 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci vdp = (struct volDescPtr *)bh->b_data; 17208c2ecf20Sopenharmony_ci block = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation); 17218c2ecf20Sopenharmony_ci lastblock = le32_to_cpu( 17228c2ecf20Sopenharmony_ci vdp->nextVolDescSeqExt.extLength) >> 17238c2ecf20Sopenharmony_ci sb->s_blocksize_bits; 17248c2ecf20Sopenharmony_ci lastblock += block - 1; 17258c2ecf20Sopenharmony_ci /* For loop is going to increment 'block' again */ 17268c2ecf20Sopenharmony_ci block--; 17278c2ecf20Sopenharmony_ci break; 17288c2ecf20Sopenharmony_ci case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ 17298c2ecf20Sopenharmony_ci case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ 17308c2ecf20Sopenharmony_ci case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ 17318c2ecf20Sopenharmony_ci case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ 17328c2ecf20Sopenharmony_ci case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 17338c2ecf20Sopenharmony_ci curr = get_volume_descriptor_record(ident, bh, &data); 17348c2ecf20Sopenharmony_ci if (IS_ERR(curr)) { 17358c2ecf20Sopenharmony_ci brelse(bh); 17368c2ecf20Sopenharmony_ci ret = PTR_ERR(curr); 17378c2ecf20Sopenharmony_ci goto out; 17388c2ecf20Sopenharmony_ci } 17398c2ecf20Sopenharmony_ci /* Descriptor we don't care about? */ 17408c2ecf20Sopenharmony_ci if (!curr) 17418c2ecf20Sopenharmony_ci break; 17428c2ecf20Sopenharmony_ci if (vdsn >= curr->volDescSeqNum) { 17438c2ecf20Sopenharmony_ci curr->volDescSeqNum = vdsn; 17448c2ecf20Sopenharmony_ci curr->block = block; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci break; 17478c2ecf20Sopenharmony_ci case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ 17488c2ecf20Sopenharmony_ci done = true; 17498c2ecf20Sopenharmony_ci break; 17508c2ecf20Sopenharmony_ci } 17518c2ecf20Sopenharmony_ci brelse(bh); 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci /* 17548c2ecf20Sopenharmony_ci * Now read interesting descriptors again and process them 17558c2ecf20Sopenharmony_ci * in a suitable order 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_ci if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) { 17588c2ecf20Sopenharmony_ci udf_err(sb, "Primary Volume Descriptor not found!\n"); 17598c2ecf20Sopenharmony_ci ret = -EAGAIN; 17608c2ecf20Sopenharmony_ci goto out; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block); 17638c2ecf20Sopenharmony_ci if (ret < 0) 17648c2ecf20Sopenharmony_ci goto out; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) { 17678c2ecf20Sopenharmony_ci ret = udf_load_logicalvol(sb, 17688c2ecf20Sopenharmony_ci data.vds[VDS_POS_LOGICAL_VOL_DESC].block, 17698c2ecf20Sopenharmony_ci fileset); 17708c2ecf20Sopenharmony_ci if (ret < 0) 17718c2ecf20Sopenharmony_ci goto out; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci /* Now handle prevailing Partition Descriptors */ 17758c2ecf20Sopenharmony_ci for (i = 0; i < data.num_part_descs; i++) { 17768c2ecf20Sopenharmony_ci ret = udf_load_partdesc(sb, data.part_descs_loc[i].rec.block); 17778c2ecf20Sopenharmony_ci if (ret < 0) 17788c2ecf20Sopenharmony_ci goto out; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci ret = 0; 17818c2ecf20Sopenharmony_ciout: 17828c2ecf20Sopenharmony_ci kfree(data.part_descs_loc); 17838c2ecf20Sopenharmony_ci return ret; 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci/* 17878c2ecf20Sopenharmony_ci * Load Volume Descriptor Sequence described by anchor in bh 17888c2ecf20Sopenharmony_ci * 17898c2ecf20Sopenharmony_ci * Returns <0 on error, 0 on success 17908c2ecf20Sopenharmony_ci */ 17918c2ecf20Sopenharmony_cistatic int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, 17928c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset) 17938c2ecf20Sopenharmony_ci{ 17948c2ecf20Sopenharmony_ci struct anchorVolDescPtr *anchor; 17958c2ecf20Sopenharmony_ci sector_t main_s, main_e, reserve_s, reserve_e; 17968c2ecf20Sopenharmony_ci int ret; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci anchor = (struct anchorVolDescPtr *)bh->b_data; 17998c2ecf20Sopenharmony_ci 18008c2ecf20Sopenharmony_ci /* Locate the main sequence */ 18018c2ecf20Sopenharmony_ci main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); 18028c2ecf20Sopenharmony_ci main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); 18038c2ecf20Sopenharmony_ci main_e = main_e >> sb->s_blocksize_bits; 18048c2ecf20Sopenharmony_ci main_e += main_s - 1; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci /* Locate the reserve sequence */ 18078c2ecf20Sopenharmony_ci reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); 18088c2ecf20Sopenharmony_ci reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); 18098c2ecf20Sopenharmony_ci reserve_e = reserve_e >> sb->s_blocksize_bits; 18108c2ecf20Sopenharmony_ci reserve_e += reserve_s - 1; 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci /* Process the main & reserve sequences */ 18138c2ecf20Sopenharmony_ci /* responsible for finding the PartitionDesc(s) */ 18148c2ecf20Sopenharmony_ci ret = udf_process_sequence(sb, main_s, main_e, fileset); 18158c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 18168c2ecf20Sopenharmony_ci return ret; 18178c2ecf20Sopenharmony_ci udf_sb_free_partitions(sb); 18188c2ecf20Sopenharmony_ci ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset); 18198c2ecf20Sopenharmony_ci if (ret < 0) { 18208c2ecf20Sopenharmony_ci udf_sb_free_partitions(sb); 18218c2ecf20Sopenharmony_ci /* No sequence was OK, return -EIO */ 18228c2ecf20Sopenharmony_ci if (ret == -EAGAIN) 18238c2ecf20Sopenharmony_ci ret = -EIO; 18248c2ecf20Sopenharmony_ci } 18258c2ecf20Sopenharmony_ci return ret; 18268c2ecf20Sopenharmony_ci} 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci/* 18298c2ecf20Sopenharmony_ci * Check whether there is an anchor block in the given block and 18308c2ecf20Sopenharmony_ci * load Volume Descriptor Sequence if so. 18318c2ecf20Sopenharmony_ci * 18328c2ecf20Sopenharmony_ci * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor 18338c2ecf20Sopenharmony_ci * block 18348c2ecf20Sopenharmony_ci */ 18358c2ecf20Sopenharmony_cistatic int udf_check_anchor_block(struct super_block *sb, sector_t block, 18368c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci struct buffer_head *bh; 18398c2ecf20Sopenharmony_ci uint16_t ident; 18408c2ecf20Sopenharmony_ci int ret; 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && 18438c2ecf20Sopenharmony_ci udf_fixed_to_variable(block) >= 18448c2ecf20Sopenharmony_ci i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits) 18458c2ecf20Sopenharmony_ci return -EAGAIN; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 18488c2ecf20Sopenharmony_ci if (!bh) 18498c2ecf20Sopenharmony_ci return -EAGAIN; 18508c2ecf20Sopenharmony_ci if (ident != TAG_IDENT_AVDP) { 18518c2ecf20Sopenharmony_ci brelse(bh); 18528c2ecf20Sopenharmony_ci return -EAGAIN; 18538c2ecf20Sopenharmony_ci } 18548c2ecf20Sopenharmony_ci ret = udf_load_sequence(sb, bh, fileset); 18558c2ecf20Sopenharmony_ci brelse(bh); 18568c2ecf20Sopenharmony_ci return ret; 18578c2ecf20Sopenharmony_ci} 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci/* 18608c2ecf20Sopenharmony_ci * Search for an anchor volume descriptor pointer. 18618c2ecf20Sopenharmony_ci * 18628c2ecf20Sopenharmony_ci * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set 18638c2ecf20Sopenharmony_ci * of anchors. 18648c2ecf20Sopenharmony_ci */ 18658c2ecf20Sopenharmony_cistatic int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, 18668c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci sector_t last[6]; 18698c2ecf20Sopenharmony_ci int i; 18708c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 18718c2ecf20Sopenharmony_ci int last_count = 0; 18728c2ecf20Sopenharmony_ci int ret; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci /* First try user provided anchor */ 18758c2ecf20Sopenharmony_ci if (sbi->s_anchor) { 18768c2ecf20Sopenharmony_ci ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset); 18778c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 18788c2ecf20Sopenharmony_ci return ret; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci /* 18818c2ecf20Sopenharmony_ci * according to spec, anchor is in either: 18828c2ecf20Sopenharmony_ci * block 256 18838c2ecf20Sopenharmony_ci * lastblock-256 18848c2ecf20Sopenharmony_ci * lastblock 18858c2ecf20Sopenharmony_ci * however, if the disc isn't closed, it could be 512. 18868c2ecf20Sopenharmony_ci */ 18878c2ecf20Sopenharmony_ci ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset); 18888c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 18898c2ecf20Sopenharmony_ci return ret; 18908c2ecf20Sopenharmony_ci /* 18918c2ecf20Sopenharmony_ci * The trouble is which block is the last one. Drives often misreport 18928c2ecf20Sopenharmony_ci * this so we try various possibilities. 18938c2ecf20Sopenharmony_ci */ 18948c2ecf20Sopenharmony_ci last[last_count++] = *lastblock; 18958c2ecf20Sopenharmony_ci if (*lastblock >= 1) 18968c2ecf20Sopenharmony_ci last[last_count++] = *lastblock - 1; 18978c2ecf20Sopenharmony_ci last[last_count++] = *lastblock + 1; 18988c2ecf20Sopenharmony_ci if (*lastblock >= 2) 18998c2ecf20Sopenharmony_ci last[last_count++] = *lastblock - 2; 19008c2ecf20Sopenharmony_ci if (*lastblock >= 150) 19018c2ecf20Sopenharmony_ci last[last_count++] = *lastblock - 150; 19028c2ecf20Sopenharmony_ci if (*lastblock >= 152) 19038c2ecf20Sopenharmony_ci last[last_count++] = *lastblock - 152; 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci for (i = 0; i < last_count; i++) { 19068c2ecf20Sopenharmony_ci if (last[i] >= i_size_read(sb->s_bdev->bd_inode) >> 19078c2ecf20Sopenharmony_ci sb->s_blocksize_bits) 19088c2ecf20Sopenharmony_ci continue; 19098c2ecf20Sopenharmony_ci ret = udf_check_anchor_block(sb, last[i], fileset); 19108c2ecf20Sopenharmony_ci if (ret != -EAGAIN) { 19118c2ecf20Sopenharmony_ci if (!ret) 19128c2ecf20Sopenharmony_ci *lastblock = last[i]; 19138c2ecf20Sopenharmony_ci return ret; 19148c2ecf20Sopenharmony_ci } 19158c2ecf20Sopenharmony_ci if (last[i] < 256) 19168c2ecf20Sopenharmony_ci continue; 19178c2ecf20Sopenharmony_ci ret = udf_check_anchor_block(sb, last[i] - 256, fileset); 19188c2ecf20Sopenharmony_ci if (ret != -EAGAIN) { 19198c2ecf20Sopenharmony_ci if (!ret) 19208c2ecf20Sopenharmony_ci *lastblock = last[i]; 19218c2ecf20Sopenharmony_ci return ret; 19228c2ecf20Sopenharmony_ci } 19238c2ecf20Sopenharmony_ci } 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci /* Finally try block 512 in case media is open */ 19268c2ecf20Sopenharmony_ci return udf_check_anchor_block(sb, sbi->s_session + 512, fileset); 19278c2ecf20Sopenharmony_ci} 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci/* 19308c2ecf20Sopenharmony_ci * Find an anchor volume descriptor and load Volume Descriptor Sequence from 19318c2ecf20Sopenharmony_ci * area specified by it. The function expects sbi->s_lastblock to be the last 19328c2ecf20Sopenharmony_ci * block on the media. 19338c2ecf20Sopenharmony_ci * 19348c2ecf20Sopenharmony_ci * Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor 19358c2ecf20Sopenharmony_ci * was not found. 19368c2ecf20Sopenharmony_ci */ 19378c2ecf20Sopenharmony_cistatic int udf_find_anchor(struct super_block *sb, 19388c2ecf20Sopenharmony_ci struct kernel_lb_addr *fileset) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 19418c2ecf20Sopenharmony_ci sector_t lastblock = sbi->s_last_block; 19428c2ecf20Sopenharmony_ci int ret; 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_ci ret = udf_scan_anchors(sb, &lastblock, fileset); 19458c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 19468c2ecf20Sopenharmony_ci goto out; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci /* No anchor found? Try VARCONV conversion of block numbers */ 19498c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); 19508c2ecf20Sopenharmony_ci lastblock = udf_variable_to_fixed(sbi->s_last_block); 19518c2ecf20Sopenharmony_ci /* Firstly, we try to not convert number of the last block */ 19528c2ecf20Sopenharmony_ci ret = udf_scan_anchors(sb, &lastblock, fileset); 19538c2ecf20Sopenharmony_ci if (ret != -EAGAIN) 19548c2ecf20Sopenharmony_ci goto out; 19558c2ecf20Sopenharmony_ci 19568c2ecf20Sopenharmony_ci lastblock = sbi->s_last_block; 19578c2ecf20Sopenharmony_ci /* Secondly, we try with converted number of the last block */ 19588c2ecf20Sopenharmony_ci ret = udf_scan_anchors(sb, &lastblock, fileset); 19598c2ecf20Sopenharmony_ci if (ret < 0) { 19608c2ecf20Sopenharmony_ci /* VARCONV didn't help. Clear it. */ 19618c2ecf20Sopenharmony_ci UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ciout: 19648c2ecf20Sopenharmony_ci if (ret == 0) 19658c2ecf20Sopenharmony_ci sbi->s_last_block = lastblock; 19668c2ecf20Sopenharmony_ci return ret; 19678c2ecf20Sopenharmony_ci} 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_ci/* 19708c2ecf20Sopenharmony_ci * Check Volume Structure Descriptor, find Anchor block and load Volume 19718c2ecf20Sopenharmony_ci * Descriptor Sequence. 19728c2ecf20Sopenharmony_ci * 19738c2ecf20Sopenharmony_ci * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor 19748c2ecf20Sopenharmony_ci * block was not found. 19758c2ecf20Sopenharmony_ci */ 19768c2ecf20Sopenharmony_cistatic int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, 19778c2ecf20Sopenharmony_ci int silent, struct kernel_lb_addr *fileset) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 19808c2ecf20Sopenharmony_ci int nsr = 0; 19818c2ecf20Sopenharmony_ci int ret; 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci if (!sb_set_blocksize(sb, uopt->blocksize)) { 19848c2ecf20Sopenharmony_ci if (!silent) 19858c2ecf20Sopenharmony_ci udf_warn(sb, "Bad block size\n"); 19868c2ecf20Sopenharmony_ci return -EINVAL; 19878c2ecf20Sopenharmony_ci } 19888c2ecf20Sopenharmony_ci sbi->s_last_block = uopt->lastblock; 19898c2ecf20Sopenharmony_ci if (!uopt->novrs) { 19908c2ecf20Sopenharmony_ci /* Check that it is NSR02 compliant */ 19918c2ecf20Sopenharmony_ci nsr = udf_check_vsd(sb); 19928c2ecf20Sopenharmony_ci if (!nsr) { 19938c2ecf20Sopenharmony_ci if (!silent) 19948c2ecf20Sopenharmony_ci udf_warn(sb, "No VRS found\n"); 19958c2ecf20Sopenharmony_ci return -EINVAL; 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci if (nsr == -1) 19988c2ecf20Sopenharmony_ci udf_debug("Failed to read sector at offset %d. " 19998c2ecf20Sopenharmony_ci "Assuming open disc. Skipping validity " 20008c2ecf20Sopenharmony_ci "check\n", VSD_FIRST_SECTOR_OFFSET); 20018c2ecf20Sopenharmony_ci if (!sbi->s_last_block) 20028c2ecf20Sopenharmony_ci sbi->s_last_block = udf_get_last_block(sb); 20038c2ecf20Sopenharmony_ci } else { 20048c2ecf20Sopenharmony_ci udf_debug("Validity check skipped because of novrs option\n"); 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* Look for anchor block and load Volume Descriptor Sequence */ 20088c2ecf20Sopenharmony_ci sbi->s_anchor = uopt->anchor; 20098c2ecf20Sopenharmony_ci ret = udf_find_anchor(sb, fileset); 20108c2ecf20Sopenharmony_ci if (ret < 0) { 20118c2ecf20Sopenharmony_ci if (!silent && ret == -EAGAIN) 20128c2ecf20Sopenharmony_ci udf_warn(sb, "No anchor found\n"); 20138c2ecf20Sopenharmony_ci return ret; 20148c2ecf20Sopenharmony_ci } 20158c2ecf20Sopenharmony_ci return 0; 20168c2ecf20Sopenharmony_ci} 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_cistatic void udf_finalize_lvid(struct logicalVolIntegrityDesc *lvid) 20198c2ecf20Sopenharmony_ci{ 20208c2ecf20Sopenharmony_ci struct timespec64 ts; 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci ktime_get_real_ts64(&ts); 20238c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); 20248c2ecf20Sopenharmony_ci lvid->descTag.descCRC = cpu_to_le16( 20258c2ecf20Sopenharmony_ci crc_itu_t(0, (char *)lvid + sizeof(struct tag), 20268c2ecf20Sopenharmony_ci le16_to_cpu(lvid->descTag.descCRCLength))); 20278c2ecf20Sopenharmony_ci lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); 20288c2ecf20Sopenharmony_ci} 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_cistatic void udf_open_lvid(struct super_block *sb) 20318c2ecf20Sopenharmony_ci{ 20328c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 20338c2ecf20Sopenharmony_ci struct buffer_head *bh = sbi->s_lvid_bh; 20348c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 20358c2ecf20Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu; 20368c2ecf20Sopenharmony_ci 20378c2ecf20Sopenharmony_ci if (!bh) 20388c2ecf20Sopenharmony_ci return; 20398c2ecf20Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 20408c2ecf20Sopenharmony_ci lvidiu = udf_sb_lvidiu(sb); 20418c2ecf20Sopenharmony_ci if (!lvidiu) 20428c2ecf20Sopenharmony_ci return; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 20458c2ecf20Sopenharmony_ci lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 20468c2ecf20Sopenharmony_ci lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 20478c2ecf20Sopenharmony_ci if (le32_to_cpu(lvid->integrityType) == LVID_INTEGRITY_TYPE_CLOSE) 20488c2ecf20Sopenharmony_ci lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN); 20498c2ecf20Sopenharmony_ci else 20508c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT); 20518c2ecf20Sopenharmony_ci 20528c2ecf20Sopenharmony_ci udf_finalize_lvid(lvid); 20538c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 20548c2ecf20Sopenharmony_ci sbi->s_lvid_dirty = 0; 20558c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 20568c2ecf20Sopenharmony_ci /* Make opening of filesystem visible on the media immediately */ 20578c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 20588c2ecf20Sopenharmony_ci} 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_cistatic void udf_close_lvid(struct super_block *sb) 20618c2ecf20Sopenharmony_ci{ 20628c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 20638c2ecf20Sopenharmony_ci struct buffer_head *bh = sbi->s_lvid_bh; 20648c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 20658c2ecf20Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci if (!bh) 20688c2ecf20Sopenharmony_ci return; 20698c2ecf20Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 20708c2ecf20Sopenharmony_ci lvidiu = udf_sb_lvidiu(sb); 20718c2ecf20Sopenharmony_ci if (!lvidiu) 20728c2ecf20Sopenharmony_ci return; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 20758c2ecf20Sopenharmony_ci lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 20768c2ecf20Sopenharmony_ci lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 20778c2ecf20Sopenharmony_ci if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) 20788c2ecf20Sopenharmony_ci lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); 20798c2ecf20Sopenharmony_ci if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) 20808c2ecf20Sopenharmony_ci lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); 20818c2ecf20Sopenharmony_ci if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) 20828c2ecf20Sopenharmony_ci lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); 20838c2ecf20Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT)) 20848c2ecf20Sopenharmony_ci lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* 20878c2ecf20Sopenharmony_ci * We set buffer uptodate unconditionally here to avoid spurious 20888c2ecf20Sopenharmony_ci * warnings from mark_buffer_dirty() when previous EIO has marked 20898c2ecf20Sopenharmony_ci * the buffer as !uptodate 20908c2ecf20Sopenharmony_ci */ 20918c2ecf20Sopenharmony_ci set_buffer_uptodate(bh); 20928c2ecf20Sopenharmony_ci udf_finalize_lvid(lvid); 20938c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 20948c2ecf20Sopenharmony_ci sbi->s_lvid_dirty = 0; 20958c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 20968c2ecf20Sopenharmony_ci /* Make closing of filesystem visible on the media immediately */ 20978c2ecf20Sopenharmony_ci sync_dirty_buffer(bh); 20988c2ecf20Sopenharmony_ci} 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ciu64 lvid_get_unique_id(struct super_block *sb) 21018c2ecf20Sopenharmony_ci{ 21028c2ecf20Sopenharmony_ci struct buffer_head *bh; 21038c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 21048c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 21058c2ecf20Sopenharmony_ci struct logicalVolHeaderDesc *lvhd; 21068c2ecf20Sopenharmony_ci u64 uniqueID; 21078c2ecf20Sopenharmony_ci u64 ret; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci bh = sbi->s_lvid_bh; 21108c2ecf20Sopenharmony_ci if (!bh) 21118c2ecf20Sopenharmony_ci return 0; 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 21148c2ecf20Sopenharmony_ci lvhd = (struct logicalVolHeaderDesc *)lvid->logicalVolContentsUse; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 21178c2ecf20Sopenharmony_ci ret = uniqueID = le64_to_cpu(lvhd->uniqueID); 21188c2ecf20Sopenharmony_ci if (!(++uniqueID & 0xFFFFFFFF)) 21198c2ecf20Sopenharmony_ci uniqueID += 16; 21208c2ecf20Sopenharmony_ci lvhd->uniqueID = cpu_to_le64(uniqueID); 21218c2ecf20Sopenharmony_ci udf_updated_lvid(sb); 21228c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci return ret; 21258c2ecf20Sopenharmony_ci} 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_cistatic int udf_fill_super(struct super_block *sb, void *options, int silent) 21288c2ecf20Sopenharmony_ci{ 21298c2ecf20Sopenharmony_ci int ret = -EINVAL; 21308c2ecf20Sopenharmony_ci struct inode *inode = NULL; 21318c2ecf20Sopenharmony_ci struct udf_options uopt; 21328c2ecf20Sopenharmony_ci struct kernel_lb_addr rootdir, fileset; 21338c2ecf20Sopenharmony_ci struct udf_sb_info *sbi; 21348c2ecf20Sopenharmony_ci bool lvid_open = false; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); 21378c2ecf20Sopenharmony_ci /* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */ 21388c2ecf20Sopenharmony_ci uopt.uid = make_kuid(current_user_ns(), overflowuid); 21398c2ecf20Sopenharmony_ci uopt.gid = make_kgid(current_user_ns(), overflowgid); 21408c2ecf20Sopenharmony_ci uopt.umask = 0; 21418c2ecf20Sopenharmony_ci uopt.fmode = UDF_INVALID_MODE; 21428c2ecf20Sopenharmony_ci uopt.dmode = UDF_INVALID_MODE; 21438c2ecf20Sopenharmony_ci uopt.nls_map = NULL; 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 21468c2ecf20Sopenharmony_ci if (!sbi) 21478c2ecf20Sopenharmony_ci return -ENOMEM; 21488c2ecf20Sopenharmony_ci 21498c2ecf20Sopenharmony_ci sb->s_fs_info = sbi; 21508c2ecf20Sopenharmony_ci 21518c2ecf20Sopenharmony_ci mutex_init(&sbi->s_alloc_mutex); 21528c2ecf20Sopenharmony_ci 21538c2ecf20Sopenharmony_ci if (!udf_parse_options((char *)options, &uopt, false)) 21548c2ecf20Sopenharmony_ci goto parse_options_failure; 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci fileset.logicalBlockNum = 0xFFFFFFFF; 21578c2ecf20Sopenharmony_ci fileset.partitionReferenceNum = 0xFFFF; 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci sbi->s_flags = uopt.flags; 21608c2ecf20Sopenharmony_ci sbi->s_uid = uopt.uid; 21618c2ecf20Sopenharmony_ci sbi->s_gid = uopt.gid; 21628c2ecf20Sopenharmony_ci sbi->s_umask = uopt.umask; 21638c2ecf20Sopenharmony_ci sbi->s_fmode = uopt.fmode; 21648c2ecf20Sopenharmony_ci sbi->s_dmode = uopt.dmode; 21658c2ecf20Sopenharmony_ci sbi->s_nls_map = uopt.nls_map; 21668c2ecf20Sopenharmony_ci rwlock_init(&sbi->s_cred_lock); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci if (uopt.session == 0xFFFFFFFF) 21698c2ecf20Sopenharmony_ci sbi->s_session = udf_get_last_session(sb); 21708c2ecf20Sopenharmony_ci else 21718c2ecf20Sopenharmony_ci sbi->s_session = uopt.session; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci udf_debug("Multi-session=%d\n", sbi->s_session); 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci /* Fill in the rest of the superblock */ 21768c2ecf20Sopenharmony_ci sb->s_op = &udf_sb_ops; 21778c2ecf20Sopenharmony_ci sb->s_export_op = &udf_export_ops; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci sb->s_magic = UDF_SUPER_MAGIC; 21808c2ecf20Sopenharmony_ci sb->s_time_gran = 1000; 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) { 21838c2ecf20Sopenharmony_ci ret = udf_load_vrs(sb, &uopt, silent, &fileset); 21848c2ecf20Sopenharmony_ci } else { 21858c2ecf20Sopenharmony_ci uopt.blocksize = bdev_logical_block_size(sb->s_bdev); 21868c2ecf20Sopenharmony_ci while (uopt.blocksize <= 4096) { 21878c2ecf20Sopenharmony_ci ret = udf_load_vrs(sb, &uopt, silent, &fileset); 21888c2ecf20Sopenharmony_ci if (ret < 0) { 21898c2ecf20Sopenharmony_ci if (!silent && ret != -EACCES) { 21908c2ecf20Sopenharmony_ci pr_notice("Scanning with blocksize %u failed\n", 21918c2ecf20Sopenharmony_ci uopt.blocksize); 21928c2ecf20Sopenharmony_ci } 21938c2ecf20Sopenharmony_ci brelse(sbi->s_lvid_bh); 21948c2ecf20Sopenharmony_ci sbi->s_lvid_bh = NULL; 21958c2ecf20Sopenharmony_ci /* 21968c2ecf20Sopenharmony_ci * EACCES is special - we want to propagate to 21978c2ecf20Sopenharmony_ci * upper layers that we cannot handle RW mount. 21988c2ecf20Sopenharmony_ci */ 21998c2ecf20Sopenharmony_ci if (ret == -EACCES) 22008c2ecf20Sopenharmony_ci break; 22018c2ecf20Sopenharmony_ci } else 22028c2ecf20Sopenharmony_ci break; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci uopt.blocksize <<= 1; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci if (ret < 0) { 22088c2ecf20Sopenharmony_ci if (ret == -EAGAIN) { 22098c2ecf20Sopenharmony_ci udf_warn(sb, "No partition found (1)\n"); 22108c2ecf20Sopenharmony_ci ret = -EINVAL; 22118c2ecf20Sopenharmony_ci } 22128c2ecf20Sopenharmony_ci goto error_out; 22138c2ecf20Sopenharmony_ci } 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci udf_debug("Lastblock=%u\n", sbi->s_last_block); 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci if (sbi->s_lvid_bh) { 22188c2ecf20Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu = 22198c2ecf20Sopenharmony_ci udf_sb_lvidiu(sb); 22208c2ecf20Sopenharmony_ci uint16_t minUDFReadRev; 22218c2ecf20Sopenharmony_ci uint16_t minUDFWriteRev; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci if (!lvidiu) { 22248c2ecf20Sopenharmony_ci ret = -EINVAL; 22258c2ecf20Sopenharmony_ci goto error_out; 22268c2ecf20Sopenharmony_ci } 22278c2ecf20Sopenharmony_ci minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev); 22288c2ecf20Sopenharmony_ci minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev); 22298c2ecf20Sopenharmony_ci if (minUDFReadRev > UDF_MAX_READ_VERSION) { 22308c2ecf20Sopenharmony_ci udf_err(sb, "minUDFReadRev=%x (max is %x)\n", 22318c2ecf20Sopenharmony_ci minUDFReadRev, 22328c2ecf20Sopenharmony_ci UDF_MAX_READ_VERSION); 22338c2ecf20Sopenharmony_ci ret = -EINVAL; 22348c2ecf20Sopenharmony_ci goto error_out; 22358c2ecf20Sopenharmony_ci } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) { 22368c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 22378c2ecf20Sopenharmony_ci ret = -EACCES; 22388c2ecf20Sopenharmony_ci goto error_out; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci sbi->s_udfrev = minUDFWriteRev; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE) 22468c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE); 22478c2ecf20Sopenharmony_ci if (minUDFReadRev >= UDF_VERS_USE_STREAMS) 22488c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS); 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci if (!sbi->s_partitions) { 22528c2ecf20Sopenharmony_ci udf_warn(sb, "No partition found (2)\n"); 22538c2ecf20Sopenharmony_ci ret = -EINVAL; 22548c2ecf20Sopenharmony_ci goto error_out; 22558c2ecf20Sopenharmony_ci } 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci if (sbi->s_partmaps[sbi->s_partition].s_partition_flags & 22588c2ecf20Sopenharmony_ci UDF_PART_FLAG_READ_ONLY) { 22598c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 22608c2ecf20Sopenharmony_ci ret = -EACCES; 22618c2ecf20Sopenharmony_ci goto error_out; 22628c2ecf20Sopenharmony_ci } 22638c2ecf20Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 22648c2ecf20Sopenharmony_ci } 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci ret = udf_find_fileset(sb, &fileset, &rootdir); 22678c2ecf20Sopenharmony_ci if (ret < 0) { 22688c2ecf20Sopenharmony_ci udf_warn(sb, "No fileset found\n"); 22698c2ecf20Sopenharmony_ci goto error_out; 22708c2ecf20Sopenharmony_ci } 22718c2ecf20Sopenharmony_ci 22728c2ecf20Sopenharmony_ci if (!silent) { 22738c2ecf20Sopenharmony_ci struct timestamp ts; 22748c2ecf20Sopenharmony_ci udf_time_to_disk_stamp(&ts, sbi->s_record_time); 22758c2ecf20Sopenharmony_ci udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n", 22768c2ecf20Sopenharmony_ci sbi->s_volume_ident, 22778c2ecf20Sopenharmony_ci le16_to_cpu(ts.year), ts.month, ts.day, 22788c2ecf20Sopenharmony_ci ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone)); 22798c2ecf20Sopenharmony_ci } 22808c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) { 22818c2ecf20Sopenharmony_ci udf_open_lvid(sb); 22828c2ecf20Sopenharmony_ci lvid_open = true; 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_ci /* Assign the root inode */ 22868c2ecf20Sopenharmony_ci /* assign inodes by physical block number */ 22878c2ecf20Sopenharmony_ci /* perhaps it's not extensible enough, but for now ... */ 22888c2ecf20Sopenharmony_ci inode = udf_iget(sb, &rootdir); 22898c2ecf20Sopenharmony_ci if (IS_ERR(inode)) { 22908c2ecf20Sopenharmony_ci udf_err(sb, "Error in udf_iget, block=%u, partition=%u\n", 22918c2ecf20Sopenharmony_ci rootdir.logicalBlockNum, rootdir.partitionReferenceNum); 22928c2ecf20Sopenharmony_ci ret = PTR_ERR(inode); 22938c2ecf20Sopenharmony_ci goto error_out; 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci /* Allocate a dentry for the root inode */ 22978c2ecf20Sopenharmony_ci sb->s_root = d_make_root(inode); 22988c2ecf20Sopenharmony_ci if (!sb->s_root) { 22998c2ecf20Sopenharmony_ci udf_err(sb, "Couldn't allocate root dentry\n"); 23008c2ecf20Sopenharmony_ci ret = -ENOMEM; 23018c2ecf20Sopenharmony_ci goto error_out; 23028c2ecf20Sopenharmony_ci } 23038c2ecf20Sopenharmony_ci sb->s_maxbytes = MAX_LFS_FILESIZE; 23048c2ecf20Sopenharmony_ci sb->s_max_links = UDF_MAX_LINKS; 23058c2ecf20Sopenharmony_ci return 0; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_cierror_out: 23088c2ecf20Sopenharmony_ci iput(sbi->s_vat_inode); 23098c2ecf20Sopenharmony_ciparse_options_failure: 23108c2ecf20Sopenharmony_ci unload_nls(uopt.nls_map); 23118c2ecf20Sopenharmony_ci if (lvid_open) 23128c2ecf20Sopenharmony_ci udf_close_lvid(sb); 23138c2ecf20Sopenharmony_ci brelse(sbi->s_lvid_bh); 23148c2ecf20Sopenharmony_ci udf_sb_free_partitions(sb); 23158c2ecf20Sopenharmony_ci kfree(sbi); 23168c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci return ret; 23198c2ecf20Sopenharmony_ci} 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_civoid _udf_err(struct super_block *sb, const char *function, 23228c2ecf20Sopenharmony_ci const char *fmt, ...) 23238c2ecf20Sopenharmony_ci{ 23248c2ecf20Sopenharmony_ci struct va_format vaf; 23258c2ecf20Sopenharmony_ci va_list args; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci va_start(args, fmt); 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci vaf.fmt = fmt; 23308c2ecf20Sopenharmony_ci vaf.va = &args; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci pr_err("error (device %s): %s: %pV", sb->s_id, function, &vaf); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci va_end(args); 23358c2ecf20Sopenharmony_ci} 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_civoid _udf_warn(struct super_block *sb, const char *function, 23388c2ecf20Sopenharmony_ci const char *fmt, ...) 23398c2ecf20Sopenharmony_ci{ 23408c2ecf20Sopenharmony_ci struct va_format vaf; 23418c2ecf20Sopenharmony_ci va_list args; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci va_start(args, fmt); 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci vaf.fmt = fmt; 23468c2ecf20Sopenharmony_ci vaf.va = &args; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci pr_warn("warning (device %s): %s: %pV", sb->s_id, function, &vaf); 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci va_end(args); 23518c2ecf20Sopenharmony_ci} 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_cistatic void udf_put_super(struct super_block *sb) 23548c2ecf20Sopenharmony_ci{ 23558c2ecf20Sopenharmony_ci struct udf_sb_info *sbi; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci sbi = UDF_SB(sb); 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci iput(sbi->s_vat_inode); 23608c2ecf20Sopenharmony_ci unload_nls(sbi->s_nls_map); 23618c2ecf20Sopenharmony_ci if (!sb_rdonly(sb)) 23628c2ecf20Sopenharmony_ci udf_close_lvid(sb); 23638c2ecf20Sopenharmony_ci brelse(sbi->s_lvid_bh); 23648c2ecf20Sopenharmony_ci udf_sb_free_partitions(sb); 23658c2ecf20Sopenharmony_ci mutex_destroy(&sbi->s_alloc_mutex); 23668c2ecf20Sopenharmony_ci kfree(sb->s_fs_info); 23678c2ecf20Sopenharmony_ci sb->s_fs_info = NULL; 23688c2ecf20Sopenharmony_ci} 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_cistatic int udf_sync_fs(struct super_block *sb, int wait) 23718c2ecf20Sopenharmony_ci{ 23728c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 23758c2ecf20Sopenharmony_ci if (sbi->s_lvid_dirty) { 23768c2ecf20Sopenharmony_ci struct buffer_head *bh = sbi->s_lvid_bh; 23778c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 23808c2ecf20Sopenharmony_ci udf_finalize_lvid(lvid); 23818c2ecf20Sopenharmony_ci 23828c2ecf20Sopenharmony_ci /* 23838c2ecf20Sopenharmony_ci * Blockdevice will be synced later so we don't have to submit 23848c2ecf20Sopenharmony_ci * the buffer for IO 23858c2ecf20Sopenharmony_ci */ 23868c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 23878c2ecf20Sopenharmony_ci sbi->s_lvid_dirty = 0; 23888c2ecf20Sopenharmony_ci } 23898c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci return 0; 23928c2ecf20Sopenharmony_ci} 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_cistatic int udf_statfs(struct dentry *dentry, struct kstatfs *buf) 23958c2ecf20Sopenharmony_ci{ 23968c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 23978c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 23988c2ecf20Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu; 23998c2ecf20Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci lvidiu = udf_sb_lvidiu(sb); 24028c2ecf20Sopenharmony_ci buf->f_type = UDF_SUPER_MAGIC; 24038c2ecf20Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 24048c2ecf20Sopenharmony_ci buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len; 24058c2ecf20Sopenharmony_ci buf->f_bfree = udf_count_free(sb); 24068c2ecf20Sopenharmony_ci buf->f_bavail = buf->f_bfree; 24078c2ecf20Sopenharmony_ci /* 24088c2ecf20Sopenharmony_ci * Let's pretend each free block is also a free 'inode' since UDF does 24098c2ecf20Sopenharmony_ci * not have separate preallocated table of inodes. 24108c2ecf20Sopenharmony_ci */ 24118c2ecf20Sopenharmony_ci buf->f_files = (lvidiu != NULL ? (le32_to_cpu(lvidiu->numFiles) + 24128c2ecf20Sopenharmony_ci le32_to_cpu(lvidiu->numDirs)) : 0) 24138c2ecf20Sopenharmony_ci + buf->f_bfree; 24148c2ecf20Sopenharmony_ci buf->f_ffree = buf->f_bfree; 24158c2ecf20Sopenharmony_ci buf->f_namelen = UDF_NAME_LEN; 24168c2ecf20Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci return 0; 24198c2ecf20Sopenharmony_ci} 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_cistatic unsigned int udf_count_free_bitmap(struct super_block *sb, 24228c2ecf20Sopenharmony_ci struct udf_bitmap *bitmap) 24238c2ecf20Sopenharmony_ci{ 24248c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 24258c2ecf20Sopenharmony_ci unsigned int accum = 0; 24268c2ecf20Sopenharmony_ci int index; 24278c2ecf20Sopenharmony_ci udf_pblk_t block = 0, newblock; 24288c2ecf20Sopenharmony_ci struct kernel_lb_addr loc; 24298c2ecf20Sopenharmony_ci uint32_t bytes; 24308c2ecf20Sopenharmony_ci uint8_t *ptr; 24318c2ecf20Sopenharmony_ci uint16_t ident; 24328c2ecf20Sopenharmony_ci struct spaceBitmapDesc *bm; 24338c2ecf20Sopenharmony_ci 24348c2ecf20Sopenharmony_ci loc.logicalBlockNum = bitmap->s_extPosition; 24358c2ecf20Sopenharmony_ci loc.partitionReferenceNum = UDF_SB(sb)->s_partition; 24368c2ecf20Sopenharmony_ci bh = udf_read_ptagged(sb, &loc, 0, &ident); 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci if (!bh) { 24398c2ecf20Sopenharmony_ci udf_err(sb, "udf_count_free failed\n"); 24408c2ecf20Sopenharmony_ci goto out; 24418c2ecf20Sopenharmony_ci } else if (ident != TAG_IDENT_SBD) { 24428c2ecf20Sopenharmony_ci brelse(bh); 24438c2ecf20Sopenharmony_ci udf_err(sb, "udf_count_free failed\n"); 24448c2ecf20Sopenharmony_ci goto out; 24458c2ecf20Sopenharmony_ci } 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci bm = (struct spaceBitmapDesc *)bh->b_data; 24488c2ecf20Sopenharmony_ci bytes = le32_to_cpu(bm->numOfBytes); 24498c2ecf20Sopenharmony_ci index = sizeof(struct spaceBitmapDesc); /* offset in first block only */ 24508c2ecf20Sopenharmony_ci ptr = (uint8_t *)bh->b_data; 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci while (bytes > 0) { 24538c2ecf20Sopenharmony_ci u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index); 24548c2ecf20Sopenharmony_ci accum += bitmap_weight((const unsigned long *)(ptr + index), 24558c2ecf20Sopenharmony_ci cur_bytes * 8); 24568c2ecf20Sopenharmony_ci bytes -= cur_bytes; 24578c2ecf20Sopenharmony_ci if (bytes) { 24588c2ecf20Sopenharmony_ci brelse(bh); 24598c2ecf20Sopenharmony_ci newblock = udf_get_lb_pblock(sb, &loc, ++block); 24608c2ecf20Sopenharmony_ci bh = udf_tread(sb, newblock); 24618c2ecf20Sopenharmony_ci if (!bh) { 24628c2ecf20Sopenharmony_ci udf_debug("read failed\n"); 24638c2ecf20Sopenharmony_ci goto out; 24648c2ecf20Sopenharmony_ci } 24658c2ecf20Sopenharmony_ci index = 0; 24668c2ecf20Sopenharmony_ci ptr = (uint8_t *)bh->b_data; 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci brelse(bh); 24708c2ecf20Sopenharmony_ciout: 24718c2ecf20Sopenharmony_ci return accum; 24728c2ecf20Sopenharmony_ci} 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_cistatic unsigned int udf_count_free_table(struct super_block *sb, 24758c2ecf20Sopenharmony_ci struct inode *table) 24768c2ecf20Sopenharmony_ci{ 24778c2ecf20Sopenharmony_ci unsigned int accum = 0; 24788c2ecf20Sopenharmony_ci uint32_t elen; 24798c2ecf20Sopenharmony_ci struct kernel_lb_addr eloc; 24808c2ecf20Sopenharmony_ci int8_t etype; 24818c2ecf20Sopenharmony_ci struct extent_position epos; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci mutex_lock(&UDF_SB(sb)->s_alloc_mutex); 24848c2ecf20Sopenharmony_ci epos.block = UDF_I(table)->i_location; 24858c2ecf20Sopenharmony_ci epos.offset = sizeof(struct unallocSpaceEntry); 24868c2ecf20Sopenharmony_ci epos.bh = NULL; 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) 24898c2ecf20Sopenharmony_ci accum += (elen >> table->i_sb->s_blocksize_bits); 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ci brelse(epos.bh); 24928c2ecf20Sopenharmony_ci mutex_unlock(&UDF_SB(sb)->s_alloc_mutex); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci return accum; 24958c2ecf20Sopenharmony_ci} 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_cistatic unsigned int udf_count_free(struct super_block *sb) 24988c2ecf20Sopenharmony_ci{ 24998c2ecf20Sopenharmony_ci unsigned int accum = 0; 25008c2ecf20Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 25018c2ecf20Sopenharmony_ci struct udf_part_map *map; 25028c2ecf20Sopenharmony_ci unsigned int part = sbi->s_partition; 25038c2ecf20Sopenharmony_ci int ptype = sbi->s_partmaps[part].s_partition_type; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci if (ptype == UDF_METADATA_MAP25) { 25068c2ecf20Sopenharmony_ci part = sbi->s_partmaps[part].s_type_specific.s_metadata. 25078c2ecf20Sopenharmony_ci s_phys_partition_ref; 25088c2ecf20Sopenharmony_ci } else if (ptype == UDF_VIRTUAL_MAP15 || ptype == UDF_VIRTUAL_MAP20) { 25098c2ecf20Sopenharmony_ci /* 25108c2ecf20Sopenharmony_ci * Filesystems with VAT are append-only and we cannot write to 25118c2ecf20Sopenharmony_ci * them. Let's just report 0 here. 25128c2ecf20Sopenharmony_ci */ 25138c2ecf20Sopenharmony_ci return 0; 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci if (sbi->s_lvid_bh) { 25178c2ecf20Sopenharmony_ci struct logicalVolIntegrityDesc *lvid = 25188c2ecf20Sopenharmony_ci (struct logicalVolIntegrityDesc *) 25198c2ecf20Sopenharmony_ci sbi->s_lvid_bh->b_data; 25208c2ecf20Sopenharmony_ci if (le32_to_cpu(lvid->numOfPartitions) > part) { 25218c2ecf20Sopenharmony_ci accum = le32_to_cpu( 25228c2ecf20Sopenharmony_ci lvid->freeSpaceTable[part]); 25238c2ecf20Sopenharmony_ci if (accum == 0xFFFFFFFF) 25248c2ecf20Sopenharmony_ci accum = 0; 25258c2ecf20Sopenharmony_ci } 25268c2ecf20Sopenharmony_ci } 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (accum) 25298c2ecf20Sopenharmony_ci return accum; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci map = &sbi->s_partmaps[part]; 25328c2ecf20Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) { 25338c2ecf20Sopenharmony_ci accum += udf_count_free_bitmap(sb, 25348c2ecf20Sopenharmony_ci map->s_uspace.s_bitmap); 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci if (accum) 25378c2ecf20Sopenharmony_ci return accum; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) { 25408c2ecf20Sopenharmony_ci accum += udf_count_free_table(sb, 25418c2ecf20Sopenharmony_ci map->s_uspace.s_table); 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci return accum; 25448c2ecf20Sopenharmony_ci} 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ben Fennema"); 25478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Universal Disk Format Filesystem"); 25488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 25498c2ecf20Sopenharmony_cimodule_init(init_udf_fs) 25508c2ecf20Sopenharmony_cimodule_exit(exit_udf_fs) 2551