X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=fs%2Fudf%2Fsuper.c;h=4d2ecee1970b5313ad5c56cbd293bf58d9a7286b;hb=56774805d5eeecd3f1fb700603e593a35dc523c8;hp=4360c7a05743727a3f7b94753057a5a831eb2b0b;hpb=fe2520094d88018423dfc42b3cd0015f74e8adea;p=linux-2.6-omap-h63xx.git diff --git a/fs/udf/super.c b/fs/udf/super.c index 4360c7a0574..4d2ecee1970 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -33,8 +33,8 @@ * 10/17/98 added freespace count for "df" * 11/11/98 gr added novrs option * 11/26/98 dgb added fileset,anchor mount options - * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced vol descs - * rewrote option handling based on isofs + * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced + * vol descs. rewrote option handling based on isofs * 12/20/98 find the free space bitmap (if it exists) */ @@ -52,9 +52,12 @@ #include #include #include +#include +#include +#include +#include #include -#include #include "udf_sb.h" #include "udf_i.h" @@ -70,6 +73,8 @@ #define VDS_POS_TERMINATING_DESC 6 #define VDS_POS_LENGTH 7 +#define UDF_DEFAULT_BLOCKSIZE 2048 + static char error_buf[1024]; /* These are the "meat" - everything else is stuffing */ @@ -94,6 +99,19 @@ 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 void udf_error(struct super_block *sb, const char *function, + const char *fmt, ...); + +struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) +{ + 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); + return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]); +} /* UDF filesystem type */ static int udf_get_sb(struct file_system_type *fs_type, @@ -116,7 +134,7 @@ static struct kmem_cache *udf_inode_cachep; static struct inode *udf_alloc_inode(struct super_block *sb) { struct udf_inode_info *ei; - ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, GFP_KERNEL); + ei = kmem_cache_alloc(udf_inode_cachep, GFP_KERNEL); if (!ei) return NULL; @@ -170,6 +188,7 @@ static const struct super_operations udf_sb_ops = { .write_super = udf_write_super, .statfs = udf_statfs, .remount_fs = udf_remount_fs, + .show_options = udf_show_options, }; struct udf_options { @@ -218,6 +237,79 @@ static void __exit exit_udf_fs(void) module_init(init_udf_fs) module_exit(exit_udf_fs) +static int udf_sb_alloc_partition_maps(struct super_block *sb, u32 count) +{ + struct udf_sb_info *sbi = UDF_SB(sb); + + 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); + sbi->s_partitions = 0; + return -ENOMEM; + } + + sbi->s_partitions = count; + return 0; +} + +static int udf_show_options(struct seq_file *seq, struct vfsmount *mnt) +{ + struct super_block *sb = mnt->mnt_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) + seq_printf(seq, ",bs=%lu", sb->s_blocksize); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE)) + seq_puts(seq, ",unhide"); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE)) + seq_puts(seq, ",undelete"); + if (!UDF_QUERY_FLAG(sb, UDF_FLAG_USE_AD_IN_ICB)) + seq_puts(seq, ",noadinicb"); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_USE_SHORT_AD)) + seq_puts(seq, ",shortad"); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_FORGET)) + seq_puts(seq, ",uid=forget"); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_UID_IGNORE)) + seq_puts(seq, ",uid=ignore"); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_FORGET)) + seq_puts(seq, ",gid=forget"); + 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); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_GID_SET)) + seq_printf(seq, ",gid=%u", sbi->s_gid); + if (sbi->s_umask != 0) + seq_printf(seq, ",umask=%o", sbi->s_umask); + 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]); + /* + * volume, partition, fileset and rootdir seem to be ignored + * currently + */ + if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) + seq_puts(seq, ",utf8"); + if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP) && sbi->s_nls_map) + seq_printf(seq, ",iocharset=%s", sbi->s_nls_map->charset); + + return 0; +} + /* * udf_parse_options * @@ -310,13 +402,14 @@ static match_table_t tokens = { {Opt_err, NULL} }; -static int udf_parse_options(char *options, struct udf_options *uopt) +static int udf_parse_options(char *options, struct udf_options *uopt, + bool remount) { char *p; int option; uopt->novrs = 0; - uopt->blocksize = 2048; + uopt->blocksize = UDF_DEFAULT_BLOCKSIZE; uopt->partition = 0xFFFF; uopt->session = 0xFFFFFFFF; uopt->lastblock = 0; @@ -386,11 +479,15 @@ static int udf_parse_options(char *options, struct udf_options *uopt) if (match_int(args, &option)) return 0; uopt->session = option; + if (!remount) + uopt->flags |= (1 << UDF_FLAG_SESSION_SET); break; case Opt_lastblock: if (match_int(args, &option)) return 0; uopt->lastblock = option; + if (!remount) + uopt->flags |= (1 << UDF_FLAG_LASTBLOCK_SET); break; case Opt_anchor: if (match_int(args, &option)) @@ -447,7 +544,7 @@ static int udf_parse_options(char *options, struct udf_options *uopt) return 1; } -void udf_write_super(struct super_block *sb) +static void udf_write_super(struct super_block *sb) { lock_kernel(); @@ -461,22 +558,23 @@ void udf_write_super(struct super_block *sb) 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); - uopt.flags = UDF_SB(sb)->s_flags; - uopt.uid = UDF_SB(sb)->s_uid; - uopt.gid = UDF_SB(sb)->s_gid; - uopt.umask = UDF_SB(sb)->s_umask; + uopt.flags = sbi->s_flags; + uopt.uid = sbi->s_uid; + uopt.gid = sbi->s_gid; + uopt.umask = sbi->s_umask; - if (!udf_parse_options(options, &uopt)) + if (!udf_parse_options(options, &uopt, true)) return -EINVAL; - UDF_SB(sb)->s_flags = uopt.flags; - UDF_SB(sb)->s_uid = uopt.uid; - UDF_SB(sb)->s_gid = uopt.gid; - UDF_SB(sb)->s_umask = uopt.umask; + sbi->s_flags = uopt.flags; + sbi->s_uid = uopt.uid; + sbi->s_gid = uopt.gid; + sbi->s_umask = uopt.umask; - if (UDF_SB_LVIDBH(sb)) { - int write_rev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev); + 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; } @@ -491,44 +589,6 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) return 0; } -/* - * 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. - * 0 Blocksize is valid. - * 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) { struct volStructDesc *vsd = NULL; @@ -538,17 +598,19 @@ static int udf_vrs(struct super_block *sb, int silent) 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 sectorsize = sb->s_blocksize; - sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits); + 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); @@ -561,47 +623,52 @@ static int udf_vrs(struct super_block *sb, int silent) /* Look for ISO descriptors */ vsd = (struct volStructDesc *)(bh->b_data + - (sector & (sb->s_blocksize - 1))); + (sector & (sb->s_blocksize - 1))); if (vsd->stdIdent[0] == 0) { brelse(bh); break; - } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) { + } else 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", vsd->structType); break; } - } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) { - } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN)) { + } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, + VSD_STD_ID_LEN)) + ; /* nothing */ + else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, + VSD_STD_ID_LEN)) { brelse(bh); break; - } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) { + } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, + VSD_STD_ID_LEN)) nsr02 = sector; - } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) { + else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, + VSD_STD_ID_LEN)) nsr03 = sector; - } brelse(bh); } @@ -609,7 +676,7 @@ static int udf_vrs(struct super_block *sb, int silent) return nsr03; else if (nsr02) return nsr02; - else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768) + else if (sector - (sbi->s_session << sb->s_blocksize_bits) == 32768) return -1; else return 0; @@ -634,11 +701,15 @@ static int udf_vrs(struct super_block *sb, int silent) */ static void udf_find_anchor(struct super_block *sb) { - int lastblock = UDF_SB_LASTBLOCK(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); @@ -658,57 +729,83 @@ static void udf_find_anchor(struct super_block *sb) * however, if the disc isn't closed, it could be 512 */ for (i = 0; !lastblock && i < ARRAY_SIZE(last); i++) { - if (last[i] < 0 || !(bh = sb_bread(sb, last[i]))) { - ident = location = 0; - } else { - ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); - location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); - brelse(bh); + 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] - UDF_SB_SESSION(sb)) { - lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb); - UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb); - } else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) { + 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_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb); - UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb); + 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", + udf_debug("Anchor found at block %d, " + "location mismatch %d.\n", last[i], location); } - } else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE) { + } else if (ident == TAG_IDENT_FE || + ident == TAG_IDENT_EFE) { lastblock = last[i]; - UDF_SB_ANCHOR(sb)[3] = 512; + sbi->s_anchor[3] = 512; } else { - if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256))) { - ident = location = 0; - } else { - ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); - location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); - brelse(bh); + 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 - UDF_SB_SESSION(sb)) { + location == last[i] - 256 - + sbi->s_session) { lastblock = last[i]; - UDF_SB_ANCHOR(sb)[1] = last[i] - 256; + sbi->s_anchor[1] = last[i] - 256; } else { - if (last[i] < 312 + UDF_SB_SESSION(sb) || - !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb)))) { - ident = location = 0; - } else { - ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); - location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); - brelse(bh); + 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); + UDF_SET_FLAG(sb, + UDF_FLAG_VARCONV); lastblock = udf_variable_to_fixed(last[i]); - UDF_SB_ANCHOR(sb)[1] = lastblock - 256; + sbi->s_anchor[1] = lastblock - 256; } } } @@ -716,10 +813,12 @@ static void udf_find_anchor(struct super_block *sb) } if (!lastblock) { - /* We havn't found the lastblock. check 312 */ - if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb)))) { - ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); - location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); + /* 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) @@ -727,29 +826,33 @@ static void udf_find_anchor(struct super_block *sb) } } - for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) { - if (UDF_SB_ANCHOR(sb)[i]) { - if (!(bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i], - UDF_SB_ANCHOR(sb)[i], &ident))) { - UDF_SB_ANCHOR(sb)[i] = 0; - } else { + 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))) { - UDF_SB_ANCHOR(sb)[i] = 0; - } + (i || (ident != TAG_IDENT_FE && + ident != TAG_IDENT_EFE))) + sbi->s_anchor[i] = 0; } } } - UDF_SB_LASTBLOCK(sb) = lastblock; + sbi->s_last_block = lastblock; } -static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root) +static int udf_find_fileset(struct super_block *sb, + kernel_lb_addr *fileset, + kernel_lb_addr *root) { struct buffer_head *bh = NULL; long lastblock; uint16_t ident; + struct udf_sb_info *sbi; if (fileset->logicalBlockNum != 0xFFFFFFFF || fileset->partitionReferenceNum != 0xFFFF) { @@ -764,22 +867,27 @@ static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, ker } - if (!bh) { /* Search backwards through the partitions */ + sbi = UDF_SB(sb); + if (!bh) { + /* Search backwards through the partitions */ kernel_lb_addr newfileset; /* --> cvg: FIXME - is it reasonable? */ return 1; - for (newfileset.partitionReferenceNum = UDF_SB_NUMPARTS(sb) - 1; + for (newfileset.partitionReferenceNum = sbi->s_partitions - 1; (newfileset.partitionReferenceNum != 0xFFFF && fileset->logicalBlockNum == 0xFFFFFFFF && fileset->partitionReferenceNum == 0xFFFF); newfileset.partitionReferenceNum--) { - lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum); + lastblock = sbi->s_partmaps + [newfileset.partitionReferenceNum] + .s_partition_len; newfileset.logicalBlockNum = 0; do { - bh = udf_read_ptagged(sb, newfileset, 0, &ident); + bh = udf_read_ptagged(sb, newfileset, 0, + &ident); if (!bh) { newfileset.logicalBlockNum++; continue; @@ -789,11 +897,12 @@ static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, ker case TAG_IDENT_SBD: { struct spaceBitmapDesc *sp; - sp = (struct spaceBitmapDesc *)bh->b_data; + sp = (struct spaceBitmapDesc *) + bh->b_data; newfileset.logicalBlockNum += 1 + ((le32_to_cpu(sp->numOfBytes) + - sizeof(struct spaceBitmapDesc) - 1) - >> sb->s_blocksize_bits); + sizeof(struct spaceBitmapDesc) + - 1) >> sb->s_blocksize_bits); brelse(bh); break; } @@ -818,7 +927,7 @@ static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, ker fileset->logicalBlockNum, fileset->partitionReferenceNum); - UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum; + sbi->s_partition = fileset->partitionReferenceNum; udf_load_fileset(sb, bh, root); brelse(bh); return 0; @@ -829,37 +938,32 @@ static int udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, ker static void udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) { struct primaryVolDesc *pvoldesc; - time_t recording; - long recording_usec; struct ustr instr; struct ustr outstr; pvoldesc = (struct primaryVolDesc *)bh->b_data; - if (udf_stamp_to_time(&recording, &recording_usec, - lets_to_cpu(pvoldesc->recordingDateAndTime))) { + if (udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, + 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, + udf_debug("recording time %04u/%02u/%02u" + " %02u:%02u (%x)\n", ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone); - UDF_SB_RECORDTIME(sb).tv_sec = recording; - UDF_SB_RECORDTIME(sb).tv_nsec = recording_usec * 1000; } - if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) { + if (!udf_build_ustr(&instr, pvoldesc->volIdent, 32)) if (udf_CS0toUTF8(&outstr, &instr)) { - strncpy(UDF_SB_VOLIDENT(sb), outstr.u_name, + 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_VOLIDENT(sb)); + udf_debug("volIdent[] = '%s'\n", + UDF_SB(sb)->s_volume_ident); } - } - if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) { + if (!udf_build_ustr(&instr, pvoldesc->volSetIdent, 128)) if (udf_CS0toUTF8(&outstr, &instr)) udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); - } } static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, @@ -871,65 +975,123 @@ static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); - UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum); + UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum); udf_debug("Rootdir at block=%d, partition=%d\n", root->logicalBlockNum, root->partitionReferenceNum); } +int udf_compute_nr_groups(struct super_block *sb, u32 partition) +{ + struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; + 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) +{ + struct udf_bitmap *bitmap; + int nr_groups; + int size; + + nr_groups = udf_compute_nr_groups(sb, index); + size = sizeof(struct udf_bitmap) + + (sizeof(struct buffer_head *) * nr_groups); + + if (size <= PAGE_SIZE) + bitmap = kmalloc(size, GFP_KERNEL); + else + bitmap = vmalloc(size); /* TODO: get rid of vmalloc */ + + if (bitmap == NULL) { + udf_error(sb, __FUNCTION__, + "Unable to allocate space for bitmap " + "and %d buffer_head pointers", nr_groups); + 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) { struct partitionDesc *p; int i; + struct udf_part_map *map; + struct udf_sb_info *sbi; p = (struct partitionDesc *)bh->b_data; + sbi = UDF_SB(sb); - for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) { + for (i = 0; i < sbi->s_partitions; i++) { + map = &sbi->s_partmaps[i]; udf_debug("Searching map: (%d == %d)\n", - UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber)); - if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) { - UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */ - UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation); - if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY) - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_READ_ONLY; - if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_WRITE_ONCE) - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_WRITE_ONCE; - if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_REWRITABLE) - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_REWRITABLE; - if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_OVERWRITABLE) - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_OVERWRITABLE; - - if (!strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) || - !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) { + 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); + phd = (struct partitionHeaderDesc *) + (p->partitionContentsUse); if (phd->unallocSpaceTable.extLength) { kernel_lb_addr loc = { .logicalBlockNum = le32_to_cpu(phd->unallocSpaceTable.extPosition), .partitionReferenceNum = i, }; - UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table = + map->s_uspace.s_table = udf_iget(sb, loc); - if (!UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table) { + if (!map->s_uspace.s_table) { udf_debug("cannot load unallocSpaceTable (part %d)\n", i); return 1; } - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE; + map->s_partition_flags |= + UDF_PART_FLAG_UNALLOC_TABLE; udf_debug("unallocSpaceTable (part %d) @ %ld\n", - i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino); + i, map->s_uspace.s_table->i_ino); } if (phd->unallocSpaceBitmap.extLength) { - UDF_SB_ALLOC_BITMAP(sb, i, s_uspace); - if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL) { - UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_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); - UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition = + bitmap->s_extPosition = le32_to_cpu(phd->unallocSpaceBitmap.extPosition); - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP; + map->s_partition_flags |= UDF_PART_FLAG_UNALLOC_BITMAP; udf_debug("unallocSpaceBitmap (part %d) @ %d\n", - i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition); + i, bitmap->s_extPosition); } } if (phd->partitionIntegrityTable.extLength) @@ -940,40 +1102,45 @@ static int udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) .partitionReferenceNum = i, }; - UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table = + map->s_fspace.s_table = udf_iget(sb, loc); - if (!UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table) { + if (!map->s_fspace.s_table) { udf_debug("cannot load freedSpaceTable (part %d)\n", i); return 1; } - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE; + map->s_partition_flags |= + UDF_PART_FLAG_FREED_TABLE; udf_debug("freedSpaceTable (part %d) @ %ld\n", - i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino); + i, map->s_fspace.s_table->i_ino); } if (phd->freedSpaceBitmap.extLength) { - UDF_SB_ALLOC_BITMAP(sb, i, s_fspace); - if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL) { - UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_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); - UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition = + bitmap->s_extPosition = le32_to_cpu(phd->freedSpaceBitmap.extPosition); - UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP; + map->s_partition_flags |= UDF_PART_FLAG_FREED_BITMAP; udf_debug("freedSpaceBitmap (part %d) @ %d\n", - i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition); + i, bitmap->s_extPosition); } } } break; } } - if (i == UDF_SB_NUMPARTS(sb)) { + 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, UDF_SB_PARTTYPE(sb,i), - UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i)); - } + 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); return 0; } @@ -983,70 +1150,105 @@ static int udf_load_logicalvol(struct super_block *sb, struct buffer_head *bh, struct logicalVolDesc *lvd; int i, j, offset; uint8_t type; + struct udf_sb_info *sbi = UDF_SB(sb); + struct genericPartitionMap *gpm; lvd = (struct logicalVolDesc *)bh->b_data; - UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps)); + i = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); + if (i != 0) + return i; for (i = 0, offset = 0; - i < UDF_SB_NUMPARTS(sb) && offset < le32_to_cpu(lvd->mapTableLength); - i++, offset += ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength) { - type = ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType; + i < sbi->s_partitions && offset < le32_to_cpu(lvd->mapTableLength); + i++, offset += gpm->partitionMapLength) { + struct udf_part_map *map = &sbi->s_partmaps[i]; + gpm = (struct genericPartitionMap *) + &(lvd->partitionMaps[offset]); + type = gpm->partitionMapType; if (type == 1) { - struct genericPartitionMap1 *gpm1 = (struct genericPartitionMap1 *)&(lvd->partitionMaps[offset]); - UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15; - UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum); - UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum); - UDF_SB_PARTFUNC(sb,i) = NULL; + struct genericPartitionMap1 *gpm1 = + (struct genericPartitionMap1 *)gpm; + map->s_partition_type = UDF_TYPE1_MAP15; + map->s_volumeseqnum = le16_to_cpu(gpm1->volSeqNum); + map->s_partition_num = le16_to_cpu(gpm1->partitionNum); + map->s_partition_func = NULL; } else if (type == 2) { - struct udfPartitionMap2 *upm2 = (struct udfPartitionMap2 *)&(lvd->partitionMaps[offset]); - if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) { - if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150) { - UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15; - UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15; - } else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200) { - UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20; - UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20; + struct udfPartitionMap2 *upm2 = + (struct udfPartitionMap2 *)gpm; + if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, + strlen(UDF_ID_VIRTUAL))) { + u16 suf = + le16_to_cpu(((__le16 *)upm2->partIdent. + identSuffix)[0]); + if (suf == 0x0150) { + map->s_partition_type = + UDF_VIRTUAL_MAP15; + map->s_partition_func = + udf_get_pblock_virt15; + } else if (suf == 0x0200) { + map->s_partition_type = + UDF_VIRTUAL_MAP20; + map->s_partition_func = + udf_get_pblock_virt20; } - } else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) { + } 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 *)&(lvd->partitionMaps[offset]); + struct sparablePartitionMap *spm = + (struct sparablePartitionMap *)gpm; - UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15; - UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength); + 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++) { - loc = le32_to_cpu(spm->locSparingTable[j]); - UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = - udf_read_tagged(sb, loc, loc, &ident); - if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) { - st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data; - if (ident != 0 || - strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) { - brelse(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]); - UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL; + 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; } } } - UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15; + map->s_partition_func = udf_get_pblock_spar15; } else { - udf_debug("Unknown ident: %s\n", upm2->partIdent.ident); + udf_debug("Unknown ident: %s\n", + upm2->partIdent.ident); continue; } - UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum); - UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum); + map->s_volumeseqnum = le16_to_cpu(upm2->volSeqNum); + map->s_partition_num = le16_to_cpu(upm2->partitionNum); } udf_debug("Partition (%d:%d) type %d on volume %d\n", - i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i)); + i, map->s_partition_num, type, + map->s_volumeseqnum); } if (fileset) { long_ad *la = (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) @@ -1063,22 +1265,26 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) { struct buffer_head *bh = NULL; uint16_t ident; + struct udf_sb_info *sbi = UDF_SB(sb); + struct logicalVolIntegrityDesc *lvid; while (loc.extLength > 0 && (bh = udf_read_tagged(sb, loc.extLocation, loc.extLocation, &ident)) && ident == TAG_IDENT_LVID) { - UDF_SB_LVIDBH(sb) = bh; + sbi->s_lvid_bh = bh; + lvid = (struct logicalVolIntegrityDesc *)bh->b_data; - if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength) - udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt)); + if (lvid->nextIntegrityExt.extLength) + udf_load_logicalvolint(sb, + leea_to_cpu(lvid->nextIntegrityExt)); - if (UDF_SB_LVIDBH(sb) != bh) + if (sbi->s_lvid_bh != bh) brelse(bh); loc.extLength -= sb->s_blocksize; loc.extLocation++; } - if (UDF_SB_LVIDBH(sb) != bh) + if (sbi->s_lvid_bh != bh) brelse(bh); } @@ -1097,11 +1303,12 @@ static void udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) * July 1, 1997 - Andrew E. Mileski * Written, tested, and released. */ -static int udf_process_sequence(struct super_block *sb, long block, long lastblock, - kernel_lb_addr *fileset) +static int udf_process_sequence(struct super_block *sb, long block, + long lastblock, kernel_lb_addr *fileset) { struct buffer_head *bh = NULL; struct udf_vds_record vds[VDS_POS_LENGTH]; + struct udf_vds_record *curr; struct generic_desc *gd; struct volDescPtr *vdp; int done = 0; @@ -1124,43 +1331,51 @@ static int udf_process_sequence(struct super_block *sb, long block, long lastblo vdsn = le32_to_cpu(gd->volDescSeqNum); switch (ident) { case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ - if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) { - vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn; - vds[VDS_POS_PRIMARY_VOL_DESC].block = block; + curr = &vds[VDS_POS_PRIMARY_VOL_DESC]; + if (vdsn >= curr->volDescSeqNum) { + curr->volDescSeqNum = vdsn; + curr->block = block; } break; case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */ - if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) { - vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn; - vds[VDS_POS_VOL_DESC_PTR].block = block; + curr = &vds[VDS_POS_VOL_DESC_PTR]; + if (vdsn >= curr->volDescSeqNum) { + curr->volDescSeqNum = vdsn; + curr->block = block; vdp = (struct volDescPtr *)bh->b_data; - next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation); - next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength); + next_s = le32_to_cpu( + vdp->nextVolDescSeqExt.extLocation); + next_e = le32_to_cpu( + vdp->nextVolDescSeqExt.extLength); next_e = next_e >> sb->s_blocksize_bits; next_e += next_s; } break; case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ - if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) { - vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn; - vds[VDS_POS_IMP_USE_VOL_DESC].block = block; + curr = &vds[VDS_POS_IMP_USE_VOL_DESC]; + if (vdsn >= curr->volDescSeqNum) { + curr->volDescSeqNum = vdsn; + curr->block = block; } break; case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ - if (!vds[VDS_POS_PARTITION_DESC].block) - vds[VDS_POS_PARTITION_DESC].block = block; + curr = &vds[VDS_POS_PARTITION_DESC]; + if (!curr->block) + curr->block = block; break; case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ - if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) { - vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn; - vds[VDS_POS_LOGICAL_VOL_DESC].block = block; + curr = &vds[VDS_POS_LOGICAL_VOL_DESC]; + if (vdsn >= curr->volDescSeqNum) { + curr->volDescSeqNum = vdsn; + curr->block = block; } break; case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ - if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) { - vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn; - vds[VDS_POS_UNALLOC_SPACE_DESC].block = block; + curr = &vds[VDS_POS_UNALLOC_SPACE_DESC]; + if (vdsn >= curr->volDescSeqNum) { + curr->volDescSeqNum = vdsn; + curr->block = block; } break; case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ @@ -1169,32 +1384,38 @@ static int udf_process_sequence(struct super_block *sb, long block, long lastblo block = next_s; lastblock = next_e; next_s = next_e = 0; - } else { + } else done = 1; - } break; } 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); + bh = udf_read_tagged(sb, vds[i].block, vds[i].block, + &ident); if (i == VDS_POS_PRIMARY_VOL_DESC) { udf_load_pvoldesc(sb, bh); } else if (i == VDS_POS_LOGICAL_VOL_DESC) { - udf_load_logicalvol(sb, bh, fileset); + 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++) { + 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)) { + if (udf_load_partdesc(sb, + bh2)) { brelse(bh); brelse(bh2); return 1; @@ -1222,14 +1443,17 @@ static int udf_check_valid(struct super_block *sb, int novrs, int silent) } /* Check that it is NSR02 compliant */ /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ - else if ((block = udf_vrs(sb, silent)) == -1) { - udf_debug("Failed to read byte 32768. Assuming open disc. " - "Skipping validity check\n"); - if (!UDF_SB_LASTBLOCK(sb)) - UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb); - return 0; - } else { - return !block; + 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; } } @@ -1240,100 +1464,121 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) struct buffer_head *bh; long main_s, main_e, reserve_s, reserve_e; int i, j; + struct udf_sb_info *sbi; if (!sb) return 1; + sbi = UDF_SB(sb); - for (i = 0; i < ARRAY_SIZE(UDF_SB_ANCHOR(sb)); i++) { - if (UDF_SB_ANCHOR(sb)[i] && - (bh = udf_read_tagged(sb, UDF_SB_ANCHOR(sb)[i], - UDF_SB_ANCHOR(sb)[i], &ident))) { - anchor = (struct anchorVolDescPtr *)bh->b_data; + for (i = 0; i < ARRAY_SIZE(sbi->s_anchor); i++) { + if (!sbi->s_anchor[i]) + continue; + bh = udf_read_tagged(sb, sbi->s_anchor[i], sbi->s_anchor[i], + &ident); + if (!bh) + continue; - /* 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; + anchor = (struct anchorVolDescPtr *)bh->b_data; - /* 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; + /* 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; - brelse(bh); + /* 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) */ - if (!(udf_process_sequence(sb, main_s, main_e, fileset) && - udf_process_sequence(sb, reserve_s, reserve_e, fileset))) { - break; - } - } + brelse(bh); + + /* 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; } - if (i == ARRAY_SIZE(UDF_SB_ANCHOR(sb))) { + if (i == ARRAY_SIZE(sbi->s_anchor)) { udf_debug("No Anchor block found\n"); return 1; - } else - udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]); + } + udf_debug("Using anchor in block %d\n", sbi->s_anchor[i]); - for (i = 0; i < UDF_SB_NUMPARTS(sb); i++) { + for (i = 0; i < sbi->s_partitions; i++) { kernel_lb_addr uninitialized_var(ino); - switch (UDF_SB_PARTTYPE(sb, i)) { + struct udf_part_map *map = &sbi->s_partmaps[i]; + switch (map->s_partition_type) { case UDF_VIRTUAL_MAP15: case UDF_VIRTUAL_MAP20: - if (!UDF_SB_LASTBLOCK(sb)) { - UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb); + if (!sbi->s_last_block) { + sbi->s_last_block = udf_get_last_block(sb); udf_find_anchor(sb); } - if (!UDF_SB_LASTBLOCK(sb)) { + if (!sbi->s_last_block) { udf_debug("Unable to determine Lastblock (For " "Virtual Partition)\n"); return 1; } - for (j = 0; j < UDF_SB_NUMPARTS(sb); j++) { + for (j = 0; j < sbi->s_partitions; j++) { + struct udf_part_map *map2 = &sbi->s_partmaps[j]; if (j != i && - UDF_SB_PARTVSN(sb, i) == UDF_SB_PARTVSN(sb, j) && - UDF_SB_PARTNUM(sb, i) == UDF_SB_PARTNUM(sb, j)) { + map->s_volumeseqnum == + map2->s_volumeseqnum && + map->s_partition_num == + map2->s_partition_num) { ino.partitionReferenceNum = j; - ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) - UDF_SB_PARTROOT(sb, j); + ino.logicalBlockNum = + sbi->s_last_block - + map2->s_partition_root; break; } } - if (j == UDF_SB_NUMPARTS(sb)) + if (j == sbi->s_partitions) return 1; - if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino))) + sbi->s_vat_inode = udf_iget(sb, ino); + if (!sbi->s_vat_inode) return 1; - if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP15) { - UDF_SB_TYPEVIRT(sb, i).s_start_offset = - udf_ext0_offset(UDF_SB_VAT(sb)); - UDF_SB_TYPEVIRT(sb, i).s_num_entries = - (UDF_SB_VAT(sb)->i_size - 36) >> 2; - } else if (UDF_SB_PARTTYPE(sb, i) == UDF_VIRTUAL_MAP20) { - struct buffer_head *bh = NULL; + 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(UDF_SB_VAT(sb), 0); + pos = udf_block_map(sbi->s_vat_inode, 0); bh = sb_bread(sb, pos); if (!bh) return 1; - UDF_SB_TYPEVIRT(sb, i).s_start_offset = - le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + - udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) + - udf_ext0_offset(UDF_SB_VAT(sb)); - UDF_SB_TYPEVIRT(sb, i).s_num_entries = (UDF_SB_VAT(sb)->i_size - - UDF_SB_TYPEVIRT(sb, i).s_start_offset) >> 2; + 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); } - UDF_SB_PARTROOT(sb, i) = udf_get_pblock(sb, 0, i, 0); - UDF_SB_PARTLEN(sb, i) = UDF_SB_PARTLEN(sb, ino.partitionReferenceNum); + map->s_partition_root = udf_get_pblock(sb, 0, i, 0); + map->s_partition_len = + sbi->s_partmaps[ino.partitionReferenceNum]. + s_partition_len; } } return 0; @@ -1341,78 +1586,84 @@ static int udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) static void udf_open_lvid(struct super_block *sb) { - if (UDF_SB_LVIDBH(sb)) { - int i; - kernel_timestamp cpu_time; - - UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); - UDF_SB_LVID(sb)->integrityType = LVID_INTEGRITY_TYPE_OPEN; - - UDF_SB_LVID(sb)->descTag.descCRC = cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), - le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); - - UDF_SB_LVID(sb)->descTag.tagChecksum = 0; - for (i = 0; i < 16; i++) - if (i != 4) - UDF_SB_LVID(sb)->descTag.tagChecksum += - ((uint8_t *) &(UDF_SB_LVID(sb)->descTag))[i]; - - mark_buffer_dirty(UDF_SB_LVIDBH(sb)); + struct udf_sb_info *sbi = UDF_SB(sb); + struct buffer_head *bh = sbi->s_lvid_bh; + if (bh) { + 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; + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, + CURRENT_TIME); + lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; + + 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); } } 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; + + if (!bh) + return; + + lvid = (struct logicalVolIntegrityDesc *)bh->b_data; + + 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; + 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( + 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); + } +} + +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); - if (UDF_SB_LVIDBH(sb) && - UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN) { - UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; - UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) - UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); - if (UDF_MAX_WRITE_VERSION > le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev)) - UDF_SB_LVIDIU(sb)->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); - if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev)) - UDF_SB_LVIDIU(sb)->minUDFReadRev = cpu_to_le16(UDF_SB_UDFREV(sb)); - if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev)) - UDF_SB_LVIDIU(sb)->minUDFWriteRev = cpu_to_le16(UDF_SB_UDFREV(sb)); - UDF_SB_LVID(sb)->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); - - UDF_SB_LVID(sb)->descTag.descCRC = - cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), - le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); - - UDF_SB_LVID(sb)->descTag.tagChecksum = 0; - for (i = 0; i < 16; i++) - if (i != 4) - UDF_SB_LVID(sb)->descTag.tagChecksum += - ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i]; - - mark_buffer_dirty(UDF_SB_LVIDBH(sb)); - } + 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); } -/* - * 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; @@ -1426,16 +1677,15 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) uopt.gid = -1; uopt.umask = 0; - sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL); + sbi = kzalloc(sizeof(struct udf_sb_info), GFP_KERNEL); if (!sbi) return -ENOMEM; sb->s_fs_info = sbi; - memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info)); mutex_init(&sbi->s_alloc_mutex); - if (!udf_parse_options((char *)options, &uopt)) + if (!udf_parse_options((char *)options, &uopt, false)) goto error_out; if (uopt.flags & (1 << UDF_FLAG_UTF8) && @@ -1459,30 +1709,34 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) fileset.logicalBlockNum = 0xFFFFFFFF; fileset.partitionReferenceNum = 0xFFFF; - UDF_SB(sb)->s_flags = uopt.flags; - UDF_SB(sb)->s_uid = uopt.uid; - UDF_SB(sb)->s_gid = uopt.gid; - UDF_SB(sb)->s_umask = uopt.umask; - UDF_SB(sb)->s_nls_map = uopt.nls_map; + sbi->s_flags = uopt.flags; + sbi->s_uid = uopt.uid; + sbi->s_gid = uopt.gid; + sbi->s_umask = uopt.umask; + sbi->s_nls_map = uopt.nls_map; /* Set the block size for all transfers */ - if (!udf_set_blocksize(sb, uopt.blocksize)) + if (!sb_min_blocksize(sb, uopt.blocksize)) { + udf_debug("Bad block size (%d)\n", uopt.blocksize); + printk(KERN_ERR "udf: bad block size (%d)\n", uopt.blocksize); goto error_out; + } if (uopt.session == 0xFFFFFFFF) - UDF_SB_SESSION(sb) = udf_get_last_session(sb); + sbi->s_session = udf_get_last_session(sb); else - UDF_SB_SESSION(sb) = uopt.session; + sbi->s_session = uopt.session; - udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb)); + udf_debug("Multi-session=%d\n", sbi->s_session); - UDF_SB_LASTBLOCK(sb) = uopt.lastblock; - UDF_SB_ANCHOR(sb)[0] = UDF_SB_ANCHOR(sb)[1] = 0; - UDF_SB_ANCHOR(sb)[2] = uopt.anchor; - UDF_SB_ANCHOR(sb)[3] = 256; + 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("UDF-fs: No VRS found\n"); + if (udf_check_valid(sb, uopt.novrs, silent)) { + /* read volume recognition sequences */ + printk(KERN_WARNING "UDF-fs: No VRS found\n"); goto error_out; } @@ -1496,27 +1750,30 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) sb->s_time_gran = 1000; if (udf_load_partition(sb, &fileset)) { - printk("UDF-fs: No partition found (1)\n"); + printk(KERN_WARNING "UDF-fs: No partition found (1)\n"); goto error_out; } - udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb)); + udf_debug("Lastblock=%d\n", sbi->s_last_block); - if (UDF_SB_LVIDBH(sb)) { - uint16_t minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev); - uint16_t minUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev); - /* uint16_t maxUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev); */ + 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); */ if (minUDFReadRev > UDF_MAX_READ_VERSION) { - printk("UDF-fs: minUDFReadRev=%x (max is %x)\n", - le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev), + printk(KERN_ERR "UDF-fs: minUDFReadRev=%x " + "(max is %x)\n", + le16_to_cpu(lvidiu->minUDFReadRev), UDF_MAX_READ_VERSION); goto error_out; - } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) { + } else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) sb->s_flags |= MS_RDONLY; - } - UDF_SB_UDFREV(sb) = minUDFWriteRev; + sbi->s_udfrev = minUDFWriteRev; if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE) UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE); @@ -1524,29 +1781,30 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS); } - if (!UDF_SB_NUMPARTS(sb)) { - printk("UDF-fs: No partition found (2)\n"); + if (!sbi->s_partitions) { + printk(KERN_WARNING "UDF-fs: No partition found (2)\n"); goto error_out; } - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_READ_ONLY) { - printk("UDF-fs: Partition marked readonly; forcing readonly mount\n"); + 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; } if (udf_find_fileset(sb, &fileset, &rootdir)) { - printk("UDF-fs: No fileset found\n"); + printk(KERN_WARNING "UDF-fs: No fileset found\n"); goto error_out; } if (!silent) { - kernel_timestamp ts; - udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb)); - udf_info("UDF %s (%s) Mounting volume '%s', " + timestamp ts; + udf_time_to_disk_stamp(&ts, sbi->s_record_time); + udf_info("UDF: Mounting volume '%s', " "timestamp %04u/%02u/%02u %02u:%02u (%x)\n", - UDFFS_VERSION, UDFFS_DATE, - UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute, - ts.typeAndTimezone); + 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); @@ -1556,7 +1814,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) /* perhaps it's not extensible enough, but for now ... */ inode = udf_iget(sb, rootdir); if (!inode) { - printk("UDF-fs: Error in udf_iget, block=%d, partition=%d\n", + printk(KERN_ERR "UDF-fs: Error in udf_iget, block=%d, " + "partition=%d\n", rootdir.logicalBlockNum, rootdir.partitionReferenceNum); goto error_out; } @@ -1564,7 +1823,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) /* Allocate a dentry for the root inode */ sb->s_root = d_alloc_root(inode); if (!sb->s_root) { - printk("UDF-fs: Couldn't allocate root dentry\n"); + printk(KERN_ERR "UDF-fs: Couldn't allocate root dentry\n"); iput(inode); goto error_out; } @@ -1572,38 +1831,40 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) return 0; error_out: - if (UDF_SB_VAT(sb)) - iput(UDF_SB_VAT(sb)); - if (UDF_SB_NUMPARTS(sb)) { - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) - iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table); - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) - iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) - UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace); - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) - UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace); - if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) { + 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(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[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(UDF_SB(sb)->s_nls_map); + unload_nls(sbi->s_nls_map); #endif if (!(sb->s_flags & MS_RDONLY)) udf_close_lvid(sb); - brelse(UDF_SB_LVIDBH(sb)); - UDF_SB_FREE(sb); + brelse(sbi->s_lvid_bh); + + kfree(sbi->s_partmaps); kfree(sbi); sb->s_fs_info = NULL; return -EINVAL; } -void udf_error(struct super_block *sb, const char *function, - const char *fmt, ...) +static void udf_error(struct super_block *sb, const char *function, + const char *fmt, ...) { va_list args; @@ -1614,7 +1875,7 @@ void udf_error(struct super_block *sb, const char *function, va_start(args, fmt); vsnprintf(error_buf, sizeof(error_buf), fmt, args); va_end(args); - printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n", + printk(KERN_CRIT "UDF-fs error (device %s): %s: %s\n", sb->s_id, function, error_buf); } @@ -1630,76 +1891,60 @@ void udf_warning(struct super_block *sb, const char *function, 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; - if (UDF_SB_VAT(sb)) - iput(UDF_SB_VAT(sb)); - if (UDF_SB_NUMPARTS(sb)) { - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) - iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table); - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) - iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) - UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_uspace); - if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) - UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb), s_fspace); - if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) { + 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(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[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(UDF_SB(sb)->s_nls_map); + unload_nls(sbi->s_nls_map); #endif if (!(sb->s_flags & MS_RDONLY)) udf_close_lvid(sb); - brelse(UDF_SB_LVIDBH(sb)); - UDF_SB_FREE(sb); + brelse(sbi->s_lvid_bh); + kfree(sbi->s_partmaps); 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_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; + + if (sbi->s_lvid_bh != NULL) + lvidiu = udf_sb_lvidiu(sbi); + else + lvidiu = NULL; buf->f_type = UDF_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)); + buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len; buf->f_bfree = udf_count_free(sb); buf->f_bavail = buf->f_bfree; - buf->f_files = (UDF_SB_LVIDBH(sb) ? - (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + - le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree; + buf->f_files = (lvidiu != NULL ? (le32_to_cpu(lvidiu->numFiles) + + 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; @@ -1707,11 +1952,8 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) 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) +static unsigned int udf_count_free_bitmap(struct super_block *sb, + struct udf_bitmap *bitmap) { struct buffer_head *bh = NULL; unsigned int accum = 0; @@ -1719,7 +1961,6 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bit int block = 0, newblock; kernel_lb_addr loc; uint32_t bytes; - uint8_t value; uint8_t *ptr; uint16_t ident; struct spaceBitmapDesc *bm; @@ -1727,7 +1968,7 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bit lock_kernel(); loc.logicalBlockNum = bitmap->s_extPosition; - loc.partitionReferenceNum = UDF_SB_PARTITION(sb); + loc.partitionReferenceNum = UDF_SB(sb)->s_partition; bh = udf_read_ptagged(sb, loc, 0, &ident); if (!bh) { @@ -1745,13 +1986,10 @@ static unsigned int udf_count_free_bitmap(struct super_block *sb, struct udf_bit 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); @@ -1772,7 +2010,8 @@ out: return accum; } -static unsigned int udf_count_free_table(struct super_block *sb, struct inode *table) +static unsigned int udf_count_free_table(struct super_block *sb, + struct inode *table) { unsigned int accum = 0; uint32_t elen; @@ -1782,13 +2021,13 @@ static unsigned int udf_count_free_table(struct super_block *sb, struct inode *t lock_kernel(); - epos.block = UDF_I_LOCATION(table); + epos.block = UDF_I(table)->i_location; epos.offset = sizeof(struct unallocSpaceEntry); epos.bh = NULL; - while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) { + while ((etype = udf_next_aext(table, &epos, &eloc, &elen, 1)) != -1) accum += (elen >> table->i_sb->s_blocksize_bits); - } + brelse(epos.bh); unlock_kernel(); @@ -1799,10 +2038,17 @@ static unsigned int udf_count_free_table(struct super_block *sb, struct inode *t static unsigned int udf_count_free(struct super_block *sb) { unsigned int accum = 0; - - if (UDF_SB_LVIDBH(sb)) { - if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb)) { - accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]); + struct udf_sb_info *sbi; + struct udf_part_map *map; + + sbi = UDF_SB(sb); + if (sbi->s_lvid_bh) { + struct logicalVolIntegrityDesc *lvid = + (struct logicalVolIntegrityDesc *) + sbi->s_lvid_bh->b_data; + if (le32_to_cpu(lvid->numOfPartitions) > sbi->s_partition) { + accum = le32_to_cpu( + lvid->freeSpaceTable[sbi->s_partition]); if (accum == 0xFFFFFFFF) accum = 0; } @@ -1811,24 +2057,25 @@ static unsigned int udf_count_free(struct super_block *sb) if (accum) return accum; - if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) { + map = &sbi->s_partmaps[sbi->s_partition]; + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) { accum += udf_count_free_bitmap(sb, - UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap); + map->s_uspace.s_bitmap); } - if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) { + if (map->s_partition_flags & UDF_PART_FLAG_FREED_BITMAP) { accum += udf_count_free_bitmap(sb, - UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap); + map->s_fspace.s_bitmap); } if (accum) return accum; - if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) { + if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_TABLE) { accum += udf_count_free_table(sb, - UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table); + map->s_uspace.s_table); } - if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) { + if (map->s_partition_flags & UDF_PART_FLAG_FREED_TABLE) { accum += udf_count_free_table(sb, - UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); + map->s_fspace.s_table); } return accum;