162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * super.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * PURPOSE 662306a36Sopenharmony_ci * Super block routines for the OSTA-UDF(tm) filesystem. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * DESCRIPTION 962306a36Sopenharmony_ci * OSTA-UDF(tm) = Optical Storage Technology Association 1062306a36Sopenharmony_ci * Universal Disk Format. 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * This code is based on version 2.00 of the UDF specification, 1362306a36Sopenharmony_ci * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. 1462306a36Sopenharmony_ci * http://www.osta.org/ 1562306a36Sopenharmony_ci * https://www.ecma.ch/ 1662306a36Sopenharmony_ci * https://www.iso.org/ 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * COPYRIGHT 1962306a36Sopenharmony_ci * (C) 1998 Dave Boynton 2062306a36Sopenharmony_ci * (C) 1998-2004 Ben Fennema 2162306a36Sopenharmony_ci * (C) 2000 Stelias Computing Inc 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * HISTORY 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * 09/24/98 dgb changed to allow compiling outside of kernel, and 2662306a36Sopenharmony_ci * added some debugging. 2762306a36Sopenharmony_ci * 10/01/98 dgb updated to allow (some) possibility of compiling w/2.0.34 2862306a36Sopenharmony_ci * 10/16/98 attempting some multi-session support 2962306a36Sopenharmony_ci * 10/17/98 added freespace count for "df" 3062306a36Sopenharmony_ci * 11/11/98 gr added novrs option 3162306a36Sopenharmony_ci * 11/26/98 dgb added fileset,anchor mount options 3262306a36Sopenharmony_ci * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced 3362306a36Sopenharmony_ci * vol descs. rewrote option handling based on isofs 3462306a36Sopenharmony_ci * 12/20/98 find the free space bitmap (if it exists) 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "udfdecl.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <linux/blkdev.h> 4062306a36Sopenharmony_ci#include <linux/slab.h> 4162306a36Sopenharmony_ci#include <linux/kernel.h> 4262306a36Sopenharmony_ci#include <linux/module.h> 4362306a36Sopenharmony_ci#include <linux/parser.h> 4462306a36Sopenharmony_ci#include <linux/stat.h> 4562306a36Sopenharmony_ci#include <linux/cdrom.h> 4662306a36Sopenharmony_ci#include <linux/nls.h> 4762306a36Sopenharmony_ci#include <linux/vfs.h> 4862306a36Sopenharmony_ci#include <linux/vmalloc.h> 4962306a36Sopenharmony_ci#include <linux/errno.h> 5062306a36Sopenharmony_ci#include <linux/mount.h> 5162306a36Sopenharmony_ci#include <linux/seq_file.h> 5262306a36Sopenharmony_ci#include <linux/bitmap.h> 5362306a36Sopenharmony_ci#include <linux/crc-itu-t.h> 5462306a36Sopenharmony_ci#include <linux/log2.h> 5562306a36Sopenharmony_ci#include <asm/byteorder.h> 5662306a36Sopenharmony_ci#include <linux/iversion.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include "udf_sb.h" 5962306a36Sopenharmony_ci#include "udf_i.h" 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#include <linux/init.h> 6262306a36Sopenharmony_ci#include <linux/uaccess.h> 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cienum { 6562306a36Sopenharmony_ci VDS_POS_PRIMARY_VOL_DESC, 6662306a36Sopenharmony_ci VDS_POS_UNALLOC_SPACE_DESC, 6762306a36Sopenharmony_ci VDS_POS_LOGICAL_VOL_DESC, 6862306a36Sopenharmony_ci VDS_POS_IMP_USE_VOL_DESC, 6962306a36Sopenharmony_ci VDS_POS_LENGTH 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define VSD_FIRST_SECTOR_OFFSET 32768 7362306a36Sopenharmony_ci#define VSD_MAX_SECTOR_OFFSET 0x800000 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Maximum number of Terminating Descriptor / Logical Volume Integrity 7762306a36Sopenharmony_ci * Descriptor redirections. The chosen numbers are arbitrary - just that we 7862306a36Sopenharmony_ci * hopefully don't limit any real use of rewritten inode on write-once media 7962306a36Sopenharmony_ci * but avoid looping for too long on corrupted media. 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_ci#define UDF_MAX_TD_NESTING 64 8262306a36Sopenharmony_ci#define UDF_MAX_LVID_NESTING 1000 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cienum { UDF_MAX_LINKS = 0xffff }; 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * We limit filesize to 4TB. This is arbitrary as the on-disk format supports 8762306a36Sopenharmony_ci * more but because the file space is described by a linked list of extents, 8862306a36Sopenharmony_ci * each of which can have at most 1GB, the creation and handling of extents 8962306a36Sopenharmony_ci * gets unusably slow beyond certain point... 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_ci#define UDF_MAX_FILESIZE (1ULL << 42) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* These are the "meat" - everything else is stuffing */ 9462306a36Sopenharmony_cistatic int udf_fill_super(struct super_block *, void *, int); 9562306a36Sopenharmony_cistatic void udf_put_super(struct super_block *); 9662306a36Sopenharmony_cistatic int udf_sync_fs(struct super_block *, int); 9762306a36Sopenharmony_cistatic int udf_remount_fs(struct super_block *, int *, char *); 9862306a36Sopenharmony_cistatic void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad); 9962306a36Sopenharmony_cistatic void udf_open_lvid(struct super_block *); 10062306a36Sopenharmony_cistatic void udf_close_lvid(struct super_block *); 10162306a36Sopenharmony_cistatic unsigned int udf_count_free(struct super_block *); 10262306a36Sopenharmony_cistatic int udf_statfs(struct dentry *, struct kstatfs *); 10362306a36Sopenharmony_cistatic int udf_show_options(struct seq_file *, struct dentry *); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 10862306a36Sopenharmony_ci unsigned int partnum; 10962306a36Sopenharmony_ci unsigned int offset; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!UDF_SB(sb)->s_lvid_bh) 11262306a36Sopenharmony_ci return NULL; 11362306a36Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data; 11462306a36Sopenharmony_ci partnum = le32_to_cpu(lvid->numOfPartitions); 11562306a36Sopenharmony_ci /* The offset is to skip freeSpaceTable and sizeTable arrays */ 11662306a36Sopenharmony_ci offset = partnum * 2 * sizeof(uint32_t); 11762306a36Sopenharmony_ci return (struct logicalVolIntegrityDescImpUse *) 11862306a36Sopenharmony_ci (((uint8_t *)(lvid + 1)) + offset); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci/* UDF filesystem type */ 12262306a36Sopenharmony_cistatic struct dentry *udf_mount(struct file_system_type *fs_type, 12362306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, udf_fill_super); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic struct file_system_type udf_fstype = { 12962306a36Sopenharmony_ci .owner = THIS_MODULE, 13062306a36Sopenharmony_ci .name = "udf", 13162306a36Sopenharmony_ci .mount = udf_mount, 13262306a36Sopenharmony_ci .kill_sb = kill_block_super, 13362306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ciMODULE_ALIAS_FS("udf"); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_cistatic struct kmem_cache *udf_inode_cachep; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic struct inode *udf_alloc_inode(struct super_block *sb) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci struct udf_inode_info *ei; 14262306a36Sopenharmony_ci ei = alloc_inode_sb(sb, udf_inode_cachep, GFP_KERNEL); 14362306a36Sopenharmony_ci if (!ei) 14462306a36Sopenharmony_ci return NULL; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ei->i_unique = 0; 14762306a36Sopenharmony_ci ei->i_lenExtents = 0; 14862306a36Sopenharmony_ci ei->i_lenStreams = 0; 14962306a36Sopenharmony_ci ei->i_next_alloc_block = 0; 15062306a36Sopenharmony_ci ei->i_next_alloc_goal = 0; 15162306a36Sopenharmony_ci ei->i_strat4096 = 0; 15262306a36Sopenharmony_ci ei->i_streamdir = 0; 15362306a36Sopenharmony_ci ei->i_hidden = 0; 15462306a36Sopenharmony_ci init_rwsem(&ei->i_data_sem); 15562306a36Sopenharmony_ci ei->cached_extent.lstart = -1; 15662306a36Sopenharmony_ci spin_lock_init(&ei->i_extent_cache_lock); 15762306a36Sopenharmony_ci inode_set_iversion(&ei->vfs_inode, 1); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return &ei->vfs_inode; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void udf_free_in_core_inode(struct inode *inode) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci kmem_cache_free(udf_inode_cachep, UDF_I(inode)); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void init_once(void *foo) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct udf_inode_info *ei = foo; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci ei->i_data = NULL; 17262306a36Sopenharmony_ci inode_init_once(&ei->vfs_inode); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int __init init_inodecache(void) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci udf_inode_cachep = kmem_cache_create("udf_inode_cache", 17862306a36Sopenharmony_ci sizeof(struct udf_inode_info), 17962306a36Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT | 18062306a36Sopenharmony_ci SLAB_MEM_SPREAD | 18162306a36Sopenharmony_ci SLAB_ACCOUNT), 18262306a36Sopenharmony_ci init_once); 18362306a36Sopenharmony_ci if (!udf_inode_cachep) 18462306a36Sopenharmony_ci return -ENOMEM; 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic void destroy_inodecache(void) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci /* 19162306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 19262306a36Sopenharmony_ci * destroy cache. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci rcu_barrier(); 19562306a36Sopenharmony_ci kmem_cache_destroy(udf_inode_cachep); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci/* Superblock operations */ 19962306a36Sopenharmony_cistatic const struct super_operations udf_sb_ops = { 20062306a36Sopenharmony_ci .alloc_inode = udf_alloc_inode, 20162306a36Sopenharmony_ci .free_inode = udf_free_in_core_inode, 20262306a36Sopenharmony_ci .write_inode = udf_write_inode, 20362306a36Sopenharmony_ci .evict_inode = udf_evict_inode, 20462306a36Sopenharmony_ci .put_super = udf_put_super, 20562306a36Sopenharmony_ci .sync_fs = udf_sync_fs, 20662306a36Sopenharmony_ci .statfs = udf_statfs, 20762306a36Sopenharmony_ci .remount_fs = udf_remount_fs, 20862306a36Sopenharmony_ci .show_options = udf_show_options, 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistruct udf_options { 21262306a36Sopenharmony_ci unsigned char novrs; 21362306a36Sopenharmony_ci unsigned int blocksize; 21462306a36Sopenharmony_ci unsigned int session; 21562306a36Sopenharmony_ci unsigned int lastblock; 21662306a36Sopenharmony_ci unsigned int anchor; 21762306a36Sopenharmony_ci unsigned int flags; 21862306a36Sopenharmony_ci umode_t umask; 21962306a36Sopenharmony_ci kgid_t gid; 22062306a36Sopenharmony_ci kuid_t uid; 22162306a36Sopenharmony_ci umode_t fmode; 22262306a36Sopenharmony_ci umode_t dmode; 22362306a36Sopenharmony_ci struct nls_table *nls_map; 22462306a36Sopenharmony_ci}; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int __init init_udf_fs(void) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int err; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci err = init_inodecache(); 23162306a36Sopenharmony_ci if (err) 23262306a36Sopenharmony_ci goto out1; 23362306a36Sopenharmony_ci err = register_filesystem(&udf_fstype); 23462306a36Sopenharmony_ci if (err) 23562306a36Sopenharmony_ci goto out; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci return 0; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciout: 24062306a36Sopenharmony_ci destroy_inodecache(); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciout1: 24362306a36Sopenharmony_ci return err; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic void __exit exit_udf_fs(void) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci unregister_filesystem(&udf_fstype); 24962306a36Sopenharmony_ci destroy_inodecache(); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci sbi->s_partmaps = kcalloc(count, sizeof(*sbi->s_partmaps), GFP_KERNEL); 25762306a36Sopenharmony_ci if (!sbi->s_partmaps) { 25862306a36Sopenharmony_ci sbi->s_partitions = 0; 25962306a36Sopenharmony_ci return -ENOMEM; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci sbi->s_partitions = count; 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic void udf_sb_free_bitmap(struct udf_bitmap *bitmap) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci int i; 26962306a36Sopenharmony_ci int nr_groups = bitmap->s_nr_groups; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci for (i = 0; i < nr_groups; i++) 27262306a36Sopenharmony_ci brelse(bitmap->s_block_bitmap[i]); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci kvfree(bitmap); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void udf_free_partition(struct udf_part_map *map) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci int i; 28062306a36Sopenharmony_ci struct udf_meta_data *mdata; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) 28362306a36Sopenharmony_ci iput(map->s_uspace.s_table); 28462306a36Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) 28562306a36Sopenharmony_ci udf_sb_free_bitmap(map->s_uspace.s_bitmap); 28662306a36Sopenharmony_ci if (map->s_partition_type == UDF_SPARABLE_MAP15) 28762306a36Sopenharmony_ci for (i = 0; i < 4; i++) 28862306a36Sopenharmony_ci brelse(map->s_type_specific.s_sparing.s_spar_map[i]); 28962306a36Sopenharmony_ci else if (map->s_partition_type == UDF_METADATA_MAP25) { 29062306a36Sopenharmony_ci mdata = &map->s_type_specific.s_metadata; 29162306a36Sopenharmony_ci iput(mdata->s_metadata_fe); 29262306a36Sopenharmony_ci mdata->s_metadata_fe = NULL; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci iput(mdata->s_mirror_fe); 29562306a36Sopenharmony_ci mdata->s_mirror_fe = NULL; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci iput(mdata->s_bitmap_fe); 29862306a36Sopenharmony_ci mdata->s_bitmap_fe = NULL; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic void udf_sb_free_partitions(struct super_block *sb) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 30562306a36Sopenharmony_ci int i; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (!sbi->s_partmaps) 30862306a36Sopenharmony_ci return; 30962306a36Sopenharmony_ci for (i = 0; i < sbi->s_partitions; i++) 31062306a36Sopenharmony_ci udf_free_partition(&sbi->s_partmaps[i]); 31162306a36Sopenharmony_ci kfree(sbi->s_partmaps); 31262306a36Sopenharmony_ci sbi->s_partmaps = NULL; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int udf_show_options(struct seq_file *seq, struct dentry *root) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct super_block *sb = root->d_sb; 31862306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) 32162306a36Sopenharmony_ci seq_puts(seq, ",nostrict"); 32262306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET)) 32362306a36Sopenharmony_ci seq_printf(seq, ",bs=%lu", sb->s_blocksize); 32462306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) 32562306a36Sopenharmony_ci seq_puts(seq, ",unhide"); 32662306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) 32762306a36Sopenharmony_ci seq_puts(seq, ",undelete"); 32862306a36Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_USE_AD_IN_ICB)) 32962306a36Sopenharmony_ci seq_puts(seq, ",noadinicb"); 33062306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_USE_SHORT_AD)) 33162306a36Sopenharmony_ci seq_puts(seq, ",shortad"); 33262306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET)) 33362306a36Sopenharmony_ci seq_puts(seq, ",uid=forget"); 33462306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET)) 33562306a36Sopenharmony_ci seq_puts(seq, ",gid=forget"); 33662306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET)) 33762306a36Sopenharmony_ci seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid)); 33862306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET)) 33962306a36Sopenharmony_ci seq_printf(seq, ",gid=%u", from_kgid(&init_user_ns, sbi->s_gid)); 34062306a36Sopenharmony_ci if (sbi->s_umask != 0) 34162306a36Sopenharmony_ci seq_printf(seq, ",umask=%ho", sbi->s_umask); 34262306a36Sopenharmony_ci if (sbi->s_fmode != UDF_INVALID_MODE) 34362306a36Sopenharmony_ci seq_printf(seq, ",mode=%ho", sbi->s_fmode); 34462306a36Sopenharmony_ci if (sbi->s_dmode != UDF_INVALID_MODE) 34562306a36Sopenharmony_ci seq_printf(seq, ",dmode=%ho", sbi->s_dmode); 34662306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET)) 34762306a36Sopenharmony_ci seq_printf(seq, ",session=%d", sbi->s_session); 34862306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET)) 34962306a36Sopenharmony_ci seq_printf(seq, ",lastblock=%u", sbi->s_last_block); 35062306a36Sopenharmony_ci if (sbi->s_anchor != 0) 35162306a36Sopenharmony_ci seq_printf(seq, ",anchor=%u", sbi->s_anchor); 35262306a36Sopenharmony_ci if (sbi->s_nls_map) 35362306a36Sopenharmony_ci seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset); 35462306a36Sopenharmony_ci else 35562306a36Sopenharmony_ci seq_puts(seq, ",iocharset=utf8"); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* 36162306a36Sopenharmony_ci * udf_parse_options 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * PURPOSE 36462306a36Sopenharmony_ci * Parse mount options. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * DESCRIPTION 36762306a36Sopenharmony_ci * The following mount options are supported: 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * gid= Set the default group. 37062306a36Sopenharmony_ci * umask= Set the default umask. 37162306a36Sopenharmony_ci * mode= Set the default file permissions. 37262306a36Sopenharmony_ci * dmode= Set the default directory permissions. 37362306a36Sopenharmony_ci * uid= Set the default user. 37462306a36Sopenharmony_ci * bs= Set the block size. 37562306a36Sopenharmony_ci * unhide Show otherwise hidden files. 37662306a36Sopenharmony_ci * undelete Show deleted files in lists. 37762306a36Sopenharmony_ci * adinicb Embed data in the inode (default) 37862306a36Sopenharmony_ci * noadinicb Don't embed data in the inode 37962306a36Sopenharmony_ci * shortad Use short ad's 38062306a36Sopenharmony_ci * longad Use long ad's (default) 38162306a36Sopenharmony_ci * nostrict Unset strict conformance 38262306a36Sopenharmony_ci * iocharset= Set the NLS character set 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * The remaining are for debugging and disaster recovery: 38562306a36Sopenharmony_ci * 38662306a36Sopenharmony_ci * novrs Skip volume sequence recognition 38762306a36Sopenharmony_ci * 38862306a36Sopenharmony_ci * The following expect a offset from 0. 38962306a36Sopenharmony_ci * 39062306a36Sopenharmony_ci * session= Set the CDROM session (default= last session) 39162306a36Sopenharmony_ci * anchor= Override standard anchor location. (default= 256) 39262306a36Sopenharmony_ci * volume= Override the VolumeDesc location. (unused) 39362306a36Sopenharmony_ci * partition= Override the PartitionDesc location. (unused) 39462306a36Sopenharmony_ci * lastblock= Set the last block of the filesystem/ 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * The following expect a offset from the partition root. 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * fileset= Override the fileset block location. (unused) 39962306a36Sopenharmony_ci * rootdir= Override the root directory location. (unused) 40062306a36Sopenharmony_ci * WARNING: overriding the rootdir to a non-directory may 40162306a36Sopenharmony_ci * yield highly unpredictable results. 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * PRE-CONDITIONS 40462306a36Sopenharmony_ci * options Pointer to mount options string. 40562306a36Sopenharmony_ci * uopts Pointer to mount options variable. 40662306a36Sopenharmony_ci * 40762306a36Sopenharmony_ci * POST-CONDITIONS 40862306a36Sopenharmony_ci * <return> 1 Mount options parsed okay. 40962306a36Sopenharmony_ci * <return> 0 Error parsing mount options. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * HISTORY 41262306a36Sopenharmony_ci * July 1, 1997 - Andrew E. Mileski 41362306a36Sopenharmony_ci * Written, tested, and released. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cienum { 41762306a36Sopenharmony_ci Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete, 41862306a36Sopenharmony_ci Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad, 41962306a36Sopenharmony_ci Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock, 42062306a36Sopenharmony_ci Opt_anchor, Opt_volume, Opt_partition, Opt_fileset, 42162306a36Sopenharmony_ci Opt_rootdir, Opt_utf8, Opt_iocharset, 42262306a36Sopenharmony_ci Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore, 42362306a36Sopenharmony_ci Opt_fmode, Opt_dmode 42462306a36Sopenharmony_ci}; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic const match_table_t tokens = { 42762306a36Sopenharmony_ci {Opt_novrs, "novrs"}, 42862306a36Sopenharmony_ci {Opt_nostrict, "nostrict"}, 42962306a36Sopenharmony_ci {Opt_bs, "bs=%u"}, 43062306a36Sopenharmony_ci {Opt_unhide, "unhide"}, 43162306a36Sopenharmony_ci {Opt_undelete, "undelete"}, 43262306a36Sopenharmony_ci {Opt_noadinicb, "noadinicb"}, 43362306a36Sopenharmony_ci {Opt_adinicb, "adinicb"}, 43462306a36Sopenharmony_ci {Opt_shortad, "shortad"}, 43562306a36Sopenharmony_ci {Opt_longad, "longad"}, 43662306a36Sopenharmony_ci {Opt_uforget, "uid=forget"}, 43762306a36Sopenharmony_ci {Opt_uignore, "uid=ignore"}, 43862306a36Sopenharmony_ci {Opt_gforget, "gid=forget"}, 43962306a36Sopenharmony_ci {Opt_gignore, "gid=ignore"}, 44062306a36Sopenharmony_ci {Opt_gid, "gid=%u"}, 44162306a36Sopenharmony_ci {Opt_uid, "uid=%u"}, 44262306a36Sopenharmony_ci {Opt_umask, "umask=%o"}, 44362306a36Sopenharmony_ci {Opt_session, "session=%u"}, 44462306a36Sopenharmony_ci {Opt_lastblock, "lastblock=%u"}, 44562306a36Sopenharmony_ci {Opt_anchor, "anchor=%u"}, 44662306a36Sopenharmony_ci {Opt_volume, "volume=%u"}, 44762306a36Sopenharmony_ci {Opt_partition, "partition=%u"}, 44862306a36Sopenharmony_ci {Opt_fileset, "fileset=%u"}, 44962306a36Sopenharmony_ci {Opt_rootdir, "rootdir=%u"}, 45062306a36Sopenharmony_ci {Opt_utf8, "utf8"}, 45162306a36Sopenharmony_ci {Opt_iocharset, "iocharset=%s"}, 45262306a36Sopenharmony_ci {Opt_fmode, "mode=%o"}, 45362306a36Sopenharmony_ci {Opt_dmode, "dmode=%o"}, 45462306a36Sopenharmony_ci {Opt_err, NULL} 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int udf_parse_options(char *options, struct udf_options *uopt, 45862306a36Sopenharmony_ci bool remount) 45962306a36Sopenharmony_ci{ 46062306a36Sopenharmony_ci char *p; 46162306a36Sopenharmony_ci int option; 46262306a36Sopenharmony_ci unsigned int uv; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci uopt->novrs = 0; 46562306a36Sopenharmony_ci uopt->session = 0xFFFFFFFF; 46662306a36Sopenharmony_ci uopt->lastblock = 0; 46762306a36Sopenharmony_ci uopt->anchor = 0; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!options) 47062306a36Sopenharmony_ci return 1; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 47362306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 47462306a36Sopenharmony_ci int token; 47562306a36Sopenharmony_ci unsigned n; 47662306a36Sopenharmony_ci if (!*p) 47762306a36Sopenharmony_ci continue; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci token = match_token(p, tokens, args); 48062306a36Sopenharmony_ci switch (token) { 48162306a36Sopenharmony_ci case Opt_novrs: 48262306a36Sopenharmony_ci uopt->novrs = 1; 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case Opt_bs: 48562306a36Sopenharmony_ci if (match_int(&args[0], &option)) 48662306a36Sopenharmony_ci return 0; 48762306a36Sopenharmony_ci n = option; 48862306a36Sopenharmony_ci if (n != 512 && n != 1024 && n != 2048 && n != 4096) 48962306a36Sopenharmony_ci return 0; 49062306a36Sopenharmony_ci uopt->blocksize = n; 49162306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET); 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case Opt_unhide: 49462306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UNHIDE); 49562306a36Sopenharmony_ci break; 49662306a36Sopenharmony_ci case Opt_undelete: 49762306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UNDELETE); 49862306a36Sopenharmony_ci break; 49962306a36Sopenharmony_ci case Opt_noadinicb: 50062306a36Sopenharmony_ci uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB); 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci case Opt_adinicb: 50362306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB); 50462306a36Sopenharmony_ci break; 50562306a36Sopenharmony_ci case Opt_shortad: 50662306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD); 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci case Opt_longad: 50962306a36Sopenharmony_ci uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci case Opt_gid: 51262306a36Sopenharmony_ci if (match_uint(args, &uv)) 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci uopt->gid = make_kgid(current_user_ns(), uv); 51562306a36Sopenharmony_ci if (!gid_valid(uopt->gid)) 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_GID_SET); 51862306a36Sopenharmony_ci break; 51962306a36Sopenharmony_ci case Opt_uid: 52062306a36Sopenharmony_ci if (match_uint(args, &uv)) 52162306a36Sopenharmony_ci return 0; 52262306a36Sopenharmony_ci uopt->uid = make_kuid(current_user_ns(), uv); 52362306a36Sopenharmony_ci if (!uid_valid(uopt->uid)) 52462306a36Sopenharmony_ci return 0; 52562306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UID_SET); 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci case Opt_umask: 52862306a36Sopenharmony_ci if (match_octal(args, &option)) 52962306a36Sopenharmony_ci return 0; 53062306a36Sopenharmony_ci uopt->umask = option; 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case Opt_nostrict: 53362306a36Sopenharmony_ci uopt->flags &= ~(1 << UDF_FLAG_STRICT); 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci case Opt_session: 53662306a36Sopenharmony_ci if (match_int(args, &option)) 53762306a36Sopenharmony_ci return 0; 53862306a36Sopenharmony_ci uopt->session = option; 53962306a36Sopenharmony_ci if (!remount) 54062306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_SESSION_SET); 54162306a36Sopenharmony_ci break; 54262306a36Sopenharmony_ci case Opt_lastblock: 54362306a36Sopenharmony_ci if (match_int(args, &option)) 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci uopt->lastblock = option; 54662306a36Sopenharmony_ci if (!remount) 54762306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET); 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case Opt_anchor: 55062306a36Sopenharmony_ci if (match_int(args, &option)) 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci uopt->anchor = option; 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci case Opt_volume: 55562306a36Sopenharmony_ci case Opt_partition: 55662306a36Sopenharmony_ci case Opt_fileset: 55762306a36Sopenharmony_ci case Opt_rootdir: 55862306a36Sopenharmony_ci /* Ignored (never implemented properly) */ 55962306a36Sopenharmony_ci break; 56062306a36Sopenharmony_ci case Opt_utf8: 56162306a36Sopenharmony_ci if (!remount) { 56262306a36Sopenharmony_ci unload_nls(uopt->nls_map); 56362306a36Sopenharmony_ci uopt->nls_map = NULL; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci break; 56662306a36Sopenharmony_ci case Opt_iocharset: 56762306a36Sopenharmony_ci if (!remount) { 56862306a36Sopenharmony_ci unload_nls(uopt->nls_map); 56962306a36Sopenharmony_ci uopt->nls_map = NULL; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci /* When nls_map is not loaded then UTF-8 is used */ 57262306a36Sopenharmony_ci if (!remount && strcmp(args[0].from, "utf8") != 0) { 57362306a36Sopenharmony_ci uopt->nls_map = load_nls(args[0].from); 57462306a36Sopenharmony_ci if (!uopt->nls_map) { 57562306a36Sopenharmony_ci pr_err("iocharset %s not found\n", 57662306a36Sopenharmony_ci args[0].from); 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci case Opt_uforget: 58262306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_UID_FORGET); 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case Opt_uignore: 58562306a36Sopenharmony_ci case Opt_gignore: 58662306a36Sopenharmony_ci /* These options are superseeded by uid=<number> */ 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci case Opt_gforget: 58962306a36Sopenharmony_ci uopt->flags |= (1 << UDF_FLAG_GID_FORGET); 59062306a36Sopenharmony_ci break; 59162306a36Sopenharmony_ci case Opt_fmode: 59262306a36Sopenharmony_ci if (match_octal(args, &option)) 59362306a36Sopenharmony_ci return 0; 59462306a36Sopenharmony_ci uopt->fmode = option & 0777; 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci case Opt_dmode: 59762306a36Sopenharmony_ci if (match_octal(args, &option)) 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci uopt->dmode = option & 0777; 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci default: 60262306a36Sopenharmony_ci pr_err("bad mount option \"%s\" or missing value\n", p); 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci return 1; 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic int udf_remount_fs(struct super_block *sb, int *flags, char *options) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct udf_options uopt; 61262306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 61362306a36Sopenharmony_ci int error = 0; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (!(*flags & SB_RDONLY) && UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT)) 61662306a36Sopenharmony_ci return -EACCES; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci sync_filesystem(sb); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci uopt.flags = sbi->s_flags; 62162306a36Sopenharmony_ci uopt.uid = sbi->s_uid; 62262306a36Sopenharmony_ci uopt.gid = sbi->s_gid; 62362306a36Sopenharmony_ci uopt.umask = sbi->s_umask; 62462306a36Sopenharmony_ci uopt.fmode = sbi->s_fmode; 62562306a36Sopenharmony_ci uopt.dmode = sbi->s_dmode; 62662306a36Sopenharmony_ci uopt.nls_map = NULL; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (!udf_parse_options(options, &uopt, true)) 62962306a36Sopenharmony_ci return -EINVAL; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci write_lock(&sbi->s_cred_lock); 63262306a36Sopenharmony_ci sbi->s_flags = uopt.flags; 63362306a36Sopenharmony_ci sbi->s_uid = uopt.uid; 63462306a36Sopenharmony_ci sbi->s_gid = uopt.gid; 63562306a36Sopenharmony_ci sbi->s_umask = uopt.umask; 63662306a36Sopenharmony_ci sbi->s_fmode = uopt.fmode; 63762306a36Sopenharmony_ci sbi->s_dmode = uopt.dmode; 63862306a36Sopenharmony_ci write_unlock(&sbi->s_cred_lock); 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if ((bool)(*flags & SB_RDONLY) == sb_rdonly(sb)) 64162306a36Sopenharmony_ci goto out_unlock; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (*flags & SB_RDONLY) 64462306a36Sopenharmony_ci udf_close_lvid(sb); 64562306a36Sopenharmony_ci else 64662306a36Sopenharmony_ci udf_open_lvid(sb); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ciout_unlock: 64962306a36Sopenharmony_ci return error; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci/* 65362306a36Sopenharmony_ci * Check VSD descriptor. Returns -1 in case we are at the end of volume 65462306a36Sopenharmony_ci * recognition area, 0 if the descriptor is valid but non-interesting, 1 if 65562306a36Sopenharmony_ci * we found one of NSR descriptors we are looking for. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_cistatic int identify_vsd(const struct volStructDesc *vsd) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci int ret = 0; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci if (!memcmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) { 66262306a36Sopenharmony_ci switch (vsd->structType) { 66362306a36Sopenharmony_ci case 0: 66462306a36Sopenharmony_ci udf_debug("ISO9660 Boot Record found\n"); 66562306a36Sopenharmony_ci break; 66662306a36Sopenharmony_ci case 1: 66762306a36Sopenharmony_ci udf_debug("ISO9660 Primary Volume Descriptor found\n"); 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci case 2: 67062306a36Sopenharmony_ci udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); 67162306a36Sopenharmony_ci break; 67262306a36Sopenharmony_ci case 3: 67362306a36Sopenharmony_ci udf_debug("ISO9660 Volume Partition Descriptor found\n"); 67462306a36Sopenharmony_ci break; 67562306a36Sopenharmony_ci case 255: 67662306a36Sopenharmony_ci udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); 67762306a36Sopenharmony_ci break; 67862306a36Sopenharmony_ci default: 67962306a36Sopenharmony_ci udf_debug("ISO9660 VRS (%u) found\n", vsd->structType); 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci } else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) 68362306a36Sopenharmony_ci ; /* ret = 0 */ 68462306a36Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) 68562306a36Sopenharmony_ci ret = 1; 68662306a36Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) 68762306a36Sopenharmony_ci ret = 1; 68862306a36Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BOOT2, VSD_STD_ID_LEN)) 68962306a36Sopenharmony_ci ; /* ret = 0 */ 69062306a36Sopenharmony_ci else if (!memcmp(vsd->stdIdent, VSD_STD_ID_CDW02, VSD_STD_ID_LEN)) 69162306a36Sopenharmony_ci ; /* ret = 0 */ 69262306a36Sopenharmony_ci else { 69362306a36Sopenharmony_ci /* TEA01 or invalid id : end of volume recognition area */ 69462306a36Sopenharmony_ci ret = -1; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci return ret; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci/* 70162306a36Sopenharmony_ci * Check Volume Structure Descriptors (ECMA 167 2/9.1) 70262306a36Sopenharmony_ci * We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) 70362306a36Sopenharmony_ci * @return 1 if NSR02 or NSR03 found, 70462306a36Sopenharmony_ci * -1 if first sector read error, 0 otherwise 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_cistatic int udf_check_vsd(struct super_block *sb) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct volStructDesc *vsd = NULL; 70962306a36Sopenharmony_ci loff_t sector = VSD_FIRST_SECTOR_OFFSET; 71062306a36Sopenharmony_ci int sectorsize; 71162306a36Sopenharmony_ci struct buffer_head *bh = NULL; 71262306a36Sopenharmony_ci int nsr = 0; 71362306a36Sopenharmony_ci struct udf_sb_info *sbi; 71462306a36Sopenharmony_ci loff_t session_offset; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci sbi = UDF_SB(sb); 71762306a36Sopenharmony_ci if (sb->s_blocksize < sizeof(struct volStructDesc)) 71862306a36Sopenharmony_ci sectorsize = sizeof(struct volStructDesc); 71962306a36Sopenharmony_ci else 72062306a36Sopenharmony_ci sectorsize = sb->s_blocksize; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci session_offset = (loff_t)sbi->s_session << sb->s_blocksize_bits; 72362306a36Sopenharmony_ci sector += session_offset; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci udf_debug("Starting at sector %u (%lu byte sectors)\n", 72662306a36Sopenharmony_ci (unsigned int)(sector >> sb->s_blocksize_bits), 72762306a36Sopenharmony_ci sb->s_blocksize); 72862306a36Sopenharmony_ci /* Process the sequence (if applicable). The hard limit on the sector 72962306a36Sopenharmony_ci * offset is arbitrary, hopefully large enough so that all valid UDF 73062306a36Sopenharmony_ci * filesystems will be recognised. There is no mention of an upper 73162306a36Sopenharmony_ci * bound to the size of the volume recognition area in the standard. 73262306a36Sopenharmony_ci * The limit will prevent the code to read all the sectors of a 73362306a36Sopenharmony_ci * specially crafted image (like a bluray disc full of CD001 sectors), 73462306a36Sopenharmony_ci * potentially causing minutes or even hours of uninterruptible I/O 73562306a36Sopenharmony_ci * activity. This actually happened with uninitialised SSD partitions 73662306a36Sopenharmony_ci * (all 0xFF) before the check for the limit and all valid IDs were 73762306a36Sopenharmony_ci * added */ 73862306a36Sopenharmony_ci for (; !nsr && sector < VSD_MAX_SECTOR_OFFSET; sector += sectorsize) { 73962306a36Sopenharmony_ci /* Read a block */ 74062306a36Sopenharmony_ci bh = sb_bread(sb, sector >> sb->s_blocksize_bits); 74162306a36Sopenharmony_ci if (!bh) 74262306a36Sopenharmony_ci break; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci vsd = (struct volStructDesc *)(bh->b_data + 74562306a36Sopenharmony_ci (sector & (sb->s_blocksize - 1))); 74662306a36Sopenharmony_ci nsr = identify_vsd(vsd); 74762306a36Sopenharmony_ci /* Found NSR or end? */ 74862306a36Sopenharmony_ci if (nsr) { 74962306a36Sopenharmony_ci brelse(bh); 75062306a36Sopenharmony_ci break; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci /* 75362306a36Sopenharmony_ci * Special handling for improperly formatted VRS (e.g., Win10) 75462306a36Sopenharmony_ci * where components are separated by 2048 bytes even though 75562306a36Sopenharmony_ci * sectors are 4K 75662306a36Sopenharmony_ci */ 75762306a36Sopenharmony_ci if (sb->s_blocksize == 4096) { 75862306a36Sopenharmony_ci nsr = identify_vsd(vsd + 1); 75962306a36Sopenharmony_ci /* Ignore unknown IDs... */ 76062306a36Sopenharmony_ci if (nsr < 0) 76162306a36Sopenharmony_ci nsr = 0; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci brelse(bh); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (nsr > 0) 76762306a36Sopenharmony_ci return 1; 76862306a36Sopenharmony_ci else if (!bh && sector - session_offset == VSD_FIRST_SECTOR_OFFSET) 76962306a36Sopenharmony_ci return -1; 77062306a36Sopenharmony_ci else 77162306a36Sopenharmony_ci return 0; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int udf_verify_domain_identifier(struct super_block *sb, 77562306a36Sopenharmony_ci struct regid *ident, char *dname) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci struct domainIdentSuffix *suffix; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (memcmp(ident->ident, UDF_ID_COMPLIANT, strlen(UDF_ID_COMPLIANT))) { 78062306a36Sopenharmony_ci udf_warn(sb, "Not OSTA UDF compliant %s descriptor.\n", dname); 78162306a36Sopenharmony_ci goto force_ro; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci if (ident->flags & ENTITYID_FLAGS_DIRTY) { 78462306a36Sopenharmony_ci udf_warn(sb, "Possibly not OSTA UDF compliant %s descriptor.\n", 78562306a36Sopenharmony_ci dname); 78662306a36Sopenharmony_ci goto force_ro; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci suffix = (struct domainIdentSuffix *)ident->identSuffix; 78962306a36Sopenharmony_ci if ((suffix->domainFlags & DOMAIN_FLAGS_HARD_WRITE_PROTECT) || 79062306a36Sopenharmony_ci (suffix->domainFlags & DOMAIN_FLAGS_SOFT_WRITE_PROTECT)) { 79162306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 79262306a36Sopenharmony_ci udf_warn(sb, "Descriptor for %s marked write protected." 79362306a36Sopenharmony_ci " Forcing read only mount.\n", dname); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci goto force_ro; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci return 0; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ciforce_ro: 80062306a36Sopenharmony_ci if (!sb_rdonly(sb)) 80162306a36Sopenharmony_ci return -EACCES; 80262306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int udf_load_fileset(struct super_block *sb, struct fileSetDesc *fset, 80762306a36Sopenharmony_ci struct kernel_lb_addr *root) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci int ret; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci ret = udf_verify_domain_identifier(sb, &fset->domainIdent, "file set"); 81262306a36Sopenharmony_ci if (ret < 0) 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); 81662306a36Sopenharmony_ci UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci udf_debug("Rootdir at block=%u, partition=%u\n", 81962306a36Sopenharmony_ci root->logicalBlockNum, root->partitionReferenceNum); 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic int udf_find_fileset(struct super_block *sb, 82462306a36Sopenharmony_ci struct kernel_lb_addr *fileset, 82562306a36Sopenharmony_ci struct kernel_lb_addr *root) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci struct buffer_head *bh; 82862306a36Sopenharmony_ci uint16_t ident; 82962306a36Sopenharmony_ci int ret; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (fileset->logicalBlockNum == 0xFFFFFFFF && 83262306a36Sopenharmony_ci fileset->partitionReferenceNum == 0xFFFF) 83362306a36Sopenharmony_ci return -EINVAL; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci bh = udf_read_ptagged(sb, fileset, 0, &ident); 83662306a36Sopenharmony_ci if (!bh) 83762306a36Sopenharmony_ci return -EIO; 83862306a36Sopenharmony_ci if (ident != TAG_IDENT_FSD) { 83962306a36Sopenharmony_ci brelse(bh); 84062306a36Sopenharmony_ci return -EINVAL; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci udf_debug("Fileset at block=%u, partition=%u\n", 84462306a36Sopenharmony_ci fileset->logicalBlockNum, fileset->partitionReferenceNum); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci UDF_SB(sb)->s_partition = fileset->partitionReferenceNum; 84762306a36Sopenharmony_ci ret = udf_load_fileset(sb, (struct fileSetDesc *)bh->b_data, root); 84862306a36Sopenharmony_ci brelse(bh); 84962306a36Sopenharmony_ci return ret; 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/* 85362306a36Sopenharmony_ci * Load primary Volume Descriptor Sequence 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence 85662306a36Sopenharmony_ci * should be tried. 85762306a36Sopenharmony_ci */ 85862306a36Sopenharmony_cistatic int udf_load_pvoldesc(struct super_block *sb, sector_t block) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct primaryVolDesc *pvoldesc; 86162306a36Sopenharmony_ci uint8_t *outstr; 86262306a36Sopenharmony_ci struct buffer_head *bh; 86362306a36Sopenharmony_ci uint16_t ident; 86462306a36Sopenharmony_ci int ret; 86562306a36Sopenharmony_ci struct timestamp *ts; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci outstr = kmalloc(128, GFP_NOFS); 86862306a36Sopenharmony_ci if (!outstr) 86962306a36Sopenharmony_ci return -ENOMEM; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 87262306a36Sopenharmony_ci if (!bh) { 87362306a36Sopenharmony_ci ret = -EAGAIN; 87462306a36Sopenharmony_ci goto out2; 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (ident != TAG_IDENT_PVD) { 87862306a36Sopenharmony_ci ret = -EIO; 87962306a36Sopenharmony_ci goto out_bh; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci pvoldesc = (struct primaryVolDesc *)bh->b_data; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, 88562306a36Sopenharmony_ci pvoldesc->recordingDateAndTime); 88662306a36Sopenharmony_ci ts = &pvoldesc->recordingDateAndTime; 88762306a36Sopenharmony_ci udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n", 88862306a36Sopenharmony_ci le16_to_cpu(ts->year), ts->month, ts->day, ts->hour, 88962306a36Sopenharmony_ci ts->minute, le16_to_cpu(ts->typeAndTimezone)); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci ret = udf_dstrCS0toChar(sb, outstr, 31, pvoldesc->volIdent, 32); 89262306a36Sopenharmony_ci if (ret < 0) { 89362306a36Sopenharmony_ci strcpy(UDF_SB(sb)->s_volume_ident, "InvalidName"); 89462306a36Sopenharmony_ci pr_warn("incorrect volume identification, setting to " 89562306a36Sopenharmony_ci "'InvalidName'\n"); 89662306a36Sopenharmony_ci } else { 89762306a36Sopenharmony_ci strncpy(UDF_SB(sb)->s_volume_ident, outstr, ret); 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci udf_debug("volIdent[] = '%s'\n", UDF_SB(sb)->s_volume_ident); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci ret = udf_dstrCS0toChar(sb, outstr, 127, pvoldesc->volSetIdent, 128); 90262306a36Sopenharmony_ci if (ret < 0) { 90362306a36Sopenharmony_ci ret = 0; 90462306a36Sopenharmony_ci goto out_bh; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci outstr[ret] = 0; 90762306a36Sopenharmony_ci udf_debug("volSetIdent[] = '%s'\n", outstr); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ret = 0; 91062306a36Sopenharmony_ciout_bh: 91162306a36Sopenharmony_ci brelse(bh); 91262306a36Sopenharmony_ciout2: 91362306a36Sopenharmony_ci kfree(outstr); 91462306a36Sopenharmony_ci return ret; 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistruct inode *udf_find_metadata_inode_efe(struct super_block *sb, 91862306a36Sopenharmony_ci u32 meta_file_loc, u32 partition_ref) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct kernel_lb_addr addr; 92162306a36Sopenharmony_ci struct inode *metadata_fe; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci addr.logicalBlockNum = meta_file_loc; 92462306a36Sopenharmony_ci addr.partitionReferenceNum = partition_ref; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci metadata_fe = udf_iget_special(sb, &addr); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci if (IS_ERR(metadata_fe)) { 92962306a36Sopenharmony_ci udf_warn(sb, "metadata inode efe not found\n"); 93062306a36Sopenharmony_ci return metadata_fe; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci if (UDF_I(metadata_fe)->i_alloc_type != ICBTAG_FLAG_AD_SHORT) { 93362306a36Sopenharmony_ci udf_warn(sb, "metadata inode efe does not have short allocation descriptors!\n"); 93462306a36Sopenharmony_ci iput(metadata_fe); 93562306a36Sopenharmony_ci return ERR_PTR(-EIO); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return metadata_fe; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic int udf_load_metadata_files(struct super_block *sb, int partition, 94262306a36Sopenharmony_ci int type1_index) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 94562306a36Sopenharmony_ci struct udf_part_map *map; 94662306a36Sopenharmony_ci struct udf_meta_data *mdata; 94762306a36Sopenharmony_ci struct kernel_lb_addr addr; 94862306a36Sopenharmony_ci struct inode *fe; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci map = &sbi->s_partmaps[partition]; 95162306a36Sopenharmony_ci mdata = &map->s_type_specific.s_metadata; 95262306a36Sopenharmony_ci mdata->s_phys_partition_ref = type1_index; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* metadata address */ 95562306a36Sopenharmony_ci udf_debug("Metadata file location: block = %u part = %u\n", 95662306a36Sopenharmony_ci mdata->s_meta_file_loc, mdata->s_phys_partition_ref); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci fe = udf_find_metadata_inode_efe(sb, mdata->s_meta_file_loc, 95962306a36Sopenharmony_ci mdata->s_phys_partition_ref); 96062306a36Sopenharmony_ci if (IS_ERR(fe)) { 96162306a36Sopenharmony_ci /* mirror file entry */ 96262306a36Sopenharmony_ci udf_debug("Mirror metadata file location: block = %u part = %u\n", 96362306a36Sopenharmony_ci mdata->s_mirror_file_loc, mdata->s_phys_partition_ref); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci fe = udf_find_metadata_inode_efe(sb, mdata->s_mirror_file_loc, 96662306a36Sopenharmony_ci mdata->s_phys_partition_ref); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (IS_ERR(fe)) { 96962306a36Sopenharmony_ci udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n"); 97062306a36Sopenharmony_ci return PTR_ERR(fe); 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci mdata->s_mirror_fe = fe; 97362306a36Sopenharmony_ci } else 97462306a36Sopenharmony_ci mdata->s_metadata_fe = fe; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* 97862306a36Sopenharmony_ci * bitmap file entry 97962306a36Sopenharmony_ci * Note: 98062306a36Sopenharmony_ci * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102) 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) { 98362306a36Sopenharmony_ci addr.logicalBlockNum = mdata->s_bitmap_file_loc; 98462306a36Sopenharmony_ci addr.partitionReferenceNum = mdata->s_phys_partition_ref; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci udf_debug("Bitmap file location: block = %u part = %u\n", 98762306a36Sopenharmony_ci addr.logicalBlockNum, addr.partitionReferenceNum); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci fe = udf_iget_special(sb, &addr); 99062306a36Sopenharmony_ci if (IS_ERR(fe)) { 99162306a36Sopenharmony_ci if (sb_rdonly(sb)) 99262306a36Sopenharmony_ci udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); 99362306a36Sopenharmony_ci else { 99462306a36Sopenharmony_ci udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n"); 99562306a36Sopenharmony_ci return PTR_ERR(fe); 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci } else 99862306a36Sopenharmony_ci mdata->s_bitmap_fe = fe; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci udf_debug("udf_load_metadata_files Ok\n"); 100262306a36Sopenharmony_ci return 0; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ciint udf_compute_nr_groups(struct super_block *sb, u32 partition) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; 100862306a36Sopenharmony_ci return DIV_ROUND_UP(map->s_partition_len + 100962306a36Sopenharmony_ci (sizeof(struct spaceBitmapDesc) << 3), 101062306a36Sopenharmony_ci sb->s_blocksize * 8); 101162306a36Sopenharmony_ci} 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_cistatic struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) 101462306a36Sopenharmony_ci{ 101562306a36Sopenharmony_ci struct udf_bitmap *bitmap; 101662306a36Sopenharmony_ci int nr_groups = udf_compute_nr_groups(sb, index); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci bitmap = kvzalloc(struct_size(bitmap, s_block_bitmap, nr_groups), 101962306a36Sopenharmony_ci GFP_KERNEL); 102062306a36Sopenharmony_ci if (!bitmap) 102162306a36Sopenharmony_ci return NULL; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci bitmap->s_nr_groups = nr_groups; 102462306a36Sopenharmony_ci return bitmap; 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic int check_partition_desc(struct super_block *sb, 102862306a36Sopenharmony_ci struct partitionDesc *p, 102962306a36Sopenharmony_ci struct udf_part_map *map) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci bool umap, utable, fmap, ftable; 103262306a36Sopenharmony_ci struct partitionHeaderDesc *phd; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci switch (le32_to_cpu(p->accessType)) { 103562306a36Sopenharmony_ci case PD_ACCESS_TYPE_READ_ONLY: 103662306a36Sopenharmony_ci case PD_ACCESS_TYPE_WRITE_ONCE: 103762306a36Sopenharmony_ci case PD_ACCESS_TYPE_NONE: 103862306a36Sopenharmony_ci goto force_ro; 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* No Partition Header Descriptor? */ 104262306a36Sopenharmony_ci if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && 104362306a36Sopenharmony_ci strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) 104462306a36Sopenharmony_ci goto force_ro; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci phd = (struct partitionHeaderDesc *)p->partitionContentsUse; 104762306a36Sopenharmony_ci utable = phd->unallocSpaceTable.extLength; 104862306a36Sopenharmony_ci umap = phd->unallocSpaceBitmap.extLength; 104962306a36Sopenharmony_ci ftable = phd->freedSpaceTable.extLength; 105062306a36Sopenharmony_ci fmap = phd->freedSpaceBitmap.extLength; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci /* No allocation info? */ 105362306a36Sopenharmony_ci if (!utable && !umap && !ftable && !fmap) 105462306a36Sopenharmony_ci goto force_ro; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* We don't support blocks that require erasing before overwrite */ 105762306a36Sopenharmony_ci if (ftable || fmap) 105862306a36Sopenharmony_ci goto force_ro; 105962306a36Sopenharmony_ci /* UDF 2.60: 2.3.3 - no mixing of tables & bitmaps, no VAT. */ 106062306a36Sopenharmony_ci if (utable && umap) 106162306a36Sopenharmony_ci goto force_ro; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci if (map->s_partition_type == UDF_VIRTUAL_MAP15 || 106462306a36Sopenharmony_ci map->s_partition_type == UDF_VIRTUAL_MAP20 || 106562306a36Sopenharmony_ci map->s_partition_type == UDF_METADATA_MAP25) 106662306a36Sopenharmony_ci goto force_ro; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci return 0; 106962306a36Sopenharmony_ciforce_ro: 107062306a36Sopenharmony_ci if (!sb_rdonly(sb)) 107162306a36Sopenharmony_ci return -EACCES; 107262306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 107362306a36Sopenharmony_ci return 0; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic int udf_fill_partdesc_info(struct super_block *sb, 107762306a36Sopenharmony_ci struct partitionDesc *p, int p_index) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct udf_part_map *map; 108062306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 108162306a36Sopenharmony_ci struct partitionHeaderDesc *phd; 108262306a36Sopenharmony_ci int err; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci map = &sbi->s_partmaps[p_index]; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ 108762306a36Sopenharmony_ci map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) 109062306a36Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; 109162306a36Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) 109262306a36Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; 109362306a36Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) 109462306a36Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; 109562306a36Sopenharmony_ci if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) 109662306a36Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci udf_debug("Partition (%d type %x) starts at physical %u, block length %u\n", 109962306a36Sopenharmony_ci p_index, map->s_partition_type, 110062306a36Sopenharmony_ci map->s_partition_root, map->s_partition_len); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci err = check_partition_desc(sb, p, map); 110362306a36Sopenharmony_ci if (err) 110462306a36Sopenharmony_ci return err; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* 110762306a36Sopenharmony_ci * Skip loading allocation info it we cannot ever write to the fs. 110862306a36Sopenharmony_ci * This is a correctness thing as we may have decided to force ro mount 110962306a36Sopenharmony_ci * to avoid allocation info we don't support. 111062306a36Sopenharmony_ci */ 111162306a36Sopenharmony_ci if (UDF_QUERY_FLAG(sb, UDF_FLAG_RW_INCOMPAT)) 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci phd = (struct partitionHeaderDesc *)p->partitionContentsUse; 111562306a36Sopenharmony_ci if (phd->unallocSpaceTable.extLength) { 111662306a36Sopenharmony_ci struct kernel_lb_addr loc = { 111762306a36Sopenharmony_ci .logicalBlockNum = le32_to_cpu( 111862306a36Sopenharmony_ci phd->unallocSpaceTable.extPosition), 111962306a36Sopenharmony_ci .partitionReferenceNum = p_index, 112062306a36Sopenharmony_ci }; 112162306a36Sopenharmony_ci struct inode *inode; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci inode = udf_iget_special(sb, &loc); 112462306a36Sopenharmony_ci if (IS_ERR(inode)) { 112562306a36Sopenharmony_ci udf_debug("cannot load unallocSpaceTable (part %d)\n", 112662306a36Sopenharmony_ci p_index); 112762306a36Sopenharmony_ci return PTR_ERR(inode); 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci map->s_uspace.s_table = inode; 113062306a36Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; 113162306a36Sopenharmony_ci udf_debug("unallocSpaceTable (part %d) @ %lu\n", 113262306a36Sopenharmony_ci p_index, map->s_uspace.s_table->i_ino); 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (phd->unallocSpaceBitmap.extLength) { 113662306a36Sopenharmony_ci struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); 113762306a36Sopenharmony_ci if (!bitmap) 113862306a36Sopenharmony_ci return -ENOMEM; 113962306a36Sopenharmony_ci map->s_uspace.s_bitmap = bitmap; 114062306a36Sopenharmony_ci bitmap->s_extPosition = le32_to_cpu( 114162306a36Sopenharmony_ci phd->unallocSpaceBitmap.extPosition); 114262306a36Sopenharmony_ci map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; 114362306a36Sopenharmony_ci udf_debug("unallocSpaceBitmap (part %d) @ %u\n", 114462306a36Sopenharmony_ci p_index, bitmap->s_extPosition); 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci return 0; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic void udf_find_vat_block(struct super_block *sb, int p_index, 115162306a36Sopenharmony_ci int type1_index, sector_t start_block) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 115462306a36Sopenharmony_ci struct udf_part_map *map = &sbi->s_partmaps[p_index]; 115562306a36Sopenharmony_ci sector_t vat_block; 115662306a36Sopenharmony_ci struct kernel_lb_addr ino; 115762306a36Sopenharmony_ci struct inode *inode; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* 116062306a36Sopenharmony_ci * VAT file entry is in the last recorded block. Some broken disks have 116162306a36Sopenharmony_ci * it a few blocks before so try a bit harder... 116262306a36Sopenharmony_ci */ 116362306a36Sopenharmony_ci ino.partitionReferenceNum = type1_index; 116462306a36Sopenharmony_ci for (vat_block = start_block; 116562306a36Sopenharmony_ci vat_block >= map->s_partition_root && 116662306a36Sopenharmony_ci vat_block >= start_block - 3; vat_block--) { 116762306a36Sopenharmony_ci ino.logicalBlockNum = vat_block - map->s_partition_root; 116862306a36Sopenharmony_ci inode = udf_iget_special(sb, &ino); 116962306a36Sopenharmony_ci if (!IS_ERR(inode)) { 117062306a36Sopenharmony_ci sbi->s_vat_inode = inode; 117162306a36Sopenharmony_ci break; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int udf_load_vat(struct super_block *sb, int p_index, int type1_index) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 117962306a36Sopenharmony_ci struct udf_part_map *map = &sbi->s_partmaps[p_index]; 118062306a36Sopenharmony_ci struct buffer_head *bh = NULL; 118162306a36Sopenharmony_ci struct udf_inode_info *vati; 118262306a36Sopenharmony_ci struct virtualAllocationTable20 *vat20; 118362306a36Sopenharmony_ci sector_t blocks = sb_bdev_nr_blocks(sb); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block); 118662306a36Sopenharmony_ci if (!sbi->s_vat_inode && 118762306a36Sopenharmony_ci sbi->s_last_block != blocks - 1) { 118862306a36Sopenharmony_ci pr_notice("Failed to read VAT inode from the last recorded block (%lu), retrying with the last block of the device (%lu).\n", 118962306a36Sopenharmony_ci (unsigned long)sbi->s_last_block, 119062306a36Sopenharmony_ci (unsigned long)blocks - 1); 119162306a36Sopenharmony_ci udf_find_vat_block(sb, p_index, type1_index, blocks - 1); 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci if (!sbi->s_vat_inode) 119462306a36Sopenharmony_ci return -EIO; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (map->s_partition_type == UDF_VIRTUAL_MAP15) { 119762306a36Sopenharmony_ci map->s_type_specific.s_virtual.s_start_offset = 0; 119862306a36Sopenharmony_ci map->s_type_specific.s_virtual.s_num_entries = 119962306a36Sopenharmony_ci (sbi->s_vat_inode->i_size - 36) >> 2; 120062306a36Sopenharmony_ci } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { 120162306a36Sopenharmony_ci vati = UDF_I(sbi->s_vat_inode); 120262306a36Sopenharmony_ci if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { 120362306a36Sopenharmony_ci int err = 0; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci bh = udf_bread(sbi->s_vat_inode, 0, 0, &err); 120662306a36Sopenharmony_ci if (!bh) { 120762306a36Sopenharmony_ci if (!err) 120862306a36Sopenharmony_ci err = -EFSCORRUPTED; 120962306a36Sopenharmony_ci return err; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci vat20 = (struct virtualAllocationTable20 *)bh->b_data; 121262306a36Sopenharmony_ci } else { 121362306a36Sopenharmony_ci vat20 = (struct virtualAllocationTable20 *) 121462306a36Sopenharmony_ci vati->i_data; 121562306a36Sopenharmony_ci } 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci map->s_type_specific.s_virtual.s_start_offset = 121862306a36Sopenharmony_ci le16_to_cpu(vat20->lengthHeader); 121962306a36Sopenharmony_ci map->s_type_specific.s_virtual.s_num_entries = 122062306a36Sopenharmony_ci (sbi->s_vat_inode->i_size - 122162306a36Sopenharmony_ci map->s_type_specific.s_virtual. 122262306a36Sopenharmony_ci s_start_offset) >> 2; 122362306a36Sopenharmony_ci brelse(bh); 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci return 0; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci/* 122962306a36Sopenharmony_ci * Load partition descriptor block 123062306a36Sopenharmony_ci * 123162306a36Sopenharmony_ci * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor 123262306a36Sopenharmony_ci * sequence. 123362306a36Sopenharmony_ci */ 123462306a36Sopenharmony_cistatic int udf_load_partdesc(struct super_block *sb, sector_t block) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci struct buffer_head *bh; 123762306a36Sopenharmony_ci struct partitionDesc *p; 123862306a36Sopenharmony_ci struct udf_part_map *map; 123962306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 124062306a36Sopenharmony_ci int i, type1_idx; 124162306a36Sopenharmony_ci uint16_t partitionNumber; 124262306a36Sopenharmony_ci uint16_t ident; 124362306a36Sopenharmony_ci int ret; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 124662306a36Sopenharmony_ci if (!bh) 124762306a36Sopenharmony_ci return -EAGAIN; 124862306a36Sopenharmony_ci if (ident != TAG_IDENT_PD) { 124962306a36Sopenharmony_ci ret = 0; 125062306a36Sopenharmony_ci goto out_bh; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci p = (struct partitionDesc *)bh->b_data; 125462306a36Sopenharmony_ci partitionNumber = le16_to_cpu(p->partitionNumber); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci /* First scan for TYPE1 and SPARABLE partitions */ 125762306a36Sopenharmony_ci for (i = 0; i < sbi->s_partitions; i++) { 125862306a36Sopenharmony_ci map = &sbi->s_partmaps[i]; 125962306a36Sopenharmony_ci udf_debug("Searching map: (%u == %u)\n", 126062306a36Sopenharmony_ci map->s_partition_num, partitionNumber); 126162306a36Sopenharmony_ci if (map->s_partition_num == partitionNumber && 126262306a36Sopenharmony_ci (map->s_partition_type == UDF_TYPE1_MAP15 || 126362306a36Sopenharmony_ci map->s_partition_type == UDF_SPARABLE_MAP15)) 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci } 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci if (i >= sbi->s_partitions) { 126862306a36Sopenharmony_ci udf_debug("Partition (%u) not found in partition map\n", 126962306a36Sopenharmony_ci partitionNumber); 127062306a36Sopenharmony_ci ret = 0; 127162306a36Sopenharmony_ci goto out_bh; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci ret = udf_fill_partdesc_info(sb, p, i); 127562306a36Sopenharmony_ci if (ret < 0) 127662306a36Sopenharmony_ci goto out_bh; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci /* 127962306a36Sopenharmony_ci * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and 128062306a36Sopenharmony_ci * PHYSICAL partitions are already set up 128162306a36Sopenharmony_ci */ 128262306a36Sopenharmony_ci type1_idx = i; 128362306a36Sopenharmony_ci map = NULL; /* supress 'maybe used uninitialized' warning */ 128462306a36Sopenharmony_ci for (i = 0; i < sbi->s_partitions; i++) { 128562306a36Sopenharmony_ci map = &sbi->s_partmaps[i]; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (map->s_partition_num == partitionNumber && 128862306a36Sopenharmony_ci (map->s_partition_type == UDF_VIRTUAL_MAP15 || 128962306a36Sopenharmony_ci map->s_partition_type == UDF_VIRTUAL_MAP20 || 129062306a36Sopenharmony_ci map->s_partition_type == UDF_METADATA_MAP25)) 129162306a36Sopenharmony_ci break; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci if (i >= sbi->s_partitions) { 129562306a36Sopenharmony_ci ret = 0; 129662306a36Sopenharmony_ci goto out_bh; 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci ret = udf_fill_partdesc_info(sb, p, i); 130062306a36Sopenharmony_ci if (ret < 0) 130162306a36Sopenharmony_ci goto out_bh; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (map->s_partition_type == UDF_METADATA_MAP25) { 130462306a36Sopenharmony_ci ret = udf_load_metadata_files(sb, i, type1_idx); 130562306a36Sopenharmony_ci if (ret < 0) { 130662306a36Sopenharmony_ci udf_err(sb, "error loading MetaData partition map %d\n", 130762306a36Sopenharmony_ci i); 130862306a36Sopenharmony_ci goto out_bh; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci } else { 131162306a36Sopenharmony_ci /* 131262306a36Sopenharmony_ci * If we have a partition with virtual map, we don't handle 131362306a36Sopenharmony_ci * writing to it (we overwrite blocks instead of relocating 131462306a36Sopenharmony_ci * them). 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 131762306a36Sopenharmony_ci ret = -EACCES; 131862306a36Sopenharmony_ci goto out_bh; 131962306a36Sopenharmony_ci } 132062306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 132162306a36Sopenharmony_ci ret = udf_load_vat(sb, i, type1_idx); 132262306a36Sopenharmony_ci if (ret < 0) 132362306a36Sopenharmony_ci goto out_bh; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci ret = 0; 132662306a36Sopenharmony_ciout_bh: 132762306a36Sopenharmony_ci /* In case loading failed, we handle cleanup in udf_fill_super */ 132862306a36Sopenharmony_ci brelse(bh); 132962306a36Sopenharmony_ci return ret; 133062306a36Sopenharmony_ci} 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_cistatic int udf_load_sparable_map(struct super_block *sb, 133362306a36Sopenharmony_ci struct udf_part_map *map, 133462306a36Sopenharmony_ci struct sparablePartitionMap *spm) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci uint32_t loc; 133762306a36Sopenharmony_ci uint16_t ident; 133862306a36Sopenharmony_ci struct sparingTable *st; 133962306a36Sopenharmony_ci struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing; 134062306a36Sopenharmony_ci int i; 134162306a36Sopenharmony_ci struct buffer_head *bh; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci map->s_partition_type = UDF_SPARABLE_MAP15; 134462306a36Sopenharmony_ci sdata->s_packet_len = le16_to_cpu(spm->packetLength); 134562306a36Sopenharmony_ci if (!is_power_of_2(sdata->s_packet_len)) { 134662306a36Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 134762306a36Sopenharmony_ci "Invalid packet length %u\n", 134862306a36Sopenharmony_ci (unsigned)sdata->s_packet_len); 134962306a36Sopenharmony_ci return -EIO; 135062306a36Sopenharmony_ci } 135162306a36Sopenharmony_ci if (spm->numSparingTables > 4) { 135262306a36Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 135362306a36Sopenharmony_ci "Too many sparing tables (%d)\n", 135462306a36Sopenharmony_ci (int)spm->numSparingTables); 135562306a36Sopenharmony_ci return -EIO; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci if (le32_to_cpu(spm->sizeSparingTable) > sb->s_blocksize) { 135862306a36Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 135962306a36Sopenharmony_ci "Too big sparing table size (%u)\n", 136062306a36Sopenharmony_ci le32_to_cpu(spm->sizeSparingTable)); 136162306a36Sopenharmony_ci return -EIO; 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci for (i = 0; i < spm->numSparingTables; i++) { 136562306a36Sopenharmony_ci loc = le32_to_cpu(spm->locSparingTable[i]); 136662306a36Sopenharmony_ci bh = udf_read_tagged(sb, loc, loc, &ident); 136762306a36Sopenharmony_ci if (!bh) 136862306a36Sopenharmony_ci continue; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci st = (struct sparingTable *)bh->b_data; 137162306a36Sopenharmony_ci if (ident != 0 || 137262306a36Sopenharmony_ci strncmp(st->sparingIdent.ident, UDF_ID_SPARING, 137362306a36Sopenharmony_ci strlen(UDF_ID_SPARING)) || 137462306a36Sopenharmony_ci sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > 137562306a36Sopenharmony_ci sb->s_blocksize) { 137662306a36Sopenharmony_ci brelse(bh); 137762306a36Sopenharmony_ci continue; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci sdata->s_spar_map[i] = bh; 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci map->s_partition_func = udf_get_pblock_spar15; 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic int udf_load_logicalvol(struct super_block *sb, sector_t block, 138762306a36Sopenharmony_ci struct kernel_lb_addr *fileset) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci struct logicalVolDesc *lvd; 139062306a36Sopenharmony_ci int i, offset; 139162306a36Sopenharmony_ci uint8_t type; 139262306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 139362306a36Sopenharmony_ci struct genericPartitionMap *gpm; 139462306a36Sopenharmony_ci uint16_t ident; 139562306a36Sopenharmony_ci struct buffer_head *bh; 139662306a36Sopenharmony_ci unsigned int table_len; 139762306a36Sopenharmony_ci int ret; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 140062306a36Sopenharmony_ci if (!bh) 140162306a36Sopenharmony_ci return -EAGAIN; 140262306a36Sopenharmony_ci BUG_ON(ident != TAG_IDENT_LVD); 140362306a36Sopenharmony_ci lvd = (struct logicalVolDesc *)bh->b_data; 140462306a36Sopenharmony_ci table_len = le32_to_cpu(lvd->mapTableLength); 140562306a36Sopenharmony_ci if (table_len > sb->s_blocksize - sizeof(*lvd)) { 140662306a36Sopenharmony_ci udf_err(sb, "error loading logical volume descriptor: " 140762306a36Sopenharmony_ci "Partition table too long (%u > %lu)\n", table_len, 140862306a36Sopenharmony_ci sb->s_blocksize - sizeof(*lvd)); 140962306a36Sopenharmony_ci ret = -EIO; 141062306a36Sopenharmony_ci goto out_bh; 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci ret = udf_verify_domain_identifier(sb, &lvd->domainIdent, 141462306a36Sopenharmony_ci "logical volume"); 141562306a36Sopenharmony_ci if (ret) 141662306a36Sopenharmony_ci goto out_bh; 141762306a36Sopenharmony_ci ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); 141862306a36Sopenharmony_ci if (ret) 141962306a36Sopenharmony_ci goto out_bh; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci for (i = 0, offset = 0; 142262306a36Sopenharmony_ci i < sbi->s_partitions && offset < table_len; 142362306a36Sopenharmony_ci i++, offset += gpm->partitionMapLength) { 142462306a36Sopenharmony_ci struct udf_part_map *map = &sbi->s_partmaps[i]; 142562306a36Sopenharmony_ci gpm = (struct genericPartitionMap *) 142662306a36Sopenharmony_ci &(lvd->partitionMaps[offset]); 142762306a36Sopenharmony_ci type = gpm->partitionMapType; 142862306a36Sopenharmony_ci if (type == 1) { 142962306a36Sopenharmony_ci struct genericPartitionMap1 *gpm1 = 143062306a36Sopenharmony_ci (struct genericPartitionMap1 *)gpm; 143162306a36Sopenharmony_ci map->s_partition_type = UDF_TYPE1_MAP15; 143262306a36Sopenharmony_ci map->s_volumeseqnum = le16_to_cpu(gpm1->volSeqNum); 143362306a36Sopenharmony_ci map->s_partition_num = le16_to_cpu(gpm1->partitionNum); 143462306a36Sopenharmony_ci map->s_partition_func = NULL; 143562306a36Sopenharmony_ci } else if (type == 2) { 143662306a36Sopenharmony_ci struct udfPartitionMap2 *upm2 = 143762306a36Sopenharmony_ci (struct udfPartitionMap2 *)gpm; 143862306a36Sopenharmony_ci if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, 143962306a36Sopenharmony_ci strlen(UDF_ID_VIRTUAL))) { 144062306a36Sopenharmony_ci u16 suf = 144162306a36Sopenharmony_ci le16_to_cpu(((__le16 *)upm2->partIdent. 144262306a36Sopenharmony_ci identSuffix)[0]); 144362306a36Sopenharmony_ci if (suf < 0x0200) { 144462306a36Sopenharmony_ci map->s_partition_type = 144562306a36Sopenharmony_ci UDF_VIRTUAL_MAP15; 144662306a36Sopenharmony_ci map->s_partition_func = 144762306a36Sopenharmony_ci udf_get_pblock_virt15; 144862306a36Sopenharmony_ci } else { 144962306a36Sopenharmony_ci map->s_partition_type = 145062306a36Sopenharmony_ci UDF_VIRTUAL_MAP20; 145162306a36Sopenharmony_ci map->s_partition_func = 145262306a36Sopenharmony_ci udf_get_pblock_virt20; 145362306a36Sopenharmony_ci } 145462306a36Sopenharmony_ci } else if (!strncmp(upm2->partIdent.ident, 145562306a36Sopenharmony_ci UDF_ID_SPARABLE, 145662306a36Sopenharmony_ci strlen(UDF_ID_SPARABLE))) { 145762306a36Sopenharmony_ci ret = udf_load_sparable_map(sb, map, 145862306a36Sopenharmony_ci (struct sparablePartitionMap *)gpm); 145962306a36Sopenharmony_ci if (ret < 0) 146062306a36Sopenharmony_ci goto out_bh; 146162306a36Sopenharmony_ci } else if (!strncmp(upm2->partIdent.ident, 146262306a36Sopenharmony_ci UDF_ID_METADATA, 146362306a36Sopenharmony_ci strlen(UDF_ID_METADATA))) { 146462306a36Sopenharmony_ci struct udf_meta_data *mdata = 146562306a36Sopenharmony_ci &map->s_type_specific.s_metadata; 146662306a36Sopenharmony_ci struct metadataPartitionMap *mdm = 146762306a36Sopenharmony_ci (struct metadataPartitionMap *) 146862306a36Sopenharmony_ci &(lvd->partitionMaps[offset]); 146962306a36Sopenharmony_ci udf_debug("Parsing Logical vol part %d type %u id=%s\n", 147062306a36Sopenharmony_ci i, type, UDF_ID_METADATA); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci map->s_partition_type = UDF_METADATA_MAP25; 147362306a36Sopenharmony_ci map->s_partition_func = udf_get_pblock_meta25; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci mdata->s_meta_file_loc = 147662306a36Sopenharmony_ci le32_to_cpu(mdm->metadataFileLoc); 147762306a36Sopenharmony_ci mdata->s_mirror_file_loc = 147862306a36Sopenharmony_ci le32_to_cpu(mdm->metadataMirrorFileLoc); 147962306a36Sopenharmony_ci mdata->s_bitmap_file_loc = 148062306a36Sopenharmony_ci le32_to_cpu(mdm->metadataBitmapFileLoc); 148162306a36Sopenharmony_ci mdata->s_alloc_unit_size = 148262306a36Sopenharmony_ci le32_to_cpu(mdm->allocUnitSize); 148362306a36Sopenharmony_ci mdata->s_align_unit_size = 148462306a36Sopenharmony_ci le16_to_cpu(mdm->alignUnitSize); 148562306a36Sopenharmony_ci if (mdm->flags & 0x01) 148662306a36Sopenharmony_ci mdata->s_flags |= MF_DUPLICATE_MD; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci udf_debug("Metadata Ident suffix=0x%x\n", 148962306a36Sopenharmony_ci le16_to_cpu(*(__le16 *) 149062306a36Sopenharmony_ci mdm->partIdent.identSuffix)); 149162306a36Sopenharmony_ci udf_debug("Metadata part num=%u\n", 149262306a36Sopenharmony_ci le16_to_cpu(mdm->partitionNum)); 149362306a36Sopenharmony_ci udf_debug("Metadata part alloc unit size=%u\n", 149462306a36Sopenharmony_ci le32_to_cpu(mdm->allocUnitSize)); 149562306a36Sopenharmony_ci udf_debug("Metadata file loc=%u\n", 149662306a36Sopenharmony_ci le32_to_cpu(mdm->metadataFileLoc)); 149762306a36Sopenharmony_ci udf_debug("Mirror file loc=%u\n", 149862306a36Sopenharmony_ci le32_to_cpu(mdm->metadataMirrorFileLoc)); 149962306a36Sopenharmony_ci udf_debug("Bitmap file loc=%u\n", 150062306a36Sopenharmony_ci le32_to_cpu(mdm->metadataBitmapFileLoc)); 150162306a36Sopenharmony_ci udf_debug("Flags: %d %u\n", 150262306a36Sopenharmony_ci mdata->s_flags, mdm->flags); 150362306a36Sopenharmony_ci } else { 150462306a36Sopenharmony_ci udf_debug("Unknown ident: %s\n", 150562306a36Sopenharmony_ci upm2->partIdent.ident); 150662306a36Sopenharmony_ci continue; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci map->s_volumeseqnum = le16_to_cpu(upm2->volSeqNum); 150962306a36Sopenharmony_ci map->s_partition_num = le16_to_cpu(upm2->partitionNum); 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci udf_debug("Partition (%d:%u) type %u on volume %u\n", 151262306a36Sopenharmony_ci i, map->s_partition_num, type, map->s_volumeseqnum); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci if (fileset) { 151662306a36Sopenharmony_ci struct long_ad *la = (struct long_ad *)&(lvd->logicalVolContentsUse[0]); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci *fileset = lelb_to_cpu(la->extLocation); 151962306a36Sopenharmony_ci udf_debug("FileSet found in LogicalVolDesc at block=%u, partition=%u\n", 152062306a36Sopenharmony_ci fileset->logicalBlockNum, 152162306a36Sopenharmony_ci fileset->partitionReferenceNum); 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci if (lvd->integritySeqExt.extLength) 152462306a36Sopenharmony_ci udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); 152562306a36Sopenharmony_ci ret = 0; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci if (!sbi->s_lvid_bh) { 152862306a36Sopenharmony_ci /* We can't generate unique IDs without a valid LVID */ 152962306a36Sopenharmony_ci if (sb_rdonly(sb)) { 153062306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 153162306a36Sopenharmony_ci } else { 153262306a36Sopenharmony_ci udf_warn(sb, "Damaged or missing LVID, forcing " 153362306a36Sopenharmony_ci "readonly mount\n"); 153462306a36Sopenharmony_ci ret = -EACCES; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ciout_bh: 153862306a36Sopenharmony_ci brelse(bh); 153962306a36Sopenharmony_ci return ret; 154062306a36Sopenharmony_ci} 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci/* 154362306a36Sopenharmony_ci * Find the prevailing Logical Volume Integrity Descriptor. 154462306a36Sopenharmony_ci */ 154562306a36Sopenharmony_cistatic void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci struct buffer_head *bh, *final_bh; 154862306a36Sopenharmony_ci uint16_t ident; 154962306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 155062306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 155162306a36Sopenharmony_ci int indirections = 0; 155262306a36Sopenharmony_ci u32 parts, impuselen; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci while (++indirections <= UDF_MAX_LVID_NESTING) { 155562306a36Sopenharmony_ci final_bh = NULL; 155662306a36Sopenharmony_ci while (loc.extLength > 0 && 155762306a36Sopenharmony_ci (bh = udf_read_tagged(sb, loc.extLocation, 155862306a36Sopenharmony_ci loc.extLocation, &ident))) { 155962306a36Sopenharmony_ci if (ident != TAG_IDENT_LVID) { 156062306a36Sopenharmony_ci brelse(bh); 156162306a36Sopenharmony_ci break; 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci brelse(final_bh); 156562306a36Sopenharmony_ci final_bh = bh; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci loc.extLength -= sb->s_blocksize; 156862306a36Sopenharmony_ci loc.extLocation++; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_ci if (!final_bh) 157262306a36Sopenharmony_ci return; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci brelse(sbi->s_lvid_bh); 157562306a36Sopenharmony_ci sbi->s_lvid_bh = final_bh; 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)final_bh->b_data; 157862306a36Sopenharmony_ci if (lvid->nextIntegrityExt.extLength == 0) 157962306a36Sopenharmony_ci goto check; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci loc = leea_to_cpu(lvid->nextIntegrityExt); 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci udf_warn(sb, "Too many LVID indirections (max %u), ignoring.\n", 158562306a36Sopenharmony_ci UDF_MAX_LVID_NESTING); 158662306a36Sopenharmony_ciout_err: 158762306a36Sopenharmony_ci brelse(sbi->s_lvid_bh); 158862306a36Sopenharmony_ci sbi->s_lvid_bh = NULL; 158962306a36Sopenharmony_ci return; 159062306a36Sopenharmony_cicheck: 159162306a36Sopenharmony_ci parts = le32_to_cpu(lvid->numOfPartitions); 159262306a36Sopenharmony_ci impuselen = le32_to_cpu(lvid->lengthOfImpUse); 159362306a36Sopenharmony_ci if (parts >= sb->s_blocksize || impuselen >= sb->s_blocksize || 159462306a36Sopenharmony_ci sizeof(struct logicalVolIntegrityDesc) + impuselen + 159562306a36Sopenharmony_ci 2 * parts * sizeof(u32) > sb->s_blocksize) { 159662306a36Sopenharmony_ci udf_warn(sb, "Corrupted LVID (parts=%u, impuselen=%u), " 159762306a36Sopenharmony_ci "ignoring.\n", parts, impuselen); 159862306a36Sopenharmony_ci goto out_err; 159962306a36Sopenharmony_ci } 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci/* 160362306a36Sopenharmony_ci * Step for reallocation of table of partition descriptor sequence numbers. 160462306a36Sopenharmony_ci * Must be power of 2. 160562306a36Sopenharmony_ci */ 160662306a36Sopenharmony_ci#define PART_DESC_ALLOC_STEP 32 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistruct part_desc_seq_scan_data { 160962306a36Sopenharmony_ci struct udf_vds_record rec; 161062306a36Sopenharmony_ci u32 partnum; 161162306a36Sopenharmony_ci}; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_cistruct desc_seq_scan_data { 161462306a36Sopenharmony_ci struct udf_vds_record vds[VDS_POS_LENGTH]; 161562306a36Sopenharmony_ci unsigned int size_part_descs; 161662306a36Sopenharmony_ci unsigned int num_part_descs; 161762306a36Sopenharmony_ci struct part_desc_seq_scan_data *part_descs_loc; 161862306a36Sopenharmony_ci}; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic struct udf_vds_record *handle_partition_descriptor( 162162306a36Sopenharmony_ci struct buffer_head *bh, 162262306a36Sopenharmony_ci struct desc_seq_scan_data *data) 162362306a36Sopenharmony_ci{ 162462306a36Sopenharmony_ci struct partitionDesc *desc = (struct partitionDesc *)bh->b_data; 162562306a36Sopenharmony_ci int partnum; 162662306a36Sopenharmony_ci int i; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci partnum = le16_to_cpu(desc->partitionNumber); 162962306a36Sopenharmony_ci for (i = 0; i < data->num_part_descs; i++) 163062306a36Sopenharmony_ci if (partnum == data->part_descs_loc[i].partnum) 163162306a36Sopenharmony_ci return &(data->part_descs_loc[i].rec); 163262306a36Sopenharmony_ci if (data->num_part_descs >= data->size_part_descs) { 163362306a36Sopenharmony_ci struct part_desc_seq_scan_data *new_loc; 163462306a36Sopenharmony_ci unsigned int new_size = ALIGN(partnum, PART_DESC_ALLOC_STEP); 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci new_loc = kcalloc(new_size, sizeof(*new_loc), GFP_KERNEL); 163762306a36Sopenharmony_ci if (!new_loc) 163862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 163962306a36Sopenharmony_ci memcpy(new_loc, data->part_descs_loc, 164062306a36Sopenharmony_ci data->size_part_descs * sizeof(*new_loc)); 164162306a36Sopenharmony_ci kfree(data->part_descs_loc); 164262306a36Sopenharmony_ci data->part_descs_loc = new_loc; 164362306a36Sopenharmony_ci data->size_part_descs = new_size; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci return &(data->part_descs_loc[data->num_part_descs++].rec); 164662306a36Sopenharmony_ci} 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic struct udf_vds_record *get_volume_descriptor_record(uint16_t ident, 165062306a36Sopenharmony_ci struct buffer_head *bh, struct desc_seq_scan_data *data) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci switch (ident) { 165362306a36Sopenharmony_ci case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ 165462306a36Sopenharmony_ci return &(data->vds[VDS_POS_PRIMARY_VOL_DESC]); 165562306a36Sopenharmony_ci case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ 165662306a36Sopenharmony_ci return &(data->vds[VDS_POS_IMP_USE_VOL_DESC]); 165762306a36Sopenharmony_ci case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ 165862306a36Sopenharmony_ci return &(data->vds[VDS_POS_LOGICAL_VOL_DESC]); 165962306a36Sopenharmony_ci case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ 166062306a36Sopenharmony_ci return &(data->vds[VDS_POS_UNALLOC_SPACE_DESC]); 166162306a36Sopenharmony_ci case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 166262306a36Sopenharmony_ci return handle_partition_descriptor(bh, data); 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci return NULL; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci/* 166862306a36Sopenharmony_ci * Process a main/reserve volume descriptor sequence. 166962306a36Sopenharmony_ci * @block First block of first extent of the sequence. 167062306a36Sopenharmony_ci * @lastblock Lastblock of first extent of the sequence. 167162306a36Sopenharmony_ci * @fileset There we store extent containing root fileset 167262306a36Sopenharmony_ci * 167362306a36Sopenharmony_ci * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor 167462306a36Sopenharmony_ci * sequence 167562306a36Sopenharmony_ci */ 167662306a36Sopenharmony_cistatic noinline int udf_process_sequence( 167762306a36Sopenharmony_ci struct super_block *sb, 167862306a36Sopenharmony_ci sector_t block, sector_t lastblock, 167962306a36Sopenharmony_ci struct kernel_lb_addr *fileset) 168062306a36Sopenharmony_ci{ 168162306a36Sopenharmony_ci struct buffer_head *bh = NULL; 168262306a36Sopenharmony_ci struct udf_vds_record *curr; 168362306a36Sopenharmony_ci struct generic_desc *gd; 168462306a36Sopenharmony_ci struct volDescPtr *vdp; 168562306a36Sopenharmony_ci bool done = false; 168662306a36Sopenharmony_ci uint32_t vdsn; 168762306a36Sopenharmony_ci uint16_t ident; 168862306a36Sopenharmony_ci int ret; 168962306a36Sopenharmony_ci unsigned int indirections = 0; 169062306a36Sopenharmony_ci struct desc_seq_scan_data data; 169162306a36Sopenharmony_ci unsigned int i; 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci memset(data.vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); 169462306a36Sopenharmony_ci data.size_part_descs = PART_DESC_ALLOC_STEP; 169562306a36Sopenharmony_ci data.num_part_descs = 0; 169662306a36Sopenharmony_ci data.part_descs_loc = kcalloc(data.size_part_descs, 169762306a36Sopenharmony_ci sizeof(*data.part_descs_loc), 169862306a36Sopenharmony_ci GFP_KERNEL); 169962306a36Sopenharmony_ci if (!data.part_descs_loc) 170062306a36Sopenharmony_ci return -ENOMEM; 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci /* 170362306a36Sopenharmony_ci * Read the main descriptor sequence and find which descriptors 170462306a36Sopenharmony_ci * are in it. 170562306a36Sopenharmony_ci */ 170662306a36Sopenharmony_ci for (; (!done && block <= lastblock); block++) { 170762306a36Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 170862306a36Sopenharmony_ci if (!bh) 170962306a36Sopenharmony_ci break; 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci /* Process each descriptor (ISO 13346 3/8.3-8.4) */ 171262306a36Sopenharmony_ci gd = (struct generic_desc *)bh->b_data; 171362306a36Sopenharmony_ci vdsn = le32_to_cpu(gd->volDescSeqNum); 171462306a36Sopenharmony_ci switch (ident) { 171562306a36Sopenharmony_ci case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */ 171662306a36Sopenharmony_ci if (++indirections > UDF_MAX_TD_NESTING) { 171762306a36Sopenharmony_ci udf_err(sb, "too many Volume Descriptor " 171862306a36Sopenharmony_ci "Pointers (max %u supported)\n", 171962306a36Sopenharmony_ci UDF_MAX_TD_NESTING); 172062306a36Sopenharmony_ci brelse(bh); 172162306a36Sopenharmony_ci ret = -EIO; 172262306a36Sopenharmony_ci goto out; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci vdp = (struct volDescPtr *)bh->b_data; 172662306a36Sopenharmony_ci block = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation); 172762306a36Sopenharmony_ci lastblock = le32_to_cpu( 172862306a36Sopenharmony_ci vdp->nextVolDescSeqExt.extLength) >> 172962306a36Sopenharmony_ci sb->s_blocksize_bits; 173062306a36Sopenharmony_ci lastblock += block - 1; 173162306a36Sopenharmony_ci /* For loop is going to increment 'block' again */ 173262306a36Sopenharmony_ci block--; 173362306a36Sopenharmony_ci break; 173462306a36Sopenharmony_ci case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ 173562306a36Sopenharmony_ci case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ 173662306a36Sopenharmony_ci case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ 173762306a36Sopenharmony_ci case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ 173862306a36Sopenharmony_ci case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ 173962306a36Sopenharmony_ci curr = get_volume_descriptor_record(ident, bh, &data); 174062306a36Sopenharmony_ci if (IS_ERR(curr)) { 174162306a36Sopenharmony_ci brelse(bh); 174262306a36Sopenharmony_ci ret = PTR_ERR(curr); 174362306a36Sopenharmony_ci goto out; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci /* Descriptor we don't care about? */ 174662306a36Sopenharmony_ci if (!curr) 174762306a36Sopenharmony_ci break; 174862306a36Sopenharmony_ci if (vdsn >= curr->volDescSeqNum) { 174962306a36Sopenharmony_ci curr->volDescSeqNum = vdsn; 175062306a36Sopenharmony_ci curr->block = block; 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci break; 175362306a36Sopenharmony_ci case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ 175462306a36Sopenharmony_ci done = true; 175562306a36Sopenharmony_ci break; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci brelse(bh); 175862306a36Sopenharmony_ci } 175962306a36Sopenharmony_ci /* 176062306a36Sopenharmony_ci * Now read interesting descriptors again and process them 176162306a36Sopenharmony_ci * in a suitable order 176262306a36Sopenharmony_ci */ 176362306a36Sopenharmony_ci if (!data.vds[VDS_POS_PRIMARY_VOL_DESC].block) { 176462306a36Sopenharmony_ci udf_err(sb, "Primary Volume Descriptor not found!\n"); 176562306a36Sopenharmony_ci ret = -EAGAIN; 176662306a36Sopenharmony_ci goto out; 176762306a36Sopenharmony_ci } 176862306a36Sopenharmony_ci ret = udf_load_pvoldesc(sb, data.vds[VDS_POS_PRIMARY_VOL_DESC].block); 176962306a36Sopenharmony_ci if (ret < 0) 177062306a36Sopenharmony_ci goto out; 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci if (data.vds[VDS_POS_LOGICAL_VOL_DESC].block) { 177362306a36Sopenharmony_ci ret = udf_load_logicalvol(sb, 177462306a36Sopenharmony_ci data.vds[VDS_POS_LOGICAL_VOL_DESC].block, 177562306a36Sopenharmony_ci fileset); 177662306a36Sopenharmony_ci if (ret < 0) 177762306a36Sopenharmony_ci goto out; 177862306a36Sopenharmony_ci } 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci /* Now handle prevailing Partition Descriptors */ 178162306a36Sopenharmony_ci for (i = 0; i < data.num_part_descs; i++) { 178262306a36Sopenharmony_ci ret = udf_load_partdesc(sb, data.part_descs_loc[i].rec.block); 178362306a36Sopenharmony_ci if (ret < 0) 178462306a36Sopenharmony_ci goto out; 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci ret = 0; 178762306a36Sopenharmony_ciout: 178862306a36Sopenharmony_ci kfree(data.part_descs_loc); 178962306a36Sopenharmony_ci return ret; 179062306a36Sopenharmony_ci} 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci/* 179362306a36Sopenharmony_ci * Load Volume Descriptor Sequence described by anchor in bh 179462306a36Sopenharmony_ci * 179562306a36Sopenharmony_ci * Returns <0 on error, 0 on success 179662306a36Sopenharmony_ci */ 179762306a36Sopenharmony_cistatic int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, 179862306a36Sopenharmony_ci struct kernel_lb_addr *fileset) 179962306a36Sopenharmony_ci{ 180062306a36Sopenharmony_ci struct anchorVolDescPtr *anchor; 180162306a36Sopenharmony_ci sector_t main_s, main_e, reserve_s, reserve_e; 180262306a36Sopenharmony_ci int ret; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci anchor = (struct anchorVolDescPtr *)bh->b_data; 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci /* Locate the main sequence */ 180762306a36Sopenharmony_ci main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); 180862306a36Sopenharmony_ci main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); 180962306a36Sopenharmony_ci main_e = main_e >> sb->s_blocksize_bits; 181062306a36Sopenharmony_ci main_e += main_s - 1; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* Locate the reserve sequence */ 181362306a36Sopenharmony_ci reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); 181462306a36Sopenharmony_ci reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); 181562306a36Sopenharmony_ci reserve_e = reserve_e >> sb->s_blocksize_bits; 181662306a36Sopenharmony_ci reserve_e += reserve_s - 1; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci /* Process the main & reserve sequences */ 181962306a36Sopenharmony_ci /* responsible for finding the PartitionDesc(s) */ 182062306a36Sopenharmony_ci ret = udf_process_sequence(sb, main_s, main_e, fileset); 182162306a36Sopenharmony_ci if (ret != -EAGAIN) 182262306a36Sopenharmony_ci return ret; 182362306a36Sopenharmony_ci udf_sb_free_partitions(sb); 182462306a36Sopenharmony_ci ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset); 182562306a36Sopenharmony_ci if (ret < 0) { 182662306a36Sopenharmony_ci udf_sb_free_partitions(sb); 182762306a36Sopenharmony_ci /* No sequence was OK, return -EIO */ 182862306a36Sopenharmony_ci if (ret == -EAGAIN) 182962306a36Sopenharmony_ci ret = -EIO; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci return ret; 183262306a36Sopenharmony_ci} 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci/* 183562306a36Sopenharmony_ci * Check whether there is an anchor block in the given block and 183662306a36Sopenharmony_ci * load Volume Descriptor Sequence if so. 183762306a36Sopenharmony_ci * 183862306a36Sopenharmony_ci * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor 183962306a36Sopenharmony_ci * block 184062306a36Sopenharmony_ci */ 184162306a36Sopenharmony_cistatic int udf_check_anchor_block(struct super_block *sb, sector_t block, 184262306a36Sopenharmony_ci struct kernel_lb_addr *fileset) 184362306a36Sopenharmony_ci{ 184462306a36Sopenharmony_ci struct buffer_head *bh; 184562306a36Sopenharmony_ci uint16_t ident; 184662306a36Sopenharmony_ci int ret; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci bh = udf_read_tagged(sb, block, block, &ident); 184962306a36Sopenharmony_ci if (!bh) 185062306a36Sopenharmony_ci return -EAGAIN; 185162306a36Sopenharmony_ci if (ident != TAG_IDENT_AVDP) { 185262306a36Sopenharmony_ci brelse(bh); 185362306a36Sopenharmony_ci return -EAGAIN; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci ret = udf_load_sequence(sb, bh, fileset); 185662306a36Sopenharmony_ci brelse(bh); 185762306a36Sopenharmony_ci return ret; 185862306a36Sopenharmony_ci} 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci/* 186162306a36Sopenharmony_ci * Search for an anchor volume descriptor pointer. 186262306a36Sopenharmony_ci * 186362306a36Sopenharmony_ci * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set 186462306a36Sopenharmony_ci * of anchors. 186562306a36Sopenharmony_ci */ 186662306a36Sopenharmony_cistatic int udf_scan_anchors(struct super_block *sb, udf_pblk_t *lastblock, 186762306a36Sopenharmony_ci struct kernel_lb_addr *fileset) 186862306a36Sopenharmony_ci{ 186962306a36Sopenharmony_ci udf_pblk_t last[6]; 187062306a36Sopenharmony_ci int i; 187162306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 187262306a36Sopenharmony_ci int last_count = 0; 187362306a36Sopenharmony_ci int ret; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci /* First try user provided anchor */ 187662306a36Sopenharmony_ci if (sbi->s_anchor) { 187762306a36Sopenharmony_ci ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset); 187862306a36Sopenharmony_ci if (ret != -EAGAIN) 187962306a36Sopenharmony_ci return ret; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci /* 188262306a36Sopenharmony_ci * according to spec, anchor is in either: 188362306a36Sopenharmony_ci * block 256 188462306a36Sopenharmony_ci * lastblock-256 188562306a36Sopenharmony_ci * lastblock 188662306a36Sopenharmony_ci * however, if the disc isn't closed, it could be 512. 188762306a36Sopenharmony_ci */ 188862306a36Sopenharmony_ci ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset); 188962306a36Sopenharmony_ci if (ret != -EAGAIN) 189062306a36Sopenharmony_ci return ret; 189162306a36Sopenharmony_ci /* 189262306a36Sopenharmony_ci * The trouble is which block is the last one. Drives often misreport 189362306a36Sopenharmony_ci * this so we try various possibilities. 189462306a36Sopenharmony_ci */ 189562306a36Sopenharmony_ci last[last_count++] = *lastblock; 189662306a36Sopenharmony_ci if (*lastblock >= 1) 189762306a36Sopenharmony_ci last[last_count++] = *lastblock - 1; 189862306a36Sopenharmony_ci last[last_count++] = *lastblock + 1; 189962306a36Sopenharmony_ci if (*lastblock >= 2) 190062306a36Sopenharmony_ci last[last_count++] = *lastblock - 2; 190162306a36Sopenharmony_ci if (*lastblock >= 150) 190262306a36Sopenharmony_ci last[last_count++] = *lastblock - 150; 190362306a36Sopenharmony_ci if (*lastblock >= 152) 190462306a36Sopenharmony_ci last[last_count++] = *lastblock - 152; 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci for (i = 0; i < last_count; i++) { 190762306a36Sopenharmony_ci if (last[i] >= sb_bdev_nr_blocks(sb)) 190862306a36Sopenharmony_ci continue; 190962306a36Sopenharmony_ci ret = udf_check_anchor_block(sb, last[i], fileset); 191062306a36Sopenharmony_ci if (ret != -EAGAIN) { 191162306a36Sopenharmony_ci if (!ret) 191262306a36Sopenharmony_ci *lastblock = last[i]; 191362306a36Sopenharmony_ci return ret; 191462306a36Sopenharmony_ci } 191562306a36Sopenharmony_ci if (last[i] < 256) 191662306a36Sopenharmony_ci continue; 191762306a36Sopenharmony_ci ret = udf_check_anchor_block(sb, last[i] - 256, fileset); 191862306a36Sopenharmony_ci if (ret != -EAGAIN) { 191962306a36Sopenharmony_ci if (!ret) 192062306a36Sopenharmony_ci *lastblock = last[i]; 192162306a36Sopenharmony_ci return ret; 192262306a36Sopenharmony_ci } 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci /* Finally try block 512 in case media is open */ 192662306a36Sopenharmony_ci return udf_check_anchor_block(sb, sbi->s_session + 512, fileset); 192762306a36Sopenharmony_ci} 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci/* 193062306a36Sopenharmony_ci * Check Volume Structure Descriptor, find Anchor block and load Volume 193162306a36Sopenharmony_ci * Descriptor Sequence. 193262306a36Sopenharmony_ci * 193362306a36Sopenharmony_ci * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor 193462306a36Sopenharmony_ci * block was not found. 193562306a36Sopenharmony_ci */ 193662306a36Sopenharmony_cistatic int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, 193762306a36Sopenharmony_ci int silent, struct kernel_lb_addr *fileset) 193862306a36Sopenharmony_ci{ 193962306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 194062306a36Sopenharmony_ci int nsr = 0; 194162306a36Sopenharmony_ci int ret; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (!sb_set_blocksize(sb, uopt->blocksize)) { 194462306a36Sopenharmony_ci if (!silent) 194562306a36Sopenharmony_ci udf_warn(sb, "Bad block size\n"); 194662306a36Sopenharmony_ci return -EINVAL; 194762306a36Sopenharmony_ci } 194862306a36Sopenharmony_ci sbi->s_last_block = uopt->lastblock; 194962306a36Sopenharmony_ci if (!uopt->novrs) { 195062306a36Sopenharmony_ci /* Check that it is NSR02 compliant */ 195162306a36Sopenharmony_ci nsr = udf_check_vsd(sb); 195262306a36Sopenharmony_ci if (!nsr) { 195362306a36Sopenharmony_ci if (!silent) 195462306a36Sopenharmony_ci udf_warn(sb, "No VRS found\n"); 195562306a36Sopenharmony_ci return -EINVAL; 195662306a36Sopenharmony_ci } 195762306a36Sopenharmony_ci if (nsr == -1) 195862306a36Sopenharmony_ci udf_debug("Failed to read sector at offset %d. " 195962306a36Sopenharmony_ci "Assuming open disc. Skipping validity " 196062306a36Sopenharmony_ci "check\n", VSD_FIRST_SECTOR_OFFSET); 196162306a36Sopenharmony_ci if (!sbi->s_last_block) 196262306a36Sopenharmony_ci sbi->s_last_block = udf_get_last_block(sb); 196362306a36Sopenharmony_ci } else { 196462306a36Sopenharmony_ci udf_debug("Validity check skipped because of novrs option\n"); 196562306a36Sopenharmony_ci } 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci /* Look for anchor block and load Volume Descriptor Sequence */ 196862306a36Sopenharmony_ci sbi->s_anchor = uopt->anchor; 196962306a36Sopenharmony_ci ret = udf_scan_anchors(sb, &sbi->s_last_block, fileset); 197062306a36Sopenharmony_ci if (ret < 0) { 197162306a36Sopenharmony_ci if (!silent && ret == -EAGAIN) 197262306a36Sopenharmony_ci udf_warn(sb, "No anchor found\n"); 197362306a36Sopenharmony_ci return ret; 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci return 0; 197662306a36Sopenharmony_ci} 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_cistatic void udf_finalize_lvid(struct logicalVolIntegrityDesc *lvid) 197962306a36Sopenharmony_ci{ 198062306a36Sopenharmony_ci struct timespec64 ts; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci ktime_get_real_ts64(&ts); 198362306a36Sopenharmony_ci udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); 198462306a36Sopenharmony_ci lvid->descTag.descCRC = cpu_to_le16( 198562306a36Sopenharmony_ci crc_itu_t(0, (char *)lvid + sizeof(struct tag), 198662306a36Sopenharmony_ci le16_to_cpu(lvid->descTag.descCRCLength))); 198762306a36Sopenharmony_ci lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); 198862306a36Sopenharmony_ci} 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_cistatic void udf_open_lvid(struct super_block *sb) 199162306a36Sopenharmony_ci{ 199262306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 199362306a36Sopenharmony_ci struct buffer_head *bh = sbi->s_lvid_bh; 199462306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 199562306a36Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci if (!bh) 199862306a36Sopenharmony_ci return; 199962306a36Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 200062306a36Sopenharmony_ci lvidiu = udf_sb_lvidiu(sb); 200162306a36Sopenharmony_ci if (!lvidiu) 200262306a36Sopenharmony_ci return; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 200562306a36Sopenharmony_ci lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 200662306a36Sopenharmony_ci lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 200762306a36Sopenharmony_ci if (le32_to_cpu(lvid->integrityType) == LVID_INTEGRITY_TYPE_CLOSE) 200862306a36Sopenharmony_ci lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN); 200962306a36Sopenharmony_ci else 201062306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_INCONSISTENT); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci udf_finalize_lvid(lvid); 201362306a36Sopenharmony_ci mark_buffer_dirty(bh); 201462306a36Sopenharmony_ci sbi->s_lvid_dirty = 0; 201562306a36Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 201662306a36Sopenharmony_ci /* Make opening of filesystem visible on the media immediately */ 201762306a36Sopenharmony_ci sync_dirty_buffer(bh); 201862306a36Sopenharmony_ci} 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_cistatic void udf_close_lvid(struct super_block *sb) 202162306a36Sopenharmony_ci{ 202262306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 202362306a36Sopenharmony_ci struct buffer_head *bh = sbi->s_lvid_bh; 202462306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 202562306a36Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu; 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci if (!bh) 202862306a36Sopenharmony_ci return; 202962306a36Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 203062306a36Sopenharmony_ci lvidiu = udf_sb_lvidiu(sb); 203162306a36Sopenharmony_ci if (!lvidiu) 203262306a36Sopenharmony_ci return; 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 203562306a36Sopenharmony_ci lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 203662306a36Sopenharmony_ci lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 203762306a36Sopenharmony_ci if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) 203862306a36Sopenharmony_ci lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); 203962306a36Sopenharmony_ci if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) 204062306a36Sopenharmony_ci lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); 204162306a36Sopenharmony_ci if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) 204262306a36Sopenharmony_ci lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); 204362306a36Sopenharmony_ci if (!UDF_QUERY_FLAG(sb, UDF_FLAG_INCONSISTENT)) 204462306a36Sopenharmony_ci lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* 204762306a36Sopenharmony_ci * We set buffer uptodate unconditionally here to avoid spurious 204862306a36Sopenharmony_ci * warnings from mark_buffer_dirty() when previous EIO has marked 204962306a36Sopenharmony_ci * the buffer as !uptodate 205062306a36Sopenharmony_ci */ 205162306a36Sopenharmony_ci set_buffer_uptodate(bh); 205262306a36Sopenharmony_ci udf_finalize_lvid(lvid); 205362306a36Sopenharmony_ci mark_buffer_dirty(bh); 205462306a36Sopenharmony_ci sbi->s_lvid_dirty = 0; 205562306a36Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 205662306a36Sopenharmony_ci /* Make closing of filesystem visible on the media immediately */ 205762306a36Sopenharmony_ci sync_dirty_buffer(bh); 205862306a36Sopenharmony_ci} 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ciu64 lvid_get_unique_id(struct super_block *sb) 206162306a36Sopenharmony_ci{ 206262306a36Sopenharmony_ci struct buffer_head *bh; 206362306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 206462306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 206562306a36Sopenharmony_ci struct logicalVolHeaderDesc *lvhd; 206662306a36Sopenharmony_ci u64 uniqueID; 206762306a36Sopenharmony_ci u64 ret; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci bh = sbi->s_lvid_bh; 207062306a36Sopenharmony_ci if (!bh) 207162306a36Sopenharmony_ci return 0; 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 207462306a36Sopenharmony_ci lvhd = (struct logicalVolHeaderDesc *)lvid->logicalVolContentsUse; 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 207762306a36Sopenharmony_ci ret = uniqueID = le64_to_cpu(lvhd->uniqueID); 207862306a36Sopenharmony_ci if (!(++uniqueID & 0xFFFFFFFF)) 207962306a36Sopenharmony_ci uniqueID += 16; 208062306a36Sopenharmony_ci lvhd->uniqueID = cpu_to_le64(uniqueID); 208162306a36Sopenharmony_ci udf_updated_lvid(sb); 208262306a36Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci return ret; 208562306a36Sopenharmony_ci} 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_cistatic int udf_fill_super(struct super_block *sb, void *options, int silent) 208862306a36Sopenharmony_ci{ 208962306a36Sopenharmony_ci int ret = -EINVAL; 209062306a36Sopenharmony_ci struct inode *inode = NULL; 209162306a36Sopenharmony_ci struct udf_options uopt; 209262306a36Sopenharmony_ci struct kernel_lb_addr rootdir, fileset; 209362306a36Sopenharmony_ci struct udf_sb_info *sbi; 209462306a36Sopenharmony_ci bool lvid_open = false; 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); 209762306a36Sopenharmony_ci /* By default we'll use overflow[ug]id when UDF inode [ug]id == -1 */ 209862306a36Sopenharmony_ci uopt.uid = make_kuid(current_user_ns(), overflowuid); 209962306a36Sopenharmony_ci uopt.gid = make_kgid(current_user_ns(), overflowgid); 210062306a36Sopenharmony_ci uopt.umask = 0; 210162306a36Sopenharmony_ci uopt.fmode = UDF_INVALID_MODE; 210262306a36Sopenharmony_ci uopt.dmode = UDF_INVALID_MODE; 210362306a36Sopenharmony_ci uopt.nls_map = NULL; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 210662306a36Sopenharmony_ci if (!sbi) 210762306a36Sopenharmony_ci return -ENOMEM; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci sb->s_fs_info = sbi; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci mutex_init(&sbi->s_alloc_mutex); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci if (!udf_parse_options((char *)options, &uopt, false)) 211462306a36Sopenharmony_ci goto parse_options_failure; 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci fileset.logicalBlockNum = 0xFFFFFFFF; 211762306a36Sopenharmony_ci fileset.partitionReferenceNum = 0xFFFF; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci sbi->s_flags = uopt.flags; 212062306a36Sopenharmony_ci sbi->s_uid = uopt.uid; 212162306a36Sopenharmony_ci sbi->s_gid = uopt.gid; 212262306a36Sopenharmony_ci sbi->s_umask = uopt.umask; 212362306a36Sopenharmony_ci sbi->s_fmode = uopt.fmode; 212462306a36Sopenharmony_ci sbi->s_dmode = uopt.dmode; 212562306a36Sopenharmony_ci sbi->s_nls_map = uopt.nls_map; 212662306a36Sopenharmony_ci rwlock_init(&sbi->s_cred_lock); 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci if (uopt.session == 0xFFFFFFFF) 212962306a36Sopenharmony_ci sbi->s_session = udf_get_last_session(sb); 213062306a36Sopenharmony_ci else 213162306a36Sopenharmony_ci sbi->s_session = uopt.session; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci udf_debug("Multi-session=%d\n", sbi->s_session); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci /* Fill in the rest of the superblock */ 213662306a36Sopenharmony_ci sb->s_op = &udf_sb_ops; 213762306a36Sopenharmony_ci sb->s_export_op = &udf_export_ops; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci sb->s_magic = UDF_SUPER_MAGIC; 214062306a36Sopenharmony_ci sb->s_time_gran = 1000; 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_ci if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) { 214362306a36Sopenharmony_ci ret = udf_load_vrs(sb, &uopt, silent, &fileset); 214462306a36Sopenharmony_ci } else { 214562306a36Sopenharmony_ci uopt.blocksize = bdev_logical_block_size(sb->s_bdev); 214662306a36Sopenharmony_ci while (uopt.blocksize <= 4096) { 214762306a36Sopenharmony_ci ret = udf_load_vrs(sb, &uopt, silent, &fileset); 214862306a36Sopenharmony_ci if (ret < 0) { 214962306a36Sopenharmony_ci if (!silent && ret != -EACCES) { 215062306a36Sopenharmony_ci pr_notice("Scanning with blocksize %u failed\n", 215162306a36Sopenharmony_ci uopt.blocksize); 215262306a36Sopenharmony_ci } 215362306a36Sopenharmony_ci brelse(sbi->s_lvid_bh); 215462306a36Sopenharmony_ci sbi->s_lvid_bh = NULL; 215562306a36Sopenharmony_ci /* 215662306a36Sopenharmony_ci * EACCES is special - we want to propagate to 215762306a36Sopenharmony_ci * upper layers that we cannot handle RW mount. 215862306a36Sopenharmony_ci */ 215962306a36Sopenharmony_ci if (ret == -EACCES) 216062306a36Sopenharmony_ci break; 216162306a36Sopenharmony_ci } else 216262306a36Sopenharmony_ci break; 216362306a36Sopenharmony_ci 216462306a36Sopenharmony_ci uopt.blocksize <<= 1; 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci } 216762306a36Sopenharmony_ci if (ret < 0) { 216862306a36Sopenharmony_ci if (ret == -EAGAIN) { 216962306a36Sopenharmony_ci udf_warn(sb, "No partition found (1)\n"); 217062306a36Sopenharmony_ci ret = -EINVAL; 217162306a36Sopenharmony_ci } 217262306a36Sopenharmony_ci goto error_out; 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci udf_debug("Lastblock=%u\n", sbi->s_last_block); 217662306a36Sopenharmony_ci 217762306a36Sopenharmony_ci if (sbi->s_lvid_bh) { 217862306a36Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu = 217962306a36Sopenharmony_ci udf_sb_lvidiu(sb); 218062306a36Sopenharmony_ci uint16_t minUDFReadRev; 218162306a36Sopenharmony_ci uint16_t minUDFWriteRev; 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci if (!lvidiu) { 218462306a36Sopenharmony_ci ret = -EINVAL; 218562306a36Sopenharmony_ci goto error_out; 218662306a36Sopenharmony_ci } 218762306a36Sopenharmony_ci minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev); 218862306a36Sopenharmony_ci minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev); 218962306a36Sopenharmony_ci if (minUDFReadRev > UDF_MAX_READ_VERSION) { 219062306a36Sopenharmony_ci udf_err(sb, "minUDFReadRev=%x (max is %x)\n", 219162306a36Sopenharmony_ci minUDFReadRev, 219262306a36Sopenharmony_ci UDF_MAX_READ_VERSION); 219362306a36Sopenharmony_ci ret = -EINVAL; 219462306a36Sopenharmony_ci goto error_out; 219562306a36Sopenharmony_ci } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) { 219662306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 219762306a36Sopenharmony_ci ret = -EACCES; 219862306a36Sopenharmony_ci goto error_out; 219962306a36Sopenharmony_ci } 220062306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci 220362306a36Sopenharmony_ci sbi->s_udfrev = minUDFWriteRev; 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE) 220662306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE); 220762306a36Sopenharmony_ci if (minUDFReadRev >= UDF_VERS_USE_STREAMS) 220862306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS); 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci if (!sbi->s_partitions) { 221262306a36Sopenharmony_ci udf_warn(sb, "No partition found (2)\n"); 221362306a36Sopenharmony_ci ret = -EINVAL; 221462306a36Sopenharmony_ci goto error_out; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci if (sbi->s_partmaps[sbi->s_partition].s_partition_flags & 221862306a36Sopenharmony_ci UDF_PART_FLAG_READ_ONLY) { 221962306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 222062306a36Sopenharmony_ci ret = -EACCES; 222162306a36Sopenharmony_ci goto error_out; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci ret = udf_find_fileset(sb, &fileset, &rootdir); 222762306a36Sopenharmony_ci if (ret < 0) { 222862306a36Sopenharmony_ci udf_warn(sb, "No fileset found\n"); 222962306a36Sopenharmony_ci goto error_out; 223062306a36Sopenharmony_ci } 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_ci if (!silent) { 223362306a36Sopenharmony_ci struct timestamp ts; 223462306a36Sopenharmony_ci udf_time_to_disk_stamp(&ts, sbi->s_record_time); 223562306a36Sopenharmony_ci udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n", 223662306a36Sopenharmony_ci sbi->s_volume_ident, 223762306a36Sopenharmony_ci le16_to_cpu(ts.year), ts.month, ts.day, 223862306a36Sopenharmony_ci ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone)); 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci if (!sb_rdonly(sb)) { 224162306a36Sopenharmony_ci udf_open_lvid(sb); 224262306a36Sopenharmony_ci lvid_open = true; 224362306a36Sopenharmony_ci } 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci /* Assign the root inode */ 224662306a36Sopenharmony_ci /* assign inodes by physical block number */ 224762306a36Sopenharmony_ci /* perhaps it's not extensible enough, but for now ... */ 224862306a36Sopenharmony_ci inode = udf_iget(sb, &rootdir); 224962306a36Sopenharmony_ci if (IS_ERR(inode)) { 225062306a36Sopenharmony_ci udf_err(sb, "Error in udf_iget, block=%u, partition=%u\n", 225162306a36Sopenharmony_ci rootdir.logicalBlockNum, rootdir.partitionReferenceNum); 225262306a36Sopenharmony_ci ret = PTR_ERR(inode); 225362306a36Sopenharmony_ci goto error_out; 225462306a36Sopenharmony_ci } 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci /* Allocate a dentry for the root inode */ 225762306a36Sopenharmony_ci sb->s_root = d_make_root(inode); 225862306a36Sopenharmony_ci if (!sb->s_root) { 225962306a36Sopenharmony_ci udf_err(sb, "Couldn't allocate root dentry\n"); 226062306a36Sopenharmony_ci ret = -ENOMEM; 226162306a36Sopenharmony_ci goto error_out; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci sb->s_maxbytes = UDF_MAX_FILESIZE; 226462306a36Sopenharmony_ci sb->s_max_links = UDF_MAX_LINKS; 226562306a36Sopenharmony_ci return 0; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_cierror_out: 226862306a36Sopenharmony_ci iput(sbi->s_vat_inode); 226962306a36Sopenharmony_ciparse_options_failure: 227062306a36Sopenharmony_ci unload_nls(uopt.nls_map); 227162306a36Sopenharmony_ci if (lvid_open) 227262306a36Sopenharmony_ci udf_close_lvid(sb); 227362306a36Sopenharmony_ci brelse(sbi->s_lvid_bh); 227462306a36Sopenharmony_ci udf_sb_free_partitions(sb); 227562306a36Sopenharmony_ci kfree(sbi); 227662306a36Sopenharmony_ci sb->s_fs_info = NULL; 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci return ret; 227962306a36Sopenharmony_ci} 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_civoid _udf_err(struct super_block *sb, const char *function, 228262306a36Sopenharmony_ci const char *fmt, ...) 228362306a36Sopenharmony_ci{ 228462306a36Sopenharmony_ci struct va_format vaf; 228562306a36Sopenharmony_ci va_list args; 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci va_start(args, fmt); 228862306a36Sopenharmony_ci 228962306a36Sopenharmony_ci vaf.fmt = fmt; 229062306a36Sopenharmony_ci vaf.va = &args; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci pr_err("error (device %s): %s: %pV", sb->s_id, function, &vaf); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci va_end(args); 229562306a36Sopenharmony_ci} 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_civoid _udf_warn(struct super_block *sb, const char *function, 229862306a36Sopenharmony_ci const char *fmt, ...) 229962306a36Sopenharmony_ci{ 230062306a36Sopenharmony_ci struct va_format vaf; 230162306a36Sopenharmony_ci va_list args; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci va_start(args, fmt); 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci vaf.fmt = fmt; 230662306a36Sopenharmony_ci vaf.va = &args; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci pr_warn("warning (device %s): %s: %pV", sb->s_id, function, &vaf); 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci va_end(args); 231162306a36Sopenharmony_ci} 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_cistatic void udf_put_super(struct super_block *sb) 231462306a36Sopenharmony_ci{ 231562306a36Sopenharmony_ci struct udf_sb_info *sbi; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci sbi = UDF_SB(sb); 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci iput(sbi->s_vat_inode); 232062306a36Sopenharmony_ci unload_nls(sbi->s_nls_map); 232162306a36Sopenharmony_ci if (!sb_rdonly(sb)) 232262306a36Sopenharmony_ci udf_close_lvid(sb); 232362306a36Sopenharmony_ci brelse(sbi->s_lvid_bh); 232462306a36Sopenharmony_ci udf_sb_free_partitions(sb); 232562306a36Sopenharmony_ci mutex_destroy(&sbi->s_alloc_mutex); 232662306a36Sopenharmony_ci kfree(sb->s_fs_info); 232762306a36Sopenharmony_ci sb->s_fs_info = NULL; 232862306a36Sopenharmony_ci} 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_cistatic int udf_sync_fs(struct super_block *sb, int wait) 233162306a36Sopenharmony_ci{ 233262306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci mutex_lock(&sbi->s_alloc_mutex); 233562306a36Sopenharmony_ci if (sbi->s_lvid_dirty) { 233662306a36Sopenharmony_ci struct buffer_head *bh = sbi->s_lvid_bh; 233762306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 234062306a36Sopenharmony_ci udf_finalize_lvid(lvid); 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci /* 234362306a36Sopenharmony_ci * Blockdevice will be synced later so we don't have to submit 234462306a36Sopenharmony_ci * the buffer for IO 234562306a36Sopenharmony_ci */ 234662306a36Sopenharmony_ci mark_buffer_dirty(bh); 234762306a36Sopenharmony_ci sbi->s_lvid_dirty = 0; 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci mutex_unlock(&sbi->s_alloc_mutex); 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci return 0; 235262306a36Sopenharmony_ci} 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_cistatic int udf_statfs(struct dentry *dentry, struct kstatfs *buf) 235562306a36Sopenharmony_ci{ 235662306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 235762306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 235862306a36Sopenharmony_ci struct logicalVolIntegrityDescImpUse *lvidiu; 235962306a36Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci lvidiu = udf_sb_lvidiu(sb); 236262306a36Sopenharmony_ci buf->f_type = UDF_SUPER_MAGIC; 236362306a36Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 236462306a36Sopenharmony_ci buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len; 236562306a36Sopenharmony_ci buf->f_bfree = udf_count_free(sb); 236662306a36Sopenharmony_ci buf->f_bavail = buf->f_bfree; 236762306a36Sopenharmony_ci /* 236862306a36Sopenharmony_ci * Let's pretend each free block is also a free 'inode' since UDF does 236962306a36Sopenharmony_ci * not have separate preallocated table of inodes. 237062306a36Sopenharmony_ci */ 237162306a36Sopenharmony_ci buf->f_files = (lvidiu != NULL ? (le32_to_cpu(lvidiu->numFiles) + 237262306a36Sopenharmony_ci le32_to_cpu(lvidiu->numDirs)) : 0) 237362306a36Sopenharmony_ci + buf->f_bfree; 237462306a36Sopenharmony_ci buf->f_ffree = buf->f_bfree; 237562306a36Sopenharmony_ci buf->f_namelen = UDF_NAME_LEN; 237662306a36Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci return 0; 237962306a36Sopenharmony_ci} 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_cistatic unsigned int udf_count_free_bitmap(struct super_block *sb, 238262306a36Sopenharmony_ci struct udf_bitmap *bitmap) 238362306a36Sopenharmony_ci{ 238462306a36Sopenharmony_ci struct buffer_head *bh = NULL; 238562306a36Sopenharmony_ci unsigned int accum = 0; 238662306a36Sopenharmony_ci int index; 238762306a36Sopenharmony_ci udf_pblk_t block = 0, newblock; 238862306a36Sopenharmony_ci struct kernel_lb_addr loc; 238962306a36Sopenharmony_ci uint32_t bytes; 239062306a36Sopenharmony_ci uint8_t *ptr; 239162306a36Sopenharmony_ci uint16_t ident; 239262306a36Sopenharmony_ci struct spaceBitmapDesc *bm; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci loc.logicalBlockNum = bitmap->s_extPosition; 239562306a36Sopenharmony_ci loc.partitionReferenceNum = UDF_SB(sb)->s_partition; 239662306a36Sopenharmony_ci bh = udf_read_ptagged(sb, &loc, 0, &ident); 239762306a36Sopenharmony_ci 239862306a36Sopenharmony_ci if (!bh) { 239962306a36Sopenharmony_ci udf_err(sb, "udf_count_free failed\n"); 240062306a36Sopenharmony_ci goto out; 240162306a36Sopenharmony_ci } else if (ident != TAG_IDENT_SBD) { 240262306a36Sopenharmony_ci brelse(bh); 240362306a36Sopenharmony_ci udf_err(sb, "udf_count_free failed\n"); 240462306a36Sopenharmony_ci goto out; 240562306a36Sopenharmony_ci } 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci bm = (struct spaceBitmapDesc *)bh->b_data; 240862306a36Sopenharmony_ci bytes = le32_to_cpu(bm->numOfBytes); 240962306a36Sopenharmony_ci index = sizeof(struct spaceBitmapDesc); /* offset in first block only */ 241062306a36Sopenharmony_ci ptr = (uint8_t *)bh->b_data; 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci while (bytes > 0) { 241362306a36Sopenharmony_ci u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index); 241462306a36Sopenharmony_ci accum += bitmap_weight((const unsigned long *)(ptr + index), 241562306a36Sopenharmony_ci cur_bytes * 8); 241662306a36Sopenharmony_ci bytes -= cur_bytes; 241762306a36Sopenharmony_ci if (bytes) { 241862306a36Sopenharmony_ci brelse(bh); 241962306a36Sopenharmony_ci newblock = udf_get_lb_pblock(sb, &loc, ++block); 242062306a36Sopenharmony_ci bh = sb_bread(sb, newblock); 242162306a36Sopenharmony_ci if (!bh) { 242262306a36Sopenharmony_ci udf_debug("read failed\n"); 242362306a36Sopenharmony_ci goto out; 242462306a36Sopenharmony_ci } 242562306a36Sopenharmony_ci index = 0; 242662306a36Sopenharmony_ci ptr = (uint8_t *)bh->b_data; 242762306a36Sopenharmony_ci } 242862306a36Sopenharmony_ci } 242962306a36Sopenharmony_ci brelse(bh); 243062306a36Sopenharmony_ciout: 243162306a36Sopenharmony_ci return accum; 243262306a36Sopenharmony_ci} 243362306a36Sopenharmony_ci 243462306a36Sopenharmony_cistatic unsigned int udf_count_free_table(struct super_block *sb, 243562306a36Sopenharmony_ci struct inode *table) 243662306a36Sopenharmony_ci{ 243762306a36Sopenharmony_ci unsigned int accum = 0; 243862306a36Sopenharmony_ci uint32_t elen; 243962306a36Sopenharmony_ci struct kernel_lb_addr eloc; 244062306a36Sopenharmony_ci struct extent_position epos; 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci mutex_lock(&UDF_SB(sb)->s_alloc_mutex); 244362306a36Sopenharmony_ci epos.block = UDF_I(table)->i_location; 244462306a36Sopenharmony_ci epos.offset = sizeof(struct unallocSpaceEntry); 244562306a36Sopenharmony_ci epos.bh = NULL; 244662306a36Sopenharmony_ci 244762306a36Sopenharmony_ci while (udf_next_aext(table, &epos, &eloc, &elen, 1) != -1) 244862306a36Sopenharmony_ci accum += (elen >> table->i_sb->s_blocksize_bits); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci brelse(epos.bh); 245162306a36Sopenharmony_ci mutex_unlock(&UDF_SB(sb)->s_alloc_mutex); 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci return accum; 245462306a36Sopenharmony_ci} 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_cistatic unsigned int udf_count_free(struct super_block *sb) 245762306a36Sopenharmony_ci{ 245862306a36Sopenharmony_ci unsigned int accum = 0; 245962306a36Sopenharmony_ci struct udf_sb_info *sbi = UDF_SB(sb); 246062306a36Sopenharmony_ci struct udf_part_map *map; 246162306a36Sopenharmony_ci unsigned int part = sbi->s_partition; 246262306a36Sopenharmony_ci int ptype = sbi->s_partmaps[part].s_partition_type; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci if (ptype == UDF_METADATA_MAP25) { 246562306a36Sopenharmony_ci part = sbi->s_partmaps[part].s_type_specific.s_metadata. 246662306a36Sopenharmony_ci s_phys_partition_ref; 246762306a36Sopenharmony_ci } else if (ptype == UDF_VIRTUAL_MAP15 || ptype == UDF_VIRTUAL_MAP20) { 246862306a36Sopenharmony_ci /* 246962306a36Sopenharmony_ci * Filesystems with VAT are append-only and we cannot write to 247062306a36Sopenharmony_ci * them. Let's just report 0 here. 247162306a36Sopenharmony_ci */ 247262306a36Sopenharmony_ci return 0; 247362306a36Sopenharmony_ci } 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci if (sbi->s_lvid_bh) { 247662306a36Sopenharmony_ci struct logicalVolIntegrityDesc *lvid = 247762306a36Sopenharmony_ci (struct logicalVolIntegrityDesc *) 247862306a36Sopenharmony_ci sbi->s_lvid_bh->b_data; 247962306a36Sopenharmony_ci if (le32_to_cpu(lvid->numOfPartitions) > part) { 248062306a36Sopenharmony_ci accum = le32_to_cpu( 248162306a36Sopenharmony_ci lvid->freeSpaceTable[part]); 248262306a36Sopenharmony_ci if (accum == 0xFFFFFFFF) 248362306a36Sopenharmony_ci accum = 0; 248462306a36Sopenharmony_ci } 248562306a36Sopenharmony_ci } 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci if (accum) 248862306a36Sopenharmony_ci return accum; 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci map = &sbi->s_partmaps[part]; 249162306a36Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) { 249262306a36Sopenharmony_ci accum += udf_count_free_bitmap(sb, 249362306a36Sopenharmony_ci map->s_uspace.s_bitmap); 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci if (accum) 249662306a36Sopenharmony_ci return accum; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) { 249962306a36Sopenharmony_ci accum += udf_count_free_table(sb, 250062306a36Sopenharmony_ci map->s_uspace.s_table); 250162306a36Sopenharmony_ci } 250262306a36Sopenharmony_ci return accum; 250362306a36Sopenharmony_ci} 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ciMODULE_AUTHOR("Ben Fennema"); 250662306a36Sopenharmony_ciMODULE_DESCRIPTION("Universal Disk Format Filesystem"); 250762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 250862306a36Sopenharmony_cimodule_init(init_udf_fs) 250962306a36Sopenharmony_cimodule_exit(exit_udf_fs) 2510