diff options
Diffstat (limited to 'fs/udf/super.c')
| -rw-r--r-- | fs/udf/super.c | 2148 |
1 files changed, 1216 insertions, 932 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c index f3ac4abfc94..3286db047a4 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -48,16 +48,17 @@ #include <linux/stat.h> #include <linux/cdrom.h> #include <linux/nls.h> -#include <linux/smp_lock.h> #include <linux/buffer_head.h> #include <linux/vfs.h> #include <linux/vmalloc.h> #include <linux/errno.h> #include <linux/mount.h> #include <linux/seq_file.h> +#include <linux/bitmap.h> +#include <linux/crc-itu-t.h> +#include <linux/log2.h> #include <asm/byteorder.h> -#include <linux/udf_fs.h> #include "udf_sb.h" #include "udf_i.h" @@ -75,57 +76,64 @@ #define UDF_DEFAULT_BLOCKSIZE 2048 -static char error_buf[1024]; +#define VSD_FIRST_SECTOR_OFFSET 32768 +#define VSD_MAX_SECTOR_OFFSET 0x800000 + +enum { UDF_MAX_LINKS = 0xffff }; /* These are the "meat" - everything else is stuffing */ static int udf_fill_super(struct super_block *, void *, int); static void udf_put_super(struct super_block *); -static void udf_write_super(struct super_block *); +static int udf_sync_fs(struct super_block *, int); static int udf_remount_fs(struct super_block *, int *, char *); -static int udf_check_valid(struct super_block *, int, int); -static int udf_vrs(struct super_block *sb, int silent); -static int udf_load_partition(struct super_block *, kernel_lb_addr *); -static int udf_load_logicalvol(struct super_block *, struct buffer_head *, - kernel_lb_addr *); -static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); -static void udf_find_anchor(struct super_block *); -static int udf_find_fileset(struct super_block *, kernel_lb_addr *, - kernel_lb_addr *); -static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); +static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad); +static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *, + struct kernel_lb_addr *); static void udf_load_fileset(struct super_block *, struct buffer_head *, - kernel_lb_addr *); -static int udf_load_partdesc(struct super_block *, struct buffer_head *); + struct kernel_lb_addr *); static void udf_open_lvid(struct super_block *); static void udf_close_lvid(struct super_block *); static unsigned int udf_count_free(struct super_block *); static int udf_statfs(struct dentry *, struct kstatfs *); -static int udf_show_options(struct seq_file *, struct vfsmount *); +static int udf_show_options(struct seq_file *, struct dentry *); -struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) +struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb) { - struct logicalVolIntegrityDesc *lvid = - (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; - __u32 number_of_partitions = le32_to_cpu(lvid->numOfPartitions); - __u32 offset = number_of_partitions * 2 * - sizeof(uint32_t)/sizeof(uint8_t); + struct logicalVolIntegrityDesc *lvid; + unsigned int partnum; + unsigned int offset; + + if (!UDF_SB(sb)->s_lvid_bh) + return NULL; + lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data; + partnum = le32_to_cpu(lvid->numOfPartitions); + if ((sb->s_blocksize - sizeof(struct logicalVolIntegrityDescImpUse) - + offsetof(struct logicalVolIntegrityDesc, impUse)) / + (2 * sizeof(uint32_t)) < partnum) { + udf_err(sb, "Logical volume integrity descriptor corrupted " + "(numOfPartitions = %u)!\n", partnum); + return NULL; + } + /* The offset is to skip freeSpaceTable and sizeTable arrays */ + offset = partnum * 2 * sizeof(uint32_t); return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]); } /* UDF filesystem type */ -static int udf_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - struct vfsmount *mnt) +static struct dentry *udf_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) { - return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super, mnt); + return mount_bdev(fs_type, flags, dev_name, data, udf_fill_super); } static struct file_system_type udf_fstype = { .owner = THIS_MODULE, .name = "udf", - .get_sb = udf_get_sb, + .mount = udf_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; +MODULE_ALIAS_FS("udf"); static struct kmem_cache *udf_inode_cachep; @@ -141,16 +149,25 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ei->i_next_alloc_block = 0; ei->i_next_alloc_goal = 0; ei->i_strat4096 = 0; + init_rwsem(&ei->i_data_sem); + ei->cached_extent.lstart = -1; + spin_lock_init(&ei->i_extent_cache_lock); return &ei->vfs_inode; } -static void udf_destroy_inode(struct inode *inode) +static void udf_i_callback(struct rcu_head *head) { + struct inode *inode = container_of(head, struct inode, i_rcu); kmem_cache_free(udf_inode_cachep, UDF_I(inode)); } -static void init_once(struct kmem_cache *cachep, void *foo) +static void udf_destroy_inode(struct inode *inode) +{ + call_rcu(&inode->i_rcu, udf_i_callback); +} + +static void init_once(void *foo) { struct udf_inode_info *ei = (struct udf_inode_info *)foo; @@ -158,7 +175,7 @@ static void init_once(struct kmem_cache *cachep, void *foo) inode_init_once(&ei->vfs_inode); } -static int init_inodecache(void) +static int __init init_inodecache(void) { udf_inode_cachep = kmem_cache_create("udf_inode_cache", sizeof(struct udf_inode_info), @@ -172,6 +189,11 @@ static int init_inodecache(void) static void destroy_inodecache(void) { + /* + * Make sure all delayed rcu free inodes are flushed before we + * destroy cache. + */ + rcu_barrier(); kmem_cache_destroy(udf_inode_cachep); } @@ -180,10 +202,9 @@ static const struct super_operations udf_sb_ops = { .alloc_inode = udf_alloc_inode, .destroy_inode = udf_destroy_inode, .write_inode = udf_write_inode, - .delete_inode = udf_delete_inode, - .clear_inode = udf_clear_inode, + .evict_inode = udf_evict_inode, .put_super = udf_put_super, - .write_super = udf_write_super, + .sync_fs = udf_sync_fs, .statfs = udf_statfs, .remount_fs = udf_remount_fs, .show_options = udf_show_options, @@ -200,9 +221,11 @@ struct udf_options { unsigned int fileset; unsigned int rootdir; unsigned int flags; - mode_t umask; - gid_t gid; - uid_t uid; + umode_t umask; + kgid_t gid; + kuid_t uid; + umode_t fmode; + umode_t dmode; struct nls_table *nls_map; }; @@ -242,9 +265,8 @@ static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) sbi->s_partmaps = kcalloc(count, sizeof(struct udf_part_map), GFP_KERNEL); if (!sbi->s_partmaps) { - udf_error(sb, __FUNCTION__, - "Unable to allocate space for %d partition maps", - count); + udf_err(sb, "Unable to allocate space for %d partition maps\n", + count); sbi->s_partitions = 0; return -ENOMEM; } @@ -253,14 +275,72 @@ static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) return 0; } -static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt) +static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) +{ + int i; + int nr_groups = bitmap->s_nr_groups; + int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * + nr_groups); + + for (i = 0; i < nr_groups; i++) + if (bitmap->s_block_bitmap[i]) + brelse(bitmap->s_block_bitmap[i]); + + if (size <= PAGE_SIZE) + kfree(bitmap); + else + vfree(bitmap); +} + +static void udf_free_partition(struct udf_part_map *map) +{ + int i; + struct udf_meta_data *mdata; + + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) + iput(map->s_uspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) + iput(map->s_fspace.s_table); + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) + udf_sb_free_bitmap(map->s_uspace.s_bitmap); + if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) + udf_sb_free_bitmap(map->s_fspace.s_bitmap); + if (map->s_partition_type == UDF_SPARABLE_MAP15) + for (i = 0; i < 4; i++) + brelse(map->s_type_specific.s_sparing.s_spar_map[i]); + else if (map->s_partition_type == UDF_METADATA_MAP25) { + mdata = &map->s_type_specific.s_metadata; + iput(mdata->s_metadata_fe); + mdata->s_metadata_fe = NULL; + + iput(mdata->s_mirror_fe); + mdata->s_mirror_fe = NULL; + + iput(mdata->s_bitmap_fe); + mdata->s_bitmap_fe = NULL; + } +} + +static void udf_sb_free_partitions(struct super_block *sb) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + int i; + if (sbi->s_partmaps == NULL) + return; + for (i = 0; i < sbi->s_partitions; i++) + udf_free_partition(&sbi->s_partmaps[i]); + kfree(sbi->s_partmaps); + sbi->s_partmaps = NULL; +} + +static int udf_show_options(struct seq_file *seq, struct dentry *root) { - struct super_block *sb = mnt->mnt_sb; + struct super_block *sb = root->d_sb; struct udf_sb_info *sbi = UDF_SB(sb); if (!UDF_QUERY_FLAG(sb, UDF_FLAG_STRICT)) seq_puts(seq, ",nostrict"); - if (sb->s_blocksize != UDF_DEFAULT_BLOCKSIZE) + if (UDF_QUERY_FLAG(sb, UDF_FLAG_BLOCKSIZE_SET)) seq_printf(seq, ",bs=%lu", sb->s_blocksize); if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) seq_puts(seq, ",unhide"); @@ -279,23 +359,21 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt) if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_IGNORE)) seq_puts(seq, ",gid=ignore"); if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_SET)) - seq_printf(seq, ",uid=%u", sbi->s_uid); + seq_printf(seq, ",uid=%u", from_kuid(&init_user_ns, sbi->s_uid)); if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET)) - seq_printf(seq, ",gid=%u", sbi->s_gid); + seq_printf(seq, ",gid=%u", from_kgid(&init_user_ns, sbi->s_gid)); if (sbi->s_umask != 0) - seq_printf(seq, ",umask=%o", sbi->s_umask); + seq_printf(seq, ",umask=%ho", sbi->s_umask); + if (sbi->s_fmode != UDF_INVALID_MODE) + seq_printf(seq, ",mode=%ho", sbi->s_fmode); + if (sbi->s_dmode != UDF_INVALID_MODE) + seq_printf(seq, ",dmode=%ho", sbi->s_dmode); if (UDF_QUERY_FLAG(sb, UDF_FLAG_SESSION_SET)) seq_printf(seq, ",session=%u", sbi->s_session); if (UDF_QUERY_FLAG(sb, UDF_FLAG_LASTBLOCK_SET)) seq_printf(seq, ",lastblock=%u", sbi->s_last_block); - /* - * s_anchor[2] could be zeroed out in case there is no anchor - * in the specified block, but then the "anchor=N" option - * originally given by the user wasn't effective, so it's OK - * if we don't show it. - */ - if (sbi->s_anchor[2] != 0) - seq_printf(seq, ",anchor=%u", sbi->s_anchor[2]); + if (sbi->s_anchor != 0) + seq_printf(seq, ",anchor=%u", sbi->s_anchor); /* * volume, partition, fileset and rootdir seem to be ignored * currently @@ -319,6 +397,8 @@ static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt) * * gid= Set the default group. * umask= Set the default umask. + * mode= Set the default file permissions. + * dmode= Set the default directory permissions. * uid= Set the default user. * bs= Set the block size. * unhide Show otherwise hidden files. @@ -368,10 +448,11 @@ enum { Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock, Opt_anchor, Opt_volume, Opt_partition, Opt_fileset, Opt_rootdir, Opt_utf8, Opt_iocharset, - Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore + Opt_err, Opt_uforget, Opt_uignore, Opt_gforget, Opt_gignore, + Opt_fmode, Opt_dmode }; -static match_table_t tokens = { +static const match_table_t tokens = { {Opt_novrs, "novrs"}, {Opt_nostrict, "nostrict"}, {Opt_bs, "bs=%u"}, @@ -397,6 +478,8 @@ static match_table_t tokens = { {Opt_rootdir, "rootdir=%u"}, {Opt_utf8, "utf8"}, {Opt_iocharset, "iocharset=%s"}, + {Opt_fmode, "mode=%o"}, + {Opt_dmode, "dmode=%o"}, {Opt_err, NULL} }; @@ -407,7 +490,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt, int option; uopt->novrs = 0; - uopt->blocksize = UDF_DEFAULT_BLOCKSIZE; uopt->partition = 0xFFFF; uopt->session = 0xFFFFFFFF; uopt->lastblock = 0; @@ -423,6 +505,7 @@ static int udf_parse_options(char *options, struct udf_options *uopt, while ((p = strsep(&options, ",")) != NULL) { substring_t args[MAX_OPT_ARGS]; int token; + unsigned n; if (!*p) continue; @@ -430,10 +513,15 @@ static int udf_parse_options(char *options, struct udf_options *uopt, switch (token) { case Opt_novrs: uopt->novrs = 1; + break; case Opt_bs: if (match_int(&args[0], &option)) return 0; - uopt->blocksize = option; + n = option; + if (n != 512 && n != 1024 && n != 2048 && n != 4096) + return 0; + uopt->blocksize = n; + uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET); break; case Opt_unhide: uopt->flags |= (1 << UDF_FLAG_UNHIDE); @@ -456,13 +544,17 @@ static int udf_parse_options(char *options, struct udf_options *uopt, case Opt_gid: if (match_int(args, &option)) return 0; - uopt->gid = option; + uopt->gid = make_kgid(current_user_ns(), option); + if (!gid_valid(uopt->gid)) + return 0; uopt->flags |= (1 << UDF_FLAG_GID_SET); break; case Opt_uid: if (match_int(args, &option)) return 0; - uopt->uid = option; + uopt->uid = make_kuid(current_user_ns(), option); + if (!uid_valid(uopt->uid)) + return 0; uopt->flags |= (1 << UDF_FLAG_UID_SET); break; case Opt_umask: @@ -533,114 +625,82 @@ static int udf_parse_options(char *options, struct udf_options *uopt, case Opt_gforget: uopt->flags |= (1 << UDF_FLAG_GID_FORGET); break; + case Opt_fmode: + if (match_octal(args, &option)) + return 0; + uopt->fmode = option & 0777; + break; + case Opt_dmode: + if (match_octal(args, &option)) + return 0; + uopt->dmode = option & 0777; + break; default: - printk(KERN_ERR "udf: bad mount option \"%s\" " - "or missing value\n", p); + pr_err("bad mount option \"%s\" or missing value\n", p); return 0; } } return 1; } -static void udf_write_super(struct super_block *sb) -{ - lock_kernel(); - - if (!(sb->s_flags & MS_RDONLY)) - udf_open_lvid(sb); - sb->s_dirt = 0; - - unlock_kernel(); -} - static int udf_remount_fs(struct super_block *sb, int *flags, char *options) { struct udf_options uopt; struct udf_sb_info *sbi = UDF_SB(sb); + int error = 0; + struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb); + + sync_filesystem(sb); + if (lvidiu) { + int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev); + if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY)) + return -EACCES; + } uopt.flags = sbi->s_flags; uopt.uid = sbi->s_uid; uopt.gid = sbi->s_gid; uopt.umask = sbi->s_umask; + uopt.fmode = sbi->s_fmode; + uopt.dmode = sbi->s_dmode; if (!udf_parse_options(options, &uopt, true)) return -EINVAL; + write_lock(&sbi->s_cred_lock); sbi->s_flags = uopt.flags; sbi->s_uid = uopt.uid; sbi->s_gid = uopt.gid; sbi->s_umask = uopt.umask; - - if (sbi->s_lvid_bh) { - int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev); - if (write_rev > UDF_MAX_WRITE_VERSION) - *flags |= MS_RDONLY; - } + sbi->s_fmode = uopt.fmode; + sbi->s_dmode = uopt.dmode; + write_unlock(&sbi->s_cred_lock); if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) - return 0; + goto out_unlock; + if (*flags & MS_RDONLY) udf_close_lvid(sb); else udf_open_lvid(sb); - return 0; +out_unlock: + return error; } -/* - * udf_set_blocksize - * - * PURPOSE - * Set the block size to be used in all transfers. - * - * DESCRIPTION - * To allow room for a DMA transfer, it is best to guess big when unsure. - * This routine picks 2048 bytes as the blocksize when guessing. This - * should be adequate until devices with larger block sizes become common. - * - * Note that the Linux kernel can currently only deal with blocksizes of - * 512, 1024, 2048, 4096, and 8192 bytes. - * - * PRE-CONDITIONS - * sb Pointer to _locked_ superblock. - * - * POST-CONDITIONS - * sb->s_blocksize Blocksize. - * sb->s_blocksize_bits log2 of blocksize. - * <return> 0 Blocksize is valid. - * <return> 1 Blocksize is invalid. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ -static int udf_set_blocksize(struct super_block *sb, int bsize) -{ - if (!sb_min_blocksize(sb, bsize)) { - udf_debug("Bad block size (%d)\n", bsize); - printk(KERN_ERR "udf: bad block size (%d)\n", bsize); - return 0; - } - - return sb->s_blocksize; -} - -static int udf_vrs(struct super_block *sb, int silent) +/* Check Volume Structure Descriptors (ECMA 167 2/9.1) */ +/* We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ +static loff_t udf_check_vsd(struct super_block *sb) { struct volStructDesc *vsd = NULL; - int sector = 32768; + loff_t sector = VSD_FIRST_SECTOR_OFFSET; int sectorsize; struct buffer_head *bh = NULL; - int iso9660 = 0; int nsr02 = 0; int nsr03 = 0; struct udf_sb_info *sbi; - /* Block size must be a multiple of 512 */ - if (sb->s_blocksize & 511) - return 0; sbi = UDF_SB(sb); - if (sb->s_blocksize < sizeof(struct volStructDesc)) sectorsize = sizeof(struct volStructDesc); else @@ -649,9 +709,20 @@ static int udf_vrs(struct super_block *sb, int silent) sector += (sbi->s_session << sb->s_blocksize_bits); udf_debug("Starting at sector %u (%ld byte sectors)\n", - (sector >> sb->s_blocksize_bits), sb->s_blocksize); - /* Process the sequence (if applicable) */ - for (; !nsr02 && !nsr03; sector += sectorsize) { + (unsigned int)(sector >> sb->s_blocksize_bits), + sb->s_blocksize); + /* Process the sequence (if applicable). The hard limit on the sector + * offset is arbitrary, hopefully large enough so that all valid UDF + * filesystems will be recognised. There is no mention of an upper + * bound to the size of the volume recognition area in the standard. + * The limit will prevent the code to read all the sectors of a + * specially crafted image (like a bluray disc full of CD001 sectors), + * potentially causing minutes or even hours of uninterruptible I/O + * activity. This actually happened with uninitialised SSD partitions + * (all 0xFF) before the check for the limit and all valid IDs were + * added */ + for (; !nsr02 && !nsr03 && sector < VSD_MAX_SECTOR_OFFSET; + sector += sectorsize) { /* Read a block */ bh = udf_tread(sb, sector >> sb->s_blocksize_bits); if (!bh) @@ -661,31 +732,23 @@ static int udf_vrs(struct super_block *sb, int silent) vsd = (struct volStructDesc *)(bh->b_data + (sector & (sb->s_blocksize - 1))); - if (vsd->stdIdent[0] == 0) { - brelse(bh); - break; - } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, + if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) { - iso9660 = sector; switch (vsd->structType) { case 0: udf_debug("ISO9660 Boot Record found\n"); break; case 1: - udf_debug("ISO9660 Primary Volume Descriptor " - "found\n"); + udf_debug("ISO9660 Primary Volume Descriptor found\n"); break; case 2: - udf_debug("ISO9660 Supplementary Volume " - "Descriptor found\n"); + udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); break; case 3: - udf_debug("ISO9660 Volume Partition Descriptor " - "found\n"); + udf_debug("ISO9660 Volume Partition Descriptor found\n"); break; case 255: - udf_debug("ISO9660 Volume Descriptor Set " - "Terminator found\n"); + udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); break; default: udf_debug("ISO9660 VRS (%u) found\n", @@ -705,6 +768,17 @@ static int udf_vrs(struct super_block *sb, int silent) else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) nsr03 = sector; + else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BOOT2, + VSD_STD_ID_LEN)) + ; /* nothing */ + else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CDW02, + VSD_STD_ID_LEN)) + ; /* nothing */ + else { + /* invalid id : end of volume recognition area */ + brelse(bh); + break; + } brelse(bh); } @@ -712,178 +786,16 @@ static int udf_vrs(struct super_block *sb, int silent) return nsr03; else if (nsr02) return nsr02; - else if (sector - (sbi->s_session << sb->s_blocksize_bits) == 32768) + else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) == + VSD_FIRST_SECTOR_OFFSET) return -1; else return 0; } -/* - * udf_find_anchor - * - * PURPOSE - * Find an anchor volume descriptor. - * - * PRE-CONDITIONS - * sb Pointer to _locked_ superblock. - * lastblock Last block on media. - * - * POST-CONDITIONS - * <return> 1 if not found, 0 if ok - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ -static void udf_find_anchor(struct super_block *sb) -{ - int lastblock; - struct buffer_head *bh = NULL; - uint16_t ident; - uint32_t location; - int i; - struct udf_sb_info *sbi; - - sbi = UDF_SB(sb); - lastblock = sbi->s_last_block; - - if (lastblock) { - int varlastblock = udf_variable_to_fixed(lastblock); - int last[] = { lastblock, lastblock - 2, - lastblock - 150, lastblock - 152, - varlastblock, varlastblock - 2, - varlastblock - 150, varlastblock - 152 }; - - lastblock = 0; - - /* Search for an anchor volume descriptor pointer */ - - /* according to spec, anchor is in either: - * block 256 - * lastblock-256 - * lastblock - * however, if the disc isn't closed, it could be 512 */ - - for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { - ident = location = 0; - if (last[i] >= 0) { - bh = sb_bread(sb, last[i]); - if (bh) { - tag *t = (tag *)bh->b_data; - ident = le16_to_cpu(t->tagIdent); - location = le32_to_cpu(t->tagLocation); - brelse(bh); - } - } - - if (ident == TAG_IDENT_AVDP) { - if (location == last[i] - sbi->s_session) { - lastblock = last[i] - sbi->s_session; - sbi->s_anchor[0] = lastblock; - sbi->s_anchor[1] = lastblock - 256; - } else if (location == - udf_variable_to_fixed(last[i]) - - sbi->s_session) { - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - lastblock = - udf_variable_to_fixed(last[i]) - - sbi->s_session; - sbi->s_anchor[0] = lastblock; - sbi->s_anchor[1] = lastblock - 256 - - sbi->s_session; - } else { - udf_debug("Anchor found at block %d, " - "location mismatch %d.\n", - last[i], location); - } - } else if (ident == TAG_IDENT_FE || - ident == TAG_IDENT_EFE) { - lastblock = last[i]; - sbi->s_anchor[3] = 512; - } else { - ident = location = 0; - if (last[i] >= 256) { - bh = sb_bread(sb, last[i] - 256); - if (bh) { - tag *t = (tag *)bh->b_data; - ident = le16_to_cpu( - t->tagIdent); - location = le32_to_cpu( - t->tagLocation); - brelse(bh); - } - } - - if (ident == TAG_IDENT_AVDP && - location == last[i] - 256 - - sbi->s_session) { - lastblock = last[i]; - sbi->s_anchor[1] = last[i] - 256; - } else { - ident = location = 0; - if (last[i] >= 312 + sbi->s_session) { - bh = sb_bread(sb, - last[i] - 312 - - sbi->s_session); - if (bh) { - tag *t = (tag *) - bh->b_data; - ident = le16_to_cpu( - t->tagIdent); - location = le32_to_cpu( - t->tagLocation); - brelse(bh); - } - } - - if (ident == TAG_IDENT_AVDP && - location == udf_variable_to_fixed(last[i]) - 256) { - UDF_SET_FLAG(sb, - UDF_FLAG_VARCONV); - lastblock = udf_variable_to_fixed(last[i]); - sbi->s_anchor[1] = lastblock - 256; - } - } - } - } - } - - if (!lastblock) { - /* We haven't found the lastblock. check 312 */ - bh = sb_bread(sb, 312 + sbi->s_session); - if (bh) { - tag *t = (tag *)bh->b_data; - ident = le16_to_cpu(t->tagIdent); - location = le32_to_cpu(t->tagLocation); - brelse(bh); - - if (ident == TAG_IDENT_AVDP && location == 256) - UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); - } - } - - for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { - if (sbi->s_anchor[i]) { - bh = udf_read_tagged(sb, sbi->s_anchor[i], - sbi->s_anchor[i], &ident); - if (!bh) - sbi->s_anchor[i] = 0; - else { - brelse(bh); - if ((ident != TAG_IDENT_AVDP) && - (i || (ident != TAG_IDENT_FE && - ident != TAG_IDENT_EFE))) - sbi->s_anchor[i] = 0; - } - } - } - - sbi->s_last_block = lastblock; -} - static int udf_find_fileset(struct super_block *sb, - kernel_lb_addr *fileset, - kernel_lb_addr *root) + struct kernel_lb_addr *fileset, + struct kernel_lb_addr *root) { struct buffer_head *bh = NULL; long lastblock; @@ -892,7 +804,7 @@ static int udf_find_fileset(struct super_block *sb, if (fileset->logicalBlockNum != 0xFFFFFFFF || fileset->partitionReferenceNum != 0xFFFF) { - bh = udf_read_ptagged(sb, *fileset, 0, &ident); + bh = udf_read_ptagged(sb, fileset, 0, &ident); if (!bh) { return 1; @@ -906,7 +818,7 @@ static int udf_find_fileset(struct super_block *sb, sbi = UDF_SB(sb); if (!bh) { /* Search backwards through the partitions */ - kernel_lb_addr newfileset; + struct kernel_lb_addr newfileset; /* --> cvg: FIXME - is it reasonable? */ return 1; @@ -922,7 +834,7 @@ static int udf_find_fileset(struct super_block *sb, newfileset.logicalBlockNum = 0; do { - bh = udf_read_ptagged(sb, newfileset, 0, + bh = udf_read_ptagged(sb, &newfileset, 0, &ident); if (!bh) { newfileset.logicalBlockNum++; @@ -971,44 +883,155 @@ static int udf_find_fileset(struct super_block *sb, return 1; } -static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) +/* + * Load primary Volume Descriptor Sequence + * + * Return <0 on error, 0 on success. -EAGAIN is special meaning next sequence + * should be tried. + */ +static int udf_load_pvoldesc(struct super_block *sb, sector_t block) { struct primaryVolDesc *pvoldesc; - time_t recording; - long recording_usec; - struct ustr instr; - struct ustr outstr; + struct ustr *instr, *outstr; + struct buffer_head *bh; + uint16_t ident; + int ret = -ENOMEM; + + instr = kmalloc(sizeof(struct ustr), GFP_NOFS); + if (!instr) + return -ENOMEM; + + outstr = kmalloc(sizeof(struct ustr), GFP_NOFS); + if (!outstr) + goto out1; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) { + ret = -EAGAIN; + goto out2; + } + + if (ident != TAG_IDENT_PVD) { + ret = -EIO; + goto out_bh; + } pvoldesc = (struct primaryVolDesc *)bh->b_data; - if (udf_stamp_to_time(&recording, &recording_usec, - lets_to_cpu(pvoldesc->recordingDateAndTime))) { - kernel_timestamp ts; - ts = lets_to_cpu(pvoldesc->recordingDateAndTime); - udf_debug("recording time %ld/%ld, %04u/%02u/%02u" - " %02u:%02u (%x)\n", - recording, recording_usec, - ts.year, ts.month, ts.day, ts.hour, - ts.minute, ts.typeAndTimezone); - UDF_SB(sb)->s_record_time.tv_sec = recording; - UDF_SB(sb)->s_record_time.tv_nsec = recording_usec * 1000; - } - - if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) - if (udf_CS0toUTF8(&outstr, &instr)) { - strncpy(UDF_SB(sb)->s_volume_ident, outstr.u_name, - outstr.u_len > 31 ? 31 : outstr.u_len); + if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, + pvoldesc->recordingDateAndTime)) { +#ifdef UDFFS_DEBUG + struct timestamp *ts = &pvoldesc->recordingDateAndTime; + udf_debug("recording time %04u/%02u/%02u %02u:%02u (%x)\n", + le16_to_cpu(ts->year), ts->month, ts->day, ts->hour, + ts->minute, le16_to_cpu(ts->typeAndTimezone)); +#endif + } + + if (!udf_build_ustr(instr, pvoldesc->volIdent, 32)) + if (udf_CS0toUTF8(outstr, instr)) { + strncpy(UDF_SB(sb)->s_volume_ident, outstr->u_name, + outstr->u_len > 31 ? 31 : outstr->u_len); udf_debug("volIdent[] = '%s'\n", - UDF_SB(sb)->s_volume_ident); + UDF_SB(sb)->s_volume_ident); } - if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) - if (udf_CS0toUTF8(&outstr, &instr)) - udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); + if (!udf_build_ustr(instr, pvoldesc->volSetIdent, 128)) + if (udf_CS0toUTF8(outstr, instr)) + udf_debug("volSetIdent[] = '%s'\n", outstr->u_name); + + ret = 0; +out_bh: + brelse(bh); +out2: + kfree(outstr); +out1: + kfree(instr); + return ret; +} + +struct inode *udf_find_metadata_inode_efe(struct super_block *sb, + u32 meta_file_loc, u32 partition_num) +{ + struct kernel_lb_addr addr; + struct inode *metadata_fe; + + addr.logicalBlockNum = meta_file_loc; + addr.partitionReferenceNum = partition_num; + + metadata_fe = udf_iget(sb, &addr); + + if (metadata_fe == NULL) + udf_warn(sb, "metadata inode efe not found\n"); + else if (UDF_I(metadata_fe)->i_alloc_type != ICBTAG_FLAG_AD_SHORT) { + udf_warn(sb, "metadata inode efe does not have short allocation descriptors!\n"); + iput(metadata_fe); + metadata_fe = NULL; + } + + return metadata_fe; +} + +static int udf_load_metadata_files(struct super_block *sb, int partition) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_part_map *map; + struct udf_meta_data *mdata; + struct kernel_lb_addr addr; + + map = &sbi->s_partmaps[partition]; + mdata = &map->s_type_specific.s_metadata; + + /* metadata address */ + udf_debug("Metadata file location: block = %d part = %d\n", + mdata->s_meta_file_loc, map->s_partition_num); + + mdata->s_metadata_fe = udf_find_metadata_inode_efe(sb, + mdata->s_meta_file_loc, map->s_partition_num); + + if (mdata->s_metadata_fe == NULL) { + /* mirror file entry */ + udf_debug("Mirror metadata file location: block = %d part = %d\n", + mdata->s_mirror_file_loc, map->s_partition_num); + + mdata->s_mirror_fe = udf_find_metadata_inode_efe(sb, + mdata->s_mirror_file_loc, map->s_partition_num); + + if (mdata->s_mirror_fe == NULL) { + udf_err(sb, "Both metadata and mirror metadata inode efe can not found\n"); + return -EIO; + } + } + + /* + * bitmap file entry + * Note: + * Load only if bitmap file location differs from 0xFFFFFFFF (DCN-5102) + */ + if (mdata->s_bitmap_file_loc != 0xFFFFFFFF) { + addr.logicalBlockNum = mdata->s_bitmap_file_loc; + addr.partitionReferenceNum = map->s_partition_num; + + udf_debug("Bitmap file location: block = %d part = %d\n", + addr.logicalBlockNum, addr.partitionReferenceNum); + + mdata->s_bitmap_fe = udf_iget(sb, &addr); + if (mdata->s_bitmap_fe == NULL) { + if (sb->s_flags & MS_RDONLY) + udf_warn(sb, "bitmap inode efe not found but it's ok since the disc is mounted read-only\n"); + else { + udf_err(sb, "bitmap inode efe not found and attempted read-write mount\n"); + return -EIO; + } + } + } + + udf_debug("udf_load_metadata_files Ok\n"); + return 0; } static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, - kernel_lb_addr *root) + struct kernel_lb_addr *root) { struct fileSetDesc *fset; @@ -1025,10 +1048,9 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, int udf_compute_nr_groups(struct super_block *sb, u32 partition) { struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; - return (map->s_partition_len + - (sizeof(struct spaceBitmapDesc) << 3) + - (sb->s_blocksize * 8) - 1) / - (sb->s_blocksize * 8); + return DIV_ROUND_UP(map->s_partition_len + + (sizeof(struct spaceBitmapDesc) << 3), + sb->s_blocksize * 8); } static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) @@ -1042,167 +1064,370 @@ static struct udf_bitmap *udf_sb_alloc_bitmap(struct super_block *sb, u32 index) (sizeof(struct buffer_head *) * nr_groups); if (size <= PAGE_SIZE) - bitmap = kmalloc(size, GFP_KERNEL); + bitmap = kzalloc(size, GFP_KERNEL); else - bitmap = vmalloc(size); /* TODO: get rid of vmalloc */ + bitmap = vzalloc(size); /* TODO: get rid of vzalloc */ - if (bitmap == NULL) { - udf_error(sb, __FUNCTION__, - "Unable to allocate space for bitmap " - "and %d buffer_head pointers", nr_groups); + if (bitmap == NULL) return NULL; - } - memset(bitmap, 0x00, size); - bitmap->s_block_bitmap = (struct buffer_head **)(bitmap + 1); bitmap->s_nr_groups = nr_groups; return bitmap; } -static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) +static int udf_fill_partdesc_info(struct super_block *sb, + struct partitionDesc *p, int p_index) { + struct udf_part_map *map; + struct udf_sb_info *sbi = UDF_SB(sb); + struct partitionHeaderDesc *phd; + + map = &sbi->s_partmaps[p_index]; + + map->s_partition_len = le32_to_cpu(p->partitionLength); /* blocks */ + map->s_partition_root = le32_to_cpu(p->partitionStartingLocation); + + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) + map->s_partition_flags |= UDF_PART_FLAG_READ_ONLY; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) + map->s_partition_flags |= UDF_PART_FLAG_WRITE_ONCE; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) + map->s_partition_flags |= UDF_PART_FLAG_REWRITABLE; + if (p->accessType == cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) + map->s_partition_flags |= UDF_PART_FLAG_OVERWRITABLE; + + udf_debug("Partition (%d type %x) starts at physical %d, block length %d\n", + p_index, map->s_partition_type, + map->s_partition_root, map->s_partition_len); + + if (strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) && + strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) + return 0; + + phd = (struct partitionHeaderDesc *)p->partitionContentsUse; + if (phd->unallocSpaceTable.extLength) { + struct kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu( + phd->unallocSpaceTable.extPosition), + .partitionReferenceNum = p_index, + }; + + map->s_uspace.s_table = udf_iget(sb, &loc); + if (!map->s_uspace.s_table) { + udf_debug("cannot load unallocSpaceTable (part %d)\n", + p_index); + return -EIO; + } + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_TABLE; + udf_debug("unallocSpaceTable (part %d) @ %ld\n", + p_index, map->s_uspace.s_table->i_ino); + } + + if (phd->unallocSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); + if (!bitmap) + return -ENOMEM; + map->s_uspace.s_bitmap = bitmap; + bitmap->s_extPosition = le32_to_cpu( + phd->unallocSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; + udf_debug("unallocSpaceBitmap (part %d) @ %d\n", + p_index, bitmap->s_extPosition); + } + + if (phd->partitionIntegrityTable.extLength) + udf_debug("partitionIntegrityTable (part %d)\n", p_index); + + if (phd->freedSpaceTable.extLength) { + struct kernel_lb_addr loc = { + .logicalBlockNum = le32_to_cpu( + phd->freedSpaceTable.extPosition), + .partitionReferenceNum = p_index, + }; + + map->s_fspace.s_table = udf_iget(sb, &loc); + if (!map->s_fspace.s_table) { + udf_debug("cannot load freedSpaceTable (part %d)\n", + p_index); + return -EIO; + } + + map->s_partition_flags |= UDF_PART_FLAG_FREED_TABLE; + udf_debug("freedSpaceTable (part %d) @ %ld\n", + p_index, map->s_fspace.s_table->i_ino); + } + + if (phd->freedSpaceBitmap.extLength) { + struct udf_bitmap *bitmap = udf_sb_alloc_bitmap(sb, p_index); + if (!bitmap) + return -ENOMEM; + map->s_fspace.s_bitmap = bitmap; + bitmap->s_extPosition = le32_to_cpu( + phd->freedSpaceBitmap.extPosition); + map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; + udf_debug("freedSpaceBitmap (part %d) @ %d\n", + p_index, bitmap->s_extPosition); + } + return 0; +} + +static void udf_find_vat_block(struct super_block *sb, int p_index, + int type1_index, sector_t start_block) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_part_map *map = &sbi->s_partmaps[p_index]; + sector_t vat_block; + struct kernel_lb_addr ino; + + /* + * VAT file entry is in the last recorded block. Some broken disks have + * it a few blocks before so try a bit harder... + */ + ino.partitionReferenceNum = type1_index; + for (vat_block = start_block; + vat_block >= map->s_partition_root && + vat_block >= start_block - 3 && + !sbi->s_vat_inode; vat_block--) { + ino.logicalBlockNum = vat_block - map->s_partition_root; + sbi->s_vat_inode = udf_iget(sb, &ino); + } +} + +static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + struct udf_part_map *map = &sbi->s_partmaps[p_index]; + struct buffer_head *bh = NULL; + struct udf_inode_info *vati; + uint32_t pos; + struct virtualAllocationTable20 *vat20; + sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; + + udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block); + if (!sbi->s_vat_inode && + sbi->s_last_block != blocks - 1) { + pr_notice("Failed to read VAT inode from the last recorded block (%lu), retrying with the last block of the device (%lu).\n", + (unsigned long)sbi->s_last_block, + (unsigned long)blocks - 1); + udf_find_vat_block(sb, p_index, type1_index, blocks - 1); + } + if (!sbi->s_vat_inode) + return -EIO; + + if (map->s_partition_type == UDF_VIRTUAL_MAP15) { + map->s_type_specific.s_virtual.s_start_offset = 0; + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - 36) >> 2; + } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { + vati = UDF_I(sbi->s_vat_inode); + if (vati->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { + pos = udf_block_map(sbi->s_vat_inode, 0); + bh = sb_bread(sb, pos); + if (!bh) + return -EIO; + vat20 = (struct virtualAllocationTable20 *)bh->b_data; + } else { + vat20 = (struct virtualAllocationTable20 *) + vati->i_ext.i_data; + } + + map->s_type_specific.s_virtual.s_start_offset = + le16_to_cpu(vat20->lengthHeader); + map->s_type_specific.s_virtual.s_num_entries = + (sbi->s_vat_inode->i_size - + map->s_type_specific.s_virtual. + s_start_offset) >> 2; + brelse(bh); + } + return 0; +} + +/* + * Load partition descriptor block + * + * Returns <0 on error, 0 on success, -EAGAIN is special - try next descriptor + * sequence. + */ +static int udf_load_partdesc(struct super_block *sb, sector_t block) +{ + struct buffer_head *bh; struct partitionDesc *p; - int i; struct udf_part_map *map; - struct udf_sb_info *sbi; + struct udf_sb_info *sbi = UDF_SB(sb); + int i, type1_idx; + uint16_t partitionNumber; + uint16_t ident; + int ret; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + return -EAGAIN; + if (ident != TAG_IDENT_PD) { + ret = 0; + goto out_bh; + } p = (struct partitionDesc *)bh->b_data; - sbi = UDF_SB(sb); + partitionNumber = le16_to_cpu(p->partitionNumber); + /* First scan for TYPE1, SPARABLE and METADATA partitions */ for (i = 0; i < sbi->s_partitions; i++) { map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", - map->s_partition_num, - le16_to_cpu(p->partitionNumber)); - if (map->s_partition_num == - le16_to_cpu(p->partitionNumber)) { - map->s_partition_len = - le32_to_cpu(p->partitionLength); /* blocks */ - map->s_partition_root = - le32_to_cpu(p->partitionStartingLocation); - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_READ_ONLY)) - map->s_partition_flags |= - UDF_PART_FLAG_READ_ONLY; - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_WRITE_ONCE)) - map->s_partition_flags |= - UDF_PART_FLAG_WRITE_ONCE; - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_REWRITABLE)) - map->s_partition_flags |= - UDF_PART_FLAG_REWRITABLE; - if (p->accessType == - cpu_to_le32(PD_ACCESS_TYPE_OVERWRITABLE)) - map->s_partition_flags |= - UDF_PART_FLAG_OVERWRITABLE; - - if (!strcmp(p->partitionContents.ident, - PD_PARTITION_CONTENTS_NSR02) || - !strcmp(p->partitionContents.ident, - PD_PARTITION_CONTENTS_NSR03)) { - struct partitionHeaderDesc *phd; - - phd = (struct partitionHeaderDesc *) - (p->partitionContentsUse); - if (phd->unallocSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition), - .partitionReferenceNum = i, - }; - - map->s_uspace.s_table = - udf_iget(sb, loc); - if (!map->s_uspace.s_table) { - udf_debug("cannot load unallocSpaceTable (part %d)\n", i); - return 1; - } - map->s_partition_flags |= - UDF_PART_FLAG_UNALLOC_TABLE; - udf_debug("unallocSpaceTable (part %d) @ %ld\n", - i, map->s_uspace.s_table->i_ino); - } - if (phd->unallocSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = - udf_sb_alloc_bitmap(sb, i); - map->s_uspace.s_bitmap = bitmap; - if (bitmap != NULL) { - bitmap->s_extLength = - le32_to_cpu(phd->unallocSpaceBitmap.extLength); - bitmap->s_extPosition = - le32_to_cpu(phd->unallocSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; - udf_debug("unallocSpaceBitmap (part %d) @ %d\n", - i, bitmap->s_extPosition); - } - } - if (phd->partitionIntegrityTable.extLength) - udf_debug("partitionIntegrityTable (part %d)\n", i); - if (phd->freedSpaceTable.extLength) { - kernel_lb_addr loc = { - .logicalBlockNum = le32_to_cpu(phd->freedSpaceTable.extPosition), - .partitionReferenceNum = i, - }; - - map->s_fspace.s_table = - udf_iget(sb, loc); - if (!map->s_fspace.s_table) { - udf_debug("cannot load freedSpaceTable (part %d)\n", i); - return 1; - } - map->s_partition_flags |= - UDF_PART_FLAG_FREED_TABLE; - udf_debug("freedSpaceTable (part %d) @ %ld\n", - i, map->s_fspace.s_table->i_ino); - } - if (phd->freedSpaceBitmap.extLength) { - struct udf_bitmap *bitmap = - udf_sb_alloc_bitmap(sb, i); - map->s_fspace.s_bitmap = bitmap; - if (bitmap != NULL) { - bitmap->s_extLength = - le32_to_cpu(phd->freedSpaceBitmap.extLength); - bitmap->s_extPosition = - le32_to_cpu(phd->freedSpaceBitmap.extPosition); - map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; - udf_debug("freedSpaceBitmap (part %d) @ %d\n", - i, bitmap->s_extPosition); - } - } - } + map->s_partition_num, partitionNumber); + if (map->s_partition_num == partitionNumber && + (map->s_partition_type == UDF_TYPE1_MAP15 || + map->s_partition_type == UDF_SPARABLE_MAP15)) break; - } } - if (i == sbi->s_partitions) + + if (i >= sbi->s_partitions) { udf_debug("Partition (%d) not found in partition map\n", - le16_to_cpu(p->partitionNumber)); - else - udf_debug("Partition (%d:%d type %x) starts at physical %d, " - "block length %d\n", - le16_to_cpu(p->partitionNumber), i, - map->s_partition_type, - map->s_partition_root, - map->s_partition_len); + partitionNumber); + ret = 0; + goto out_bh; + } + + ret = udf_fill_partdesc_info(sb, p, i); + if (ret < 0) + goto out_bh; + + /* + * Now rescan for VIRTUAL or METADATA partitions when SPARABLE and + * PHYSICAL partitions are already set up + */ + type1_idx = i; +#ifdef UDFFS_DEBUG + map = NULL; /* supress 'maybe used uninitialized' warning */ +#endif + for (i = 0; i < sbi->s_partitions; i++) { + map = &sbi->s_partmaps[i]; + + if (map->s_partition_num == partitionNumber && + (map->s_partition_type == UDF_VIRTUAL_MAP15 || + map->s_partition_type == UDF_VIRTUAL_MAP20 || + map->s_partition_type == UDF_METADATA_MAP25)) + break; + } + + if (i >= sbi->s_partitions) { + ret = 0; + goto out_bh; + } + + ret = udf_fill_partdesc_info(sb, p, i); + if (ret < 0) + goto out_bh; + + if (map->s_partition_type == UDF_METADATA_MAP25) { + ret = udf_load_metadata_files(sb, i); + if (ret < 0) { + udf_err(sb, "error loading MetaData partition map %d\n", + i); + goto out_bh; + } + } else { + /* + * If we have a partition with virtual map, we don't handle + * writing to it (we overwrite blocks instead of relocating + * them). + */ + if (!(sb->s_flags & MS_RDONLY)) { + ret = -EACCES; + goto out_bh; + } + ret = udf_load_vat(sb, i, type1_idx); + if (ret < 0) + goto out_bh; + } + ret = 0; +out_bh: + /* In case loading failed, we handle cleanup in udf_fill_super */ + brelse(bh); + return ret; +} + +static int udf_load_sparable_map(struct super_block *sb, + struct udf_part_map *map, + struct sparablePartitionMap *spm) +{ + uint32_t loc; + uint16_t ident; + struct sparingTable *st; + struct udf_sparing_data *sdata = &map->s_type_specific.s_sparing; + int i; + struct buffer_head *bh; + + map->s_partition_type = UDF_SPARABLE_MAP15; + sdata->s_packet_len = le16_to_cpu(spm->packetLength); + if (!is_power_of_2(sdata->s_packet_len)) { + udf_err(sb, "error loading logical volume descriptor: " + "Invalid packet length %u\n", + (unsigned)sdata->s_packet_len); + return -EIO; + } + if (spm->numSparingTables > 4) { + udf_err(sb, "error loading logical volume descriptor: " + "Too many sparing tables (%d)\n", + (int)spm->numSparingTables); + return -EIO; + } + + for (i = 0; i < spm->numSparingTables; i++) { + loc = le32_to_cpu(spm->locSparingTable[i]); + bh = udf_read_tagged(sb, loc, loc, &ident); + if (!bh) + continue; + + st = (struct sparingTable *)bh->b_data; + if (ident != 0 || + strncmp(st->sparingIdent.ident, UDF_ID_SPARING, + strlen(UDF_ID_SPARING)) || + sizeof(*st) + le16_to_cpu(st->reallocationTableLen) > + sb->s_blocksize) { + brelse(bh); + continue; + } + + sdata->s_spar_map[i] = bh; + } + map->s_partition_func = udf_get_pblock_spar15; return 0; } -static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, - kernel_lb_addr *fileset) +static int udf_load_logicalvol(struct super_block *sb, sector_t block, + struct kernel_lb_addr *fileset) { struct logicalVolDesc *lvd; - int i, j, offset; + int i, offset; uint8_t type; struct udf_sb_info *sbi = UDF_SB(sb); struct genericPartitionMap *gpm; + uint16_t ident; + struct buffer_head *bh; + unsigned int table_len; + int ret; + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + return -EAGAIN; + BUG_ON(ident != TAG_IDENT_LVD); lvd = (struct logicalVolDesc *)bh->b_data; + table_len = le32_to_cpu(lvd->mapTableLength); + if (table_len > sb->s_blocksize - sizeof(*lvd)) { + udf_err(sb, "error loading logical volume descriptor: " + "Partition table too long (%u > %lu)\n", table_len, + sb->s_blocksize - sizeof(*lvd)); + ret = -EIO; + goto out_bh; + } - i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); - if (i != 0) - return i; + ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); + if (ret) + goto out_bh; for (i = 0, offset = 0; - i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); + i < sbi->s_partitions && offset < table_len; i++, offset += gpm->partitionMapLength) { struct udf_part_map *map = &sbi->s_partmaps[i]; gpm = (struct genericPartitionMap *) @@ -1223,12 +1448,12 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, u16 suf = le16_to_cpu(((__le16 *)upm2->partIdent. identSuffix)[0]); - if (suf == 0x0150) { + if (suf < 0x0200) { map->s_partition_type = UDF_VIRTUAL_MAP15; map->s_partition_func = udf_get_pblock_virt15; - } else if (suf == 0x0200) { + } else { map->s_partition_type = UDF_VIRTUAL_MAP20; map->s_partition_func = @@ -1237,41 +1462,52 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, } else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { - uint32_t loc; - uint16_t ident; - struct sparingTable *st; - struct sparablePartitionMap *spm = - (struct sparablePartitionMap *)gpm; - - map->s_partition_type = UDF_SPARABLE_MAP15; - map->s_type_specific.s_sparing.s_packet_len = - le16_to_cpu(spm->packetLength); - for (j = 0; j < spm->numSparingTables; j++) { - struct buffer_head *bh2; - - loc = le32_to_cpu( - spm->locSparingTable[j]); - bh2 = udf_read_tagged(sb, loc, loc, - &ident); - map->s_type_specific.s_sparing. - s_spar_map[j] = bh2; - - if (bh2 != NULL) { - st = (struct sparingTable *) - bh2->b_data; - if (ident != 0 || strncmp( - st->sparingIdent.ident, - UDF_ID_SPARING, - strlen(UDF_ID_SPARING))) { - brelse(bh2); - map->s_type_specific. - s_sparing. - s_spar_map[j] = - NULL; - } - } - } - map->s_partition_func = udf_get_pblock_spar15; + ret = udf_load_sparable_map(sb, map, + (struct sparablePartitionMap *)gpm); + if (ret < 0) + goto out_bh; + } else if (!strncmp(upm2->partIdent.ident, + UDF_ID_METADATA, + strlen(UDF_ID_METADATA))) { + struct udf_meta_data *mdata = + &map->s_type_specific.s_metadata; + struct metadataPartitionMap *mdm = + (struct metadataPartitionMap *) + &(lvd->partitionMaps[offset]); + udf_debug("Parsing Logical vol part %d type %d id=%s\n", + i, type, UDF_ID_METADATA); + + map->s_partition_type = UDF_METADATA_MAP25; + map->s_partition_func = udf_get_pblock_meta25; + + mdata->s_meta_file_loc = + le32_to_cpu(mdm->metadataFileLoc); + mdata->s_mirror_file_loc = + le32_to_cpu(mdm->metadataMirrorFileLoc); + mdata->s_bitmap_file_loc = + le32_to_cpu(mdm->metadataBitmapFileLoc); + mdata->s_alloc_unit_size = + le32_to_cpu(mdm->allocUnitSize); + mdata->s_align_unit_size = + le16_to_cpu(mdm->alignUnitSize); + if (mdm->flags & 0x01) + mdata->s_flags |= MF_DUPLICATE_MD; + + udf_debug("Metadata Ident suffix=0x%x\n", + le16_to_cpu(*(__le16 *) + mdm->partIdent.identSuffix)); + udf_debug("Metadata part num=%d\n", + le16_to_cpu(mdm->partitionNum)); + udf_debug("Metadata part alloc unit size=%d\n", + le32_to_cpu(mdm->allocUnitSize)); + udf_debug("Metadata file loc=%d\n", + le32_to_cpu(mdm->metadataFileLoc)); + udf_debug("Mirror file loc=%d\n", + le32_to_cpu(mdm->metadataMirrorFileLoc)); + udf_debug("Bitmap file loc=%d\n", + le32_to_cpu(mdm->metadataBitmapFileLoc)); + udf_debug("Flags: %d %d\n", + mdata->s_flags, mdm->flags); } else { udf_debug("Unknown ident: %s\n", upm2->partIdent.ident); @@ -1281,29 +1517,30 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, map->s_partition_num = le16_to_cpu(upm2->partitionNum); } udf_debug("Partition (%d:%d) type %d on volume %d\n", - i, map->s_partition_num, type, - map->s_volumeseqnum); + i, map->s_partition_num, type, map->s_volumeseqnum); } if (fileset) { - long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); + struct long_ad *la = (struct long_ad *)&(lvd->logicalVolContentsUse[0]); *fileset = lelb_to_cpu(la->extLocation); - udf_debug("FileSet found in LogicalVolDesc at block=%d, " - "partition=%d\n", fileset->logicalBlockNum, + udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n", + fileset->logicalBlockNum, fileset->partitionReferenceNum); } if (lvd->integritySeqExt.extLength) udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); - - return 0; + ret = 0; +out_bh: + brelse(bh); + return ret; } /* * udf_load_logicalvolint * */ -static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) +static void udf_load_logicalvolint(struct super_block *sb, struct kernel_extent_ad loc) { struct buffer_head *bh = NULL; uint16_t ident; @@ -1331,22 +1568,18 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) } /* - * udf_process_sequence - * - * PURPOSE - * Process a main/reserve volume descriptor sequence. + * Process a main/reserve volume descriptor sequence. + * @block First block of first extent of the sequence. + * @lastblock Lastblock of first extent of the sequence. + * @fileset There we store extent containing root fileset * - * PRE-CONDITIONS - * sb Pointer to _locked_ superblock. - * block First block of first extent of the sequence. - * lastblock Lastblock of first extent of the sequence. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. + * Returns <0 on error, 0 on success. -EAGAIN is special - try next descriptor + * sequence */ -static int udf_process_sequence(struct super_block *sb, long block, - long lastblock, kernel_lb_addr *fileset) +static noinline int udf_process_sequence( + struct super_block *sb, + sector_t block, sector_t lastblock, + struct kernel_lb_addr *fileset) { struct buffer_head *bh = NULL; struct udf_vds_record vds[VDS_POS_LENGTH]; @@ -1354,19 +1587,26 @@ static int udf_process_sequence(struct super_block *sb, long block, struct generic_desc *gd; struct volDescPtr *vdp; int done = 0; - int i, j; uint32_t vdsn; uint16_t ident; long next_s = 0, next_e = 0; + int ret; memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); - /* Read the main descriptor sequence */ + /* + * Read the main descriptor sequence and find which descriptors + * are in it. + */ for (; (!done && block <= lastblock); block++) { bh = udf_read_tagged(sb, block, block, &ident); - if (!bh) - break; + if (!bh) { + udf_err(sb, + "Block %llu of volume descriptor sequence is corrupted or we could not read it\n", + (unsigned long long)block); + return -EAGAIN; + } /* Process each descriptor (ISO 13346 3/8.3-8.4) */ gd = (struct generic_desc *)bh->b_data; @@ -1432,40 +1672,37 @@ static int udf_process_sequence(struct super_block *sb, long block, } brelse(bh); } - for (i = 0; i < VDS_POS_LENGTH; i++) { - if (vds[i].block) { - bh = udf_read_tagged(sb, vds[i].block, vds[i].block, - &ident); + /* + * Now read interesting descriptors again and process them + * in a suitable order + */ + if (!vds[VDS_POS_PRIMARY_VOL_DESC].block) { + udf_err(sb, "Primary Volume Descriptor not found!\n"); + return -EAGAIN; + } + ret = udf_load_pvoldesc(sb, vds[VDS_POS_PRIMARY_VOL_DESC].block); + if (ret < 0) + return ret; + + if (vds[VDS_POS_LOGICAL_VOL_DESC].block) { + ret = udf_load_logicalvol(sb, + vds[VDS_POS_LOGICAL_VOL_DESC].block, + fileset); + if (ret < 0) + return ret; + } - if (i == VDS_POS_PRIMARY_VOL_DESC) { - udf_load_pvoldesc(sb, bh); - } else if (i == VDS_POS_LOGICAL_VOL_DESC) { - if (udf_load_logicalvol(sb, bh, fileset)) { - brelse(bh); - return 1; - } - } else if (i == VDS_POS_PARTITION_DESC) { - struct buffer_head *bh2 = NULL; - if (udf_load_partdesc(sb, bh)) { - brelse(bh); - return 1; - } - for (j = vds[i].block + 1; - j < vds[VDS_POS_TERMINATING_DESC].block; - j++) { - bh2 = udf_read_tagged(sb, j, j, &ident); - gd = (struct generic_desc *)bh2->b_data; - if (ident == TAG_IDENT_PD) - if (udf_load_partdesc(sb, - bh2)) { - brelse(bh); - brelse(bh2); - return 1; - } - brelse(bh2); - } - } - brelse(bh); + if (vds[VDS_POS_PARTITION_DESC].block) { + /* + * We rescan the whole descriptor sequence to find + * partition descriptor blocks and process them. + */ + for (block = vds[VDS_POS_PARTITION_DESC].block; + block < vds[VDS_POS_TERMINATING_DESC].block; + block++) { + ret = udf_load_partdesc(sb, block); + if (ret < 0) + return ret; } } @@ -1473,155 +1710,233 @@ static int udf_process_sequence(struct super_block *sb, long block, } /* - * udf_check_valid() + * Load Volume Descriptor Sequence described by anchor in bh + * + * Returns <0 on error, 0 on success */ -static int udf_check_valid(struct super_block *sb, int novrs, int silent) +static int udf_load_sequence(struct super_block *sb, struct buffer_head *bh, + struct kernel_lb_addr *fileset) { - long block; - - if (novrs) { - udf_debug("Validity check skipped because of novrs option\n"); - return 0; - } - /* Check that it is NSR02 compliant */ - /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ - else { - block = udf_vrs(sb, silent); - if (block == -1) { - struct udf_sb_info *sbi = UDF_SB(sb); - udf_debug("Failed to read byte 32768. Assuming open " - "disc. Skipping validity check\n"); - if (!sbi->s_last_block) - sbi->s_last_block = udf_get_last_block(sb); - return 0; - } else - return !block; + struct anchorVolDescPtr *anchor; + sector_t main_s, main_e, reserve_s, reserve_e; + int ret; + + anchor = (struct anchorVolDescPtr *)bh->b_data; + + /* Locate the main sequence */ + main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); + main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); + main_e = main_e >> sb->s_blocksize_bits; + main_e += main_s; + + /* Locate the reserve sequence */ + reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); + reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); + reserve_e = reserve_e >> sb->s_blocksize_bits; + reserve_e += reserve_s; + + /* Process the main & reserve sequences */ + /* responsible for finding the PartitionDesc(s) */ + ret = udf_process_sequence(sb, main_s, main_e, fileset); + if (ret != -EAGAIN) + return ret; + udf_sb_free_partitions(sb); + ret = udf_process_sequence(sb, reserve_s, reserve_e, fileset); + if (ret < 0) { + udf_sb_free_partitions(sb); + /* No sequence was OK, return -EIO */ + if (ret == -EAGAIN) + ret = -EIO; } + return ret; } -static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) +/* + * Check whether there is an anchor block in the given block and + * load Volume Descriptor Sequence if so. + * + * Returns <0 on error, 0 on success, -EAGAIN is special - try next anchor + * block + */ +static int udf_check_anchor_block(struct super_block *sb, sector_t block, + struct kernel_lb_addr *fileset) { - struct anchorVolDescPtr *anchor; - uint16_t ident; struct buffer_head *bh; - long main_s, main_e, reserve_s, reserve_e; - int i, j; - struct udf_sb_info *sbi; + uint16_t ident; + int ret; - if (!sb) - return 1; - sbi = UDF_SB(sb); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && + udf_fixed_to_variable(block) >= + sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) + return -EAGAIN; + + bh = udf_read_tagged(sb, block, block, &ident); + if (!bh) + return -EAGAIN; + if (ident != TAG_IDENT_AVDP) { + brelse(bh); + return -EAGAIN; + } + ret = udf_load_sequence(sb, bh, fileset); + brelse(bh); + return ret; +} - for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { - if (!sbi->s_anchor[i]) +/* + * Search for an anchor volume descriptor pointer. + * + * Returns < 0 on error, 0 on success. -EAGAIN is special - try next set + * of anchors. + */ +static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, + struct kernel_lb_addr *fileset) +{ + sector_t last[6]; + int i; + struct udf_sb_info *sbi = UDF_SB(sb); + int last_count = 0; + int ret; + + /* First try user provided anchor */ + if (sbi->s_anchor) { + ret = udf_check_anchor_block(sb, sbi->s_anchor, fileset); + if (ret != -EAGAIN) + return ret; + } + /* + * according to spec, anchor is in either: + * block 256 + * lastblock-256 + * lastblock + * however, if the disc isn't closed, it could be 512. + */ + ret = udf_check_anchor_block(sb, sbi->s_session + 256, fileset); + if (ret != -EAGAIN) + return ret; + /* + * The trouble is which block is the last one. Drives often misreport + * this so we try various possibilities. + */ + last[last_count++] = *lastblock; + if (*lastblock >= 1) + last[last_count++] = *lastblock - 1; + last[last_count++] = *lastblock + 1; + if (*lastblock >= 2) + last[last_count++] = *lastblock - 2; + if (*lastblock >= 150) + last[last_count++] = *lastblock - 150; + if (*lastblock >= 152) + last[last_count++] = *lastblock - 152; + + for (i = 0; i < last_count; i++) { + if (last[i] >= sb->s_bdev->bd_inode->i_size >> + sb->s_blocksize_bits) continue; - bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], - &ident); - if (!bh) + ret = udf_check_anchor_block(sb, last[i], fileset); + if (ret != -EAGAIN) { + if (!ret) + *lastblock = last[i]; + return ret; + } + if (last[i] < 256) continue; + ret = udf_check_anchor_block(sb, last[i] - 256, fileset); + if (ret != -EAGAIN) { + if (!ret) + *lastblock = last[i]; + return ret; + } + } - anchor = (struct anchorVolDescPtr *)bh->b_data; - - /* Locate the main sequence */ - main_s = le32_to_cpu(anchor->mainVolDescSeqExt.extLocation); - main_e = le32_to_cpu(anchor->mainVolDescSeqExt.extLength); - main_e = main_e >> sb->s_blocksize_bits; - main_e += main_s; + /* Finally try block 512 in case media is open */ + return udf_check_anchor_block(sb, sbi->s_session + 512, fileset); +} - /* Locate the reserve sequence */ - reserve_s = le32_to_cpu( - anchor->reserveVolDescSeqExt.extLocation); - reserve_e = le32_to_cpu( - anchor->reserveVolDescSeqExt.extLength); - reserve_e = reserve_e >> sb->s_blocksize_bits; - reserve_e += reserve_s; +/* + * Find an anchor volume descriptor and load Volume Descriptor Sequence from + * area specified by it. The function expects sbi->s_lastblock to be the last + * block on the media. + * + * Return <0 on error, 0 if anchor found. -EAGAIN is special meaning anchor + * was not found. + */ +static int udf_find_anchor(struct super_block *sb, + struct kernel_lb_addr *fileset) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + sector_t lastblock = sbi->s_last_block; + int ret; - brelse(bh); + ret = udf_scan_anchors(sb, &lastblock, fileset); + if (ret != -EAGAIN) + goto out; - /* Process the main & reserve sequences */ - /* responsible for finding the PartitionDesc(s) */ - if (!(udf_process_sequence(sb, main_s, main_e, - fileset) && - udf_process_sequence(sb, reserve_s, reserve_e, - fileset))) - break; - } + /* No anchor found? Try VARCONV conversion of block numbers */ + UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); + lastblock = udf_variable_to_fixed(sbi->s_last_block); + /* Firstly, we try to not convert number of the last block */ + ret = udf_scan_anchors(sb, &lastblock, fileset); + if (ret != -EAGAIN) + goto out; - if (i == ARRAY_SIZE(sbi->s_anchor)) { - udf_debug("No Anchor block found\n"); - return 1; + lastblock = sbi->s_last_block; + /* Secondly, we try with converted number of the last block */ + ret = udf_scan_anchors(sb, &lastblock, fileset); + if (ret < 0) { + /* VARCONV didn't help. Clear it. */ + UDF_CLEAR_FLAG(sb, UDF_FLAG_VARCONV); } - udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); - - for (i = 0; i < sbi->s_partitions; i++) { - kernel_lb_addr uninitialized_var(ino); - struct udf_part_map *map = &sbi->s_partmaps[i]; - switch (map->s_partition_type) { - case UDF_VIRTUAL_MAP15: - case UDF_VIRTUAL_MAP20: - if (!sbi->s_last_block) { - sbi->s_last_block = udf_get_last_block(sb); - udf_find_anchor(sb); - } - - if (!sbi->s_last_block) { - udf_debug("Unable to determine Lastblock (For " - "Virtual Partition)\n"); - return 1; - } +out: + if (ret == 0) + sbi->s_last_block = lastblock; + return ret; +} - for (j = 0; j < sbi->s_partitions; j++) { - struct udf_part_map *map2 = &sbi->s_partmaps[j]; - if (j != i && - map->s_volumeseqnum == - map2->s_volumeseqnum && - map->s_partition_num == - map2->s_partition_num) { - ino.partitionReferenceNum = j; - ino.logicalBlockNum = - sbi->s_last_block - - map2->s_partition_root; - break; - } - } +/* + * Check Volume Structure Descriptor, find Anchor block and load Volume + * Descriptor Sequence. + * + * Returns < 0 on error, 0 on success. -EAGAIN is special meaning anchor + * block was not found. + */ +static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, + int silent, struct kernel_lb_addr *fileset) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + loff_t nsr_off; + int ret; - if (j == sbi->s_partitions) - return 1; - - sbi->s_vat_inode = udf_iget(sb, ino); - if (!sbi->s_vat_inode) - return 1; - - if (map->s_partition_type == UDF_VIRTUAL_MAP15) { - map->s_type_specific.s_virtual.s_start_offset = - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - 36) >> 2; - } else if (map->s_partition_type == UDF_VIRTUAL_MAP20) { - uint32_t pos; - struct virtualAllocationTable20 *vat20; - - pos = udf_block_map(sbi->s_vat_inode, 0); - bh = sb_bread(sb, pos); - if (!bh) - return 1; - vat20 = (struct virtualAllocationTable20 *) - bh->b_data + - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_start_offset = - le16_to_cpu(vat20->lengthHeader) + - udf_ext0_offset(sbi->s_vat_inode); - map->s_type_specific.s_virtual.s_num_entries = - (sbi->s_vat_inode->i_size - - map->s_type_specific.s_virtual. - s_start_offset) >> 2; - brelse(bh); - } - map->s_partition_root = udf_get_pblock(sb, 0, i, 0); - map->s_partition_len = - sbi->s_partmaps[ino.partitionReferenceNum]. - s_partition_len; + if (!sb_set_blocksize(sb, uopt->blocksize)) { + if (!silent) + udf_warn(sb, "Bad block size\n"); + return -EINVAL; + } + sbi->s_last_block = uopt->lastblock; + if (!uopt->novrs) { + /* Check that it is NSR02 compliant */ + nsr_off = udf_check_vsd(sb); + if (!nsr_off) { + if (!silent) + udf_warn(sb, "No VRS found\n"); + return 0; } + if (nsr_off == -1) + udf_debug("Failed to read sector at offset %d. " + "Assuming open disc. Skipping validity " + "check\n", VSD_FIRST_SECTOR_OFFSET); + if (!sbi->s_last_block) + sbi->s_last_block = udf_get_last_block(sb); + } else { + udf_debug("Validity check skipped because of novrs option\n"); + } + + /* Look for anchor block and load Volume Descriptor Sequence */ + sbi->s_anchor = uopt->anchor; + ret = udf_find_anchor(sb, fileset); + if (ret < 0) { + if (!silent && ret == -EAGAIN) + udf_warn(sb, "No anchor found\n"); + return ret; } return 0; } @@ -1630,112 +1945,120 @@ static void udf_open_lvid(struct super_block *sb) { struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; - if (bh) { - kernel_timestamp cpu_time; - struct logicalVolIntegrityDesc *lvid = - (struct logicalVolIntegrityDesc *)bh->b_data; - struct logicalVolIntegrityDescImpUse *lvidiu = - udf_sb_lvidiu(sbi); - - lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - lvid->recordingDateAndTime = cpu_to_lets(cpu_time); - lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; + struct logicalVolIntegrityDesc *lvid; + struct logicalVolIntegrityDescImpUse *lvidiu; - lvid->descTag.descCRC = cpu_to_le16( - udf_crc((char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength), - 0)); + if (!bh) + return; + lvid = (struct logicalVolIntegrityDesc *)bh->b_data; + lvidiu = udf_sb_lvidiu(sb); + if (!lvidiu) + return; - lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); - mark_buffer_dirty(bh); - } + mutex_lock(&sbi->s_alloc_mutex); + lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, + CURRENT_TIME); + lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN); + + lvid->descTag.descCRC = cpu_to_le16( + crc_itu_t(0, (char *)lvid + sizeof(struct tag), + le16_to_cpu(lvid->descTag.descCRCLength))); + + lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + mark_buffer_dirty(bh); + sbi->s_lvid_dirty = 0; + mutex_unlock(&sbi->s_alloc_mutex); + /* Make opening of filesystem visible on the media immediately */ + sync_dirty_buffer(bh); } static void udf_close_lvid(struct super_block *sb) { - kernel_timestamp cpu_time; struct udf_sb_info *sbi = UDF_SB(sb); struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; + struct logicalVolIntegrityDescImpUse *lvidiu; if (!bh) return; - lvid = (struct logicalVolIntegrityDesc *)bh->b_data; + lvidiu = udf_sb_lvidiu(sb); + if (!lvidiu) + return; - if (lvid->integrityType == LVID_INTEGRITY_TYPE_OPEN) { - struct logicalVolIntegrityDescImpUse *lvidiu = - udf_sb_lvidiu(sbi); - lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - lvid->recordingDateAndTime = cpu_to_lets(cpu_time); - if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) - lvidiu->maxUDFWriteRev = - cpu_to_le16(UDF_MAX_WRITE_VERSION); - if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) - lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); - if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) - lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); - lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); - - lvid->descTag.descCRC = cpu_to_le16( - udf_crc((char *)lvid + sizeof(tag), - le16_to_cpu(lvid->descTag.descCRCLength), - 0)); - - lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); - mark_buffer_dirty(bh); - } + mutex_lock(&sbi->s_alloc_mutex); + lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; + lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); + if (UDF_MAX_WRITE_VERSION > le16_to_cpu(lvidiu->maxUDFWriteRev)) + lvidiu->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); + if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFReadRev)) + lvidiu->minUDFReadRev = cpu_to_le16(sbi->s_udfrev); + if (sbi->s_udfrev > le16_to_cpu(lvidiu->minUDFWriteRev)) + lvidiu->minUDFWriteRev = cpu_to_le16(sbi->s_udfrev); + lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); + + lvid->descTag.descCRC = cpu_to_le16( + crc_itu_t(0, (char *)lvid + sizeof(struct tag), + le16_to_cpu(lvid->descTag.descCRCLength))); + + lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + /* + * We set buffer uptodate unconditionally here to avoid spurious + * warnings from mark_buffer_dirty() when previous EIO has marked + * the buffer as !uptodate + */ + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + sbi->s_lvid_dirty = 0; + mutex_unlock(&sbi->s_alloc_mutex); + /* Make closing of filesystem visible on the media immediately */ + sync_dirty_buffer(bh); } -static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) +u64 lvid_get_unique_id(struct super_block *sb) { - int i; - int nr_groups = bitmap->s_nr_groups; - int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * - nr_groups); + struct buffer_head *bh; + struct udf_sb_info *sbi = UDF_SB(sb); + struct logicalVolIntegrityDesc *lvid; + struct logicalVolHeaderDesc *lvhd; + u64 uniqueID; + u64 ret; - for (i = 0; i < nr_groups; i++) - if (bitmap->s_block_bitmap[i]) - brelse(bitmap->s_block_bitmap[i]); + bh = sbi->s_lvid_bh; + if (!bh) + return 0; - if (size <= PAGE_SIZE) - kfree(bitmap); - else - vfree(bitmap); + lvid = (struct logicalVolIntegrityDesc *)bh->b_data; + lvhd = (struct logicalVolHeaderDesc *)lvid->logicalVolContentsUse; + + mutex_lock(&sbi->s_alloc_mutex); + ret = uniqueID = le64_to_cpu(lvhd->uniqueID); + if (!(++uniqueID & 0xFFFFFFFF)) + uniqueID += 16; + lvhd->uniqueID = cpu_to_le64(uniqueID); + mutex_unlock(&sbi->s_alloc_mutex); + mark_buffer_dirty(bh); + + return ret; } -/* - * udf_read_super - * - * PURPOSE - * Complete the specified super block. - * - * PRE-CONDITIONS - * sb Pointer to superblock to complete - never NULL. - * sb->s_dev Device to read suberblock from. - * options Pointer to mount options. - * silent Silent flag. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ static int udf_fill_super(struct super_block *sb, void *options, int silent) { - int i; + int ret = -EINVAL; struct inode *inode = NULL; struct udf_options uopt; - kernel_lb_addr rootdir, fileset; + struct kernel_lb_addr rootdir, fileset; struct udf_sb_info *sbi; uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); - uopt.uid = -1; - uopt.gid = -1; + uopt.uid = INVALID_UID; + uopt.gid = INVALID_GID; uopt.umask = 0; + uopt.fmode = UDF_INVALID_MODE; + uopt.dmode = UDF_INVALID_MODE; sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL); if (!sbi) @@ -1750,8 +2073,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) if (uopt.flags & (1 << UDF_FLAG_UTF8) && uopt.flags & (1 << UDF_FLAG_NLS_MAP)) { - udf_error(sb, "udf_read_super", - "utf8 cannot be combined with iocharset\n"); + udf_err(sb, "utf8 cannot be combined with iocharset\n"); goto error_out; } #ifdef CONFIG_UDF_NLS @@ -1773,11 +2095,10 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sbi->s_uid = uopt.uid; sbi->s_gid = uopt.gid; sbi->s_umask = uopt.umask; + sbi->s_fmode = uopt.fmode; + sbi->s_dmode = uopt.dmode; sbi->s_nls_map = uopt.nls_map; - - /* Set the block size for all transfers */ - if (!udf_set_blocksize(sb, uopt.blocksize)) - goto error_out; + rwlock_init(&sbi->s_cred_lock); if (uopt.session == 0xFFFFFFFF) sbi->s_session = udf_get_last_session(sb); @@ -1786,28 +2107,33 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) udf_debug("Multi-session=%d\n", sbi->s_session); - sbi->s_last_block = uopt.lastblock; - sbi->s_anchor[0] = sbi->s_anchor[1] = 0; - sbi->s_anchor[2] = uopt.anchor; - sbi->s_anchor[3] = 256; - - if (udf_check_valid(sb, uopt.novrs, silent)) { - /* read volume recognition sequences */ - printk(KERN_WARNING "UDF-fs: No VRS found\n"); - goto error_out; - } - - udf_find_anchor(sb); - /* Fill in the rest of the superblock */ sb->s_op = &udf_sb_ops; - sb->dq_op = NULL; - sb->s_dirt = 0; + sb->s_export_op = &udf_export_ops; + sb->s_magic = UDF_SUPER_MAGIC; sb->s_time_gran = 1000; - if (udf_load_partition(sb, &fileset)) { - printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); + if (uopt.flags & (1 << UDF_FLAG_BLOCKSIZE_SET)) { + ret = udf_load_vrs(sb, &uopt, silent, &fileset); + } else { + uopt.blocksize = bdev_logical_block_size(sb->s_bdev); + ret = udf_load_vrs(sb, &uopt, silent, &fileset); + if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) { + if (!silent) + pr_notice("Rescanning with blocksize %d\n", + UDF_DEFAULT_BLOCKSIZE); + brelse(sbi->s_lvid_bh); + sbi->s_lvid_bh = NULL; + uopt.blocksize = UDF_DEFAULT_BLOCKSIZE; + ret = udf_load_vrs(sb, &uopt, silent, &fileset); + } + } + if (ret < 0) { + if (ret == -EAGAIN) { + udf_warn(sb, "No partition found (1)\n"); + ret = -EINVAL; + } goto error_out; } @@ -1815,20 +2141,27 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) if (sbi->s_lvid_bh) { struct logicalVolIntegrityDescImpUse *lvidiu = - udf_sb_lvidiu(sbi); - uint16_t minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev); - uint16_t minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev); - /* uint16_t maxUDFWriteRev = - le16_to_cpu(lvidiu->maxUDFWriteRev); */ + udf_sb_lvidiu(sb); + uint16_t minUDFReadRev; + uint16_t minUDFWriteRev; + if (!lvidiu) { + ret = -EINVAL; + goto error_out; + } + minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev); + minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev); if (minUDFReadRev > UDF_MAX_READ_VERSION) { - printk(KERN_ERR "UDF-fs: minUDFReadRev=%x " - "(max is %x)\n", - le16_to_cpu(lvidiu->minUDFReadRev), - UDF_MAX_READ_VERSION); + udf_err(sb, "minUDFReadRev=%x (max is %x)\n", + minUDFReadRev, + UDF_MAX_READ_VERSION); + ret = -EINVAL; + goto error_out; + } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION && + !(sb->s_flags & MS_RDONLY)) { + ret = -EACCES; goto error_out; - } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) - sb->s_flags |= MS_RDONLY; + } sbi->s_udfrev = minUDFWriteRev; @@ -1839,29 +2172,31 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) } if (!sbi->s_partitions) { - printk(KERN_WARNING "UDF-fs: No partition found (2)\n"); + udf_warn(sb, "No partition found (2)\n"); + ret = -EINVAL; goto error_out; } if (sbi->s_partmaps[sbi->s_partition].s_partition_flags & - UDF_PART_FLAG_READ_ONLY) { - printk(KERN_NOTICE "UDF-fs: Partition marked readonly; " - "forcing readonly mount\n"); - sb->s_flags |= MS_RDONLY; + UDF_PART_FLAG_READ_ONLY && + !(sb->s_flags & MS_RDONLY)) { + ret = -EACCES; + goto error_out; } if (udf_find_fileset(sb, &fileset, &rootdir)) { - printk(KERN_WARNING "UDF-fs: No fileset found\n"); + udf_warn(sb, "No fileset found\n"); + ret = -EINVAL; goto error_out; } if (!silent) { - kernel_timestamp ts; - udf_time_to_stamp(&ts, sbi->s_record_time); - udf_info("UDF: Mounting volume '%s', " - "timestamp %04u/%02u/%02u %02u:%02u (%x)\n", - sbi->s_volume_ident, ts.year, ts.month, ts.day, - ts.hour, ts.minute, ts.typeAndTimezone); + struct timestamp ts; + udf_time_to_disk_stamp(&ts, sbi->s_record_time); + udf_info("Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n", + sbi->s_volume_ident, + le16_to_cpu(ts.year), ts.month, ts.day, + ts.hour, ts.minute, le16_to_cpu(ts.typeAndTimezone)); } if (!(sb->s_flags & MS_RDONLY)) udf_open_lvid(sb); @@ -1869,42 +2204,28 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) /* Assign the root inode */ /* assign inodes by physical block number */ /* perhaps it's not extensible enough, but for now ... */ - inode = udf_iget(sb, rootdir); + inode = udf_iget(sb, &rootdir); if (!inode) { - printk(KERN_ERR "UDF-fs: Error in udf_iget, block=%d, " - "partition=%d\n", + udf_err(sb, "Error in udf_iget, block=%d, partition=%d\n", rootdir.logicalBlockNum, rootdir.partitionReferenceNum); + ret = -EIO; goto error_out; } /* Allocate a dentry for the root inode */ - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) { - printk(KERN_ERR "UDF-fs: Couldn't allocate root dentry\n"); - iput(inode); + udf_err(sb, "Couldn't allocate root dentry\n"); + ret = -ENOMEM; goto error_out; } sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_max_links = UDF_MAX_LINKS; return 0; error_out: if (sbi->s_vat_inode) iput(sbi->s_vat_inode); - if (sbi->s_partitions) { - struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) - iput(map->s_uspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) - iput(map->s_fspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) - udf_sb_free_bitmap(map->s_uspace.s_bitmap); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) - udf_sb_free_bitmap(map->s_fspace.s_bitmap); - if (map->s_partition_type == UDF_SPARABLE_MAP15) - for (i = 0; i < 4; i++) - brelse(map->s_type_specific.s_sparing. - s_spar_map[i]); - } #ifdef CONFIG_UDF_NLS if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) unload_nls(sbi->s_nls_map); @@ -1912,78 +2233,53 @@ error_out: if (!(sb->s_flags & MS_RDONLY)) udf_close_lvid(sb); brelse(sbi->s_lvid_bh); - - kfree(sbi->s_partmaps); + udf_sb_free_partitions(sb); kfree(sbi); sb->s_fs_info = NULL; - return -EINVAL; + return ret; } -void udf_error(struct super_block *sb, const char *function, - const char *fmt, ...) +void _udf_err(struct super_block *sb, const char *function, + const char *fmt, ...) { + struct va_format vaf; va_list args; - if (!(sb->s_flags & MS_RDONLY)) { - /* mark sb error */ - sb->s_dirt = 1; - } va_start(args, fmt); - vsnprintf(error_buf, sizeof(error_buf), fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + pr_err("error (device %s): %s: %pV", sb->s_id, function, &vaf); + va_end(args); - printk(KERN_CRIT "UDF-fs error (device %s): %s: %s\n", - sb->s_id, function, error_buf); } -void udf_warning(struct super_block *sb, const char *function, - const char *fmt, ...) +void _udf_warn(struct super_block *sb, const char *function, + const char *fmt, ...) { + struct va_format vaf; va_list args; va_start(args, fmt); - vsnprintf(error_buf, sizeof(error_buf), fmt, args); + + vaf.fmt = fmt; + vaf.va = &args; + + pr_warn("warning (device %s): %s: %pV", sb->s_id, function, &vaf); + va_end(args); - printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n", - sb->s_id, function, error_buf); } -/* - * udf_put_super - * - * PURPOSE - * Prepare for destruction of the superblock. - * - * DESCRIPTION - * Called before the filesystem is unmounted. - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ static void udf_put_super(struct super_block *sb) { - int i; struct udf_sb_info *sbi; sbi = UDF_SB(sb); + if (sbi->s_vat_inode) iput(sbi->s_vat_inode); - if (sbi->s_partitions) { - struct udf_part_map *map = &sbi->s_partmaps[sbi->s_partition]; - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) - iput(map->s_uspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) - iput(map->s_fspace.s_table); - if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) - udf_sb_free_bitmap(map->s_uspace.s_bitmap); - if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) - udf_sb_free_bitmap(map->s_fspace.s_bitmap); - if (map->s_partition_type == UDF_SPARABLE_MAP15) - for (i = 0; i < 4; i++) - brelse(map->s_type_specific.s_sparing. - s_spar_map[i]); - } #ifdef CONFIG_UDF_NLS if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) unload_nls(sbi->s_nls_map); @@ -1991,35 +2287,37 @@ static void udf_put_super(struct super_block *sb) if (!(sb->s_flags & MS_RDONLY)) udf_close_lvid(sb); brelse(sbi->s_lvid_bh); - kfree(sbi->s_partmaps); + udf_sb_free_partitions(sb); kfree(sb->s_fs_info); sb->s_fs_info = NULL; } -/* - * udf_stat_fs - * - * PURPOSE - * Return info about the filesystem. - * - * DESCRIPTION - * Called by sys_statfs() - * - * HISTORY - * July 1, 1997 - Andrew E. Mileski - * Written, tested, and released. - */ +static int udf_sync_fs(struct super_block *sb, int wait) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + + mutex_lock(&sbi->s_alloc_mutex); + if (sbi->s_lvid_dirty) { + /* + * Blockdevice will be synced later so we don't have to submit + * the buffer for IO + */ + mark_buffer_dirty(sbi->s_lvid_bh); + sbi->s_lvid_dirty = 0; + } + mutex_unlock(&sbi->s_alloc_mutex); + + return 0; +} + static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; struct udf_sb_info *sbi = UDF_SB(sb); struct logicalVolIntegrityDescImpUse *lvidiu; + u64 id = huge_encode_dev(sb->s_bdev->bd_dev); - if (sbi->s_lvid_bh != NULL) - lvidiu = udf_sb_lvidiu(sbi); - else - lvidiu = NULL; - + lvidiu = udf_sb_lvidiu(sb); buf->f_type = UDF_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len; @@ -2029,16 +2327,13 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) le32_to_cpu(lvidiu->numDirs)) : 0) + buf->f_bfree; buf->f_ffree = buf->f_bfree; - /* __kernel_fsid_t f_fsid */ buf->f_namelen = UDF_NAME_LEN - 2; + buf->f_fsid.val[0] = (u32)id; + buf->f_fsid.val[1] = (u32)(id >> 32); return 0; } -static unsigned char udf_bitmap_lookup[16] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 -}; - static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap) { @@ -2046,25 +2341,22 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, unsigned int accum = 0; int index; int block = 0, newblock; - kernel_lb_addr loc; + struct kernel_lb_addr loc; uint32_t bytes; - uint8_t value; uint8_t *ptr; uint16_t ident; struct spaceBitmapDesc *bm; - lock_kernel(); - loc.logicalBlockNum = bitmap->s_extPosition; loc.partitionReferenceNum = UDF_SB(sb)->s_partition; - bh = udf_read_ptagged(sb, loc, 0, &ident); + bh = udf_read_ptagged(sb, &loc, 0, &ident); if (!bh) { - printk(KERN_ERR "udf: udf_count_free failed\n"); + udf_err(sb, "udf_count_free failed\n"); goto out; } else if (ident != TAG_IDENT_SBD) { brelse(bh); - printk(KERN_ERR "udf: udf_count_free failed\n"); + udf_err(sb, "udf_count_free failed\n"); goto out; } @@ -2074,16 +2366,13 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, ptr = (uint8_t *)bh->b_data; while (bytes > 0) { - while ((bytes > 0) && (index < sb->s_blocksize)) { - value = ptr[index]; - accum += udf_bitmap_lookup[value & 0x0f]; - accum += udf_bitmap_lookup[value >> 4]; - index++; - bytes--; - } + u32 cur_bytes = min_t(u32, bytes, sb->s_blocksize - index); + accum += bitmap_weight((const unsigned long *)(ptr + index), + cur_bytes * 8); + bytes -= cur_bytes; if (bytes) { brelse(bh); - newblock = udf_get_lb_pblock(sb, loc, ++block); + newblock = udf_get_lb_pblock(sb, &loc, ++block); bh = udf_tread(sb, newblock); if (!bh) { udf_debug("read failed\n"); @@ -2094,10 +2383,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, } } brelse(bh); - out: - unlock_kernel(); - return accum; } @@ -2106,12 +2392,11 @@ static unsigned int udf_count_free_table(struct super_block *sb, { unsigned int accum = 0; uint32_t elen; - kernel_lb_addr eloc; + struct kernel_lb_addr eloc; int8_t etype; struct extent_position epos; - lock_kernel(); - + mutex_lock(&UDF_SB(sb)->s_alloc_mutex); epos.block = UDF_I(table)->i_location; epos.offset = sizeof(struct unallocSpaceEntry); epos.bh = NULL; @@ -2120,8 +2405,7 @@ static unsigned int udf_count_free_table(struct super_block *sb, accum += (elen >> table->i_sb->s_blocksize_bits); brelse(epos.bh); - - unlock_kernel(); + mutex_unlock(&UDF_SB(sb)->s_alloc_mutex); return accum; } |
