diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-21 13:53:34 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-09-21 13:53:34 -0700 |
commit | 7ce1e15d9a85a2b589a68a04afb2b2ded109b680 (patch) | |
tree | 0f21f4f97f7ac5efc0994656a57d6489a4f05b60 /fs | |
parent | 70cb0d02b58128db07fc39b5e87a2873e2c16bde (diff) | |
parent | 6565c182094f69e4ffdece337d395eb7ec760efc (diff) |
Merge tag 'for_v5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull ext2, quota, udf fixes and cleanups from Jan Kara:
- two small quota fixes (in grace time handling and possible missed
accounting of preallocated blocks beyond EOF).
- some ext2 cleanups
- udf fixes for better compatibility with Windows 10 generated media
(named streams, write-protection using domain-identifier, placement
of volume recognition sequence)
- some udf cleanups
* tag 'for_v5.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
quota: fix wrong condition in is_quota_modification()
fs-udf: Delete an unnecessary check before brelse()
ext2: Delete an unnecessary check before brelse()
udf: Drop forward function declarations
udf: Verify domain identifier fields
udf: augment UDF permissions on new inodes
udf: Use dynamic debug infrastructure
udf: reduce leakage of blocks related to named streams
udf: prevent allocation beyond UDF partition
quota: fix condition for resetting time limit in do_set_dqblk()
ext2: code cleanup for ext2_free_blocks()
ext2: fix block range in ext2_data_block_valid()
udf: support 2048-byte spacing of VRS descriptors on 4K media
udf: refactor VRS descriptor identification
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext2/balloc.c | 10 | ||||
-rw-r--r-- | fs/ext2/super.c | 3 | ||||
-rw-r--r-- | fs/ext2/xattr.c | 2 | ||||
-rw-r--r-- | fs/quota/dquot.c | 4 | ||||
-rw-r--r-- | fs/udf/balloc.c | 11 | ||||
-rw-r--r-- | fs/udf/ecma_167.h | 14 | ||||
-rw-r--r-- | fs/udf/file.c | 3 | ||||
-rw-r--r-- | fs/udf/ialloc.c | 3 | ||||
-rw-r--r-- | fs/udf/inode.c | 55 | ||||
-rw-r--r-- | fs/udf/super.c | 261 | ||||
-rw-r--r-- | fs/udf/udf_i.h | 6 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 11 |
12 files changed, 248 insertions, 135 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 547c165299c0..e0cc55164505 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -490,9 +490,7 @@ void ext2_free_blocks (struct inode * inode, unsigned long block, struct ext2_super_block * es = sbi->s_es; unsigned freed = 0, group_freed; - if (block < le32_to_cpu(es->s_first_data_block) || - block + count < block || - block + count > le32_to_cpu(es->s_blocks_count)) { + if (!ext2_data_block_valid(sbi, block, count)) { ext2_error (sb, "ext2_free_blocks", "Freeing blocks not in datazone - " "block = %lu, count = %lu", block, count); @@ -1203,13 +1201,13 @@ int ext2_data_block_valid(struct ext2_sb_info *sbi, ext2_fsblk_t start_blk, unsigned int count) { if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || - (start_blk + count < start_blk) || - (start_blk > le32_to_cpu(sbi->s_es->s_blocks_count))) + (start_blk + count - 1 < start_blk) || + (start_blk + count - 1 >= le32_to_cpu(sbi->s_es->s_blocks_count))) return 0; /* Ensure we do not step over superblock */ if ((start_blk <= sbi->s_sb_block) && - (start_blk + count >= sbi->s_sb_block)) + (start_blk + count - 1 >= sbi->s_sb_block)) return 0; return 1; diff --git a/fs/ext2/super.c b/fs/ext2/super.c index baa36c6fb71e..30c630d73f0f 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -162,8 +162,7 @@ static void ext2_put_super (struct super_block * sb) } db_count = sbi->s_gdb_count; for (i = 0; i < db_count; i++) - if (sbi->s_group_desc[i]) - brelse (sbi->s_group_desc[i]); + brelse(sbi->s_group_desc[i]); kfree(sbi->s_group_desc); kfree(sbi->s_debts); percpu_counter_destroy(&sbi->s_freeblocks_counter); diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 79369c13cc55..0456bc990b5e 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c @@ -794,7 +794,7 @@ ext2_xattr_delete_inode(struct inode *inode) if (!EXT2_I(inode)->i_file_acl) goto cleanup; - if (!ext2_data_block_valid(sbi, EXT2_I(inode)->i_file_acl, 0)) { + if (!ext2_data_block_valid(sbi, EXT2_I(inode)->i_file_acl, 1)) { ext2_error(inode->i_sb, "ext2_xattr_delete_inode", "inode %ld: xattr block %d is out of data blocks range", inode->i_ino, EXT2_I(inode)->i_file_acl); diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index be9c471cdbc8..6e826b454082 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -2731,7 +2731,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) if (check_blim) { if (!dm->dqb_bsoftlimit || - dm->dqb_curspace + dm->dqb_rsvspace < dm->dqb_bsoftlimit) { + dm->dqb_curspace + dm->dqb_rsvspace <= dm->dqb_bsoftlimit) { dm->dqb_btime = 0; clear_bit(DQ_BLKS_B, &dquot->dq_flags); } else if (!(di->d_fieldmask & QC_SPC_TIMER)) @@ -2740,7 +2740,7 @@ static int do_set_dqblk(struct dquot *dquot, struct qc_dqblk *di) } if (check_ilim) { if (!dm->dqb_isoftlimit || - dm->dqb_curinodes < dm->dqb_isoftlimit) { + dm->dqb_curinodes <= dm->dqb_isoftlimit) { dm->dqb_itime = 0; clear_bit(DQ_INODES_B, &dquot->dq_flags); } else if (!(di->d_fieldmask & QC_INO_TIMER)) diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index ec85aeaed54a..02f03fadb75b 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -325,6 +325,17 @@ got_block: newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) - (sizeof(struct spaceBitmapDesc) << 3); + if (newblock >= sbi->s_partmaps[partition].s_partition_len) { + /* + * Ran off the end of the bitmap, and bits following are + * non-compliant (not all zero) + */ + udf_err(sb, "bitmap for partition %d corrupted (block %u marked" + " as free, partition length is %u)\n", partition, + newblock, sbi->s_partmaps[partition].s_partition_len); + goto error_return; + } + if (!udf_clear_bit(bit, bh->b_data)) { udf_debug("bit already cleared for block %d\n", bit); goto repeat; diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h index 9f24bd1a9f44..fb7f2c7bec9c 100644 --- a/fs/udf/ecma_167.h +++ b/fs/udf/ecma_167.h @@ -88,6 +88,20 @@ struct regid { #define ENTITYID_FLAGS_DIRTY 0x00 #define ENTITYID_FLAGS_PROTECTED 0x01 +/* OSTA UDF 2.1.5.2 */ +#define UDF_ID_COMPLIANT "*OSTA UDF Compliant" + +/* OSTA UDF 2.1.5.3 */ +struct domainEntityIDSuffix { + uint16_t revision; + uint8_t flags; + uint8_t reserved[5]; +}; + +/* OSTA UDF 2.1.5.3 */ +#define ENTITYIDSUFFIX_FLAGS_HARDWRITEPROTECT 0 +#define ENTITYIDSUFFIX_FLAGS_SOFTWRITEPROTECT 1 + /* Volume Structure Descriptor (ECMA 167r3 2/9.1) */ #define VSD_STD_ID_LEN 5 struct volStructDesc { diff --git a/fs/udf/file.c b/fs/udf/file.c index cd31e4f6d6da..628941a6b79a 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -280,6 +280,9 @@ static int udf_setattr(struct dentry *dentry, struct iattr *attr) return error; } + if (attr->ia_valid & ATTR_MODE) + udf_update_extra_perms(inode, attr->ia_mode); + setattr_copy(inode, attr); mark_inode_dirty(inode); return 0; diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index f8e5872f7cc2..0adb40718a5d 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c @@ -118,6 +118,9 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode) iinfo->i_lenAlloc = 0; iinfo->i_use = 0; iinfo->i_checkpoint = 1; + iinfo->i_extraPerms = FE_PERM_U_CHATTR; + udf_update_extra_perms(inode, mode); + if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB)) iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 9bb18311a22f..ea80036d7897 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -45,6 +45,13 @@ #define EXTENT_MERGE_SIZE 5 +#define FE_MAPPED_PERMS (FE_PERM_U_READ | FE_PERM_U_WRITE | FE_PERM_U_EXEC | \ + FE_PERM_G_READ | FE_PERM_G_WRITE | FE_PERM_G_EXEC | \ + FE_PERM_O_READ | FE_PERM_O_WRITE | FE_PERM_O_EXEC) + +#define FE_DELETE_PERMS (FE_PERM_U_DELETE | FE_PERM_G_DELETE | \ + FE_PERM_O_DELETE) + static umode_t udf_convert_permissions(struct fileEntry *); static int udf_update_inode(struct inode *, int); static int udf_sync_inode(struct inode *inode); @@ -1458,6 +1465,8 @@ reread: else inode->i_mode = udf_convert_permissions(fe); inode->i_mode &= ~sbi->s_umask; + iinfo->i_extraPerms = le32_to_cpu(fe->permissions) & ~FE_MAPPED_PERMS; + read_unlock(&sbi->s_cred_lock); link_count = le16_to_cpu(fe->fileLinkCount); @@ -1485,6 +1494,8 @@ reread: iinfo->i_lenEAttr = le32_to_cpu(fe->lengthExtendedAttr); iinfo->i_lenAlloc = le32_to_cpu(fe->lengthAllocDescs); iinfo->i_checkpoint = le32_to_cpu(fe->checkpoint); + iinfo->i_streamdir = 0; + iinfo->i_lenStreams = 0; } else { inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << (inode->i_sb->s_blocksize_bits - 9); @@ -1498,6 +1509,16 @@ reread: iinfo->i_lenEAttr = le32_to_cpu(efe->lengthExtendedAttr); iinfo->i_lenAlloc = le32_to_cpu(efe->lengthAllocDescs); iinfo->i_checkpoint = le32_to_cpu(efe->checkpoint); + + /* Named streams */ + iinfo->i_streamdir = (efe->streamDirectoryICB.extLength != 0); + iinfo->i_locStreamdir = + lelb_to_cpu(efe->streamDirectoryICB.extLocation); + iinfo->i_lenStreams = le64_to_cpu(efe->objectSize); + if (iinfo->i_lenStreams >= inode->i_size) + iinfo->i_lenStreams -= inode->i_size; + else + iinfo->i_lenStreams = 0; } inode->i_generation = iinfo->i_unique; @@ -1619,6 +1640,23 @@ static umode_t udf_convert_permissions(struct fileEntry *fe) return mode; } +void udf_update_extra_perms(struct inode *inode, umode_t mode) +{ + struct udf_inode_info *iinfo = UDF_I(inode); + + /* + * UDF 2.01 sec. 3.3.3.3 Note 2: + * In Unix, delete permission tracks write + */ + iinfo->i_extraPerms &= ~FE_DELETE_PERMS; + if (mode & 0200) + iinfo->i_extraPerms |= FE_PERM_U_DELETE; + if (mode & 0020) + iinfo->i_extraPerms |= FE_PERM_G_DELETE; + if (mode & 0002) + iinfo->i_extraPerms |= FE_PERM_O_DELETE; +} + int udf_write_inode(struct inode *inode, struct writeback_control *wbc) { return udf_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); @@ -1691,10 +1729,7 @@ static int udf_update_inode(struct inode *inode, int do_sync) ((inode->i_mode & 0070) << 2) | ((inode->i_mode & 0700) << 4); - udfperms |= (le32_to_cpu(fe->permissions) & - (FE_PERM_O_DELETE | FE_PERM_O_CHATTR | - FE_PERM_G_DELETE | FE_PERM_G_CHATTR | - FE_PERM_U_DELETE | FE_PERM_U_CHATTR)); + udfperms |= iinfo->i_extraPerms; fe->permissions = cpu_to_le32(udfperms); if (S_ISDIR(inode->i_mode) && inode->i_nlink > 0) @@ -1760,9 +1795,19 @@ static int udf_update_inode(struct inode *inode, int do_sync) iinfo->i_ext.i_data, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); - efe->objectSize = cpu_to_le64(inode->i_size); + efe->objectSize = + cpu_to_le64(inode->i_size + iinfo->i_lenStreams); efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded); + if (iinfo->i_streamdir) { + struct long_ad *icb_lad = &efe->streamDirectoryICB; + + icb_lad->extLocation = + cpu_to_lelb(iinfo->i_locStreamdir); + icb_lad->extLength = + cpu_to_le32(inode->i_sb->s_blocksize); + } + udf_adjust_time(iinfo, inode->i_atime); udf_adjust_time(iinfo, inode->i_mtime); udf_adjust_time(iinfo, inode->i_ctime); diff --git a/fs/udf/super.c b/fs/udf/super.c index a14346137361..8c28e93e9b73 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -92,10 +92,6 @@ static void udf_put_super(struct super_block *); static int udf_sync_fs(struct super_block *, int); static int udf_remount_fs(struct super_block *, int *, char *); 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 *, - 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 *); @@ -151,9 +147,11 @@ static struct inode *udf_alloc_inode(struct super_block *sb) ei->i_unique = 0; ei->i_lenExtents = 0; + ei->i_lenStreams = 0; ei->i_next_alloc_block = 0; ei->i_next_alloc_goal = 0; ei->i_strat4096 = 0; + ei->i_streamdir = 0; init_rwsem(&ei->i_data_sem); ei->cached_extent.lstart = -1; spin_lock_init(&ei->i_extent_cache_lock); @@ -271,8 +269,7 @@ static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) int nr_groups = bitmap->s_nr_groups; for (i = 0; i < nr_groups; i++) - if (bitmap->s_block_bitmap[i]) - brelse(bitmap->s_block_bitmap[i]); + brelse(bitmap->s_block_bitmap[i]); kvfree(bitmap); } @@ -646,16 +643,67 @@ out_unlock: return error; } -/* 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) +/* + * Check VSD descriptor. Returns -1 in case we are at the end of volume + * recognition area, 0 if the descriptor is valid but non-interesting, 1 if + * we found one of NSR descriptors we are looking for. + */ +static int identify_vsd(const struct volStructDesc *vsd) +{ + int ret = 0; + + if (!memcmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) { + switch (vsd->structType) { + case 0: + udf_debug("ISO9660 Boot Record found\n"); + break; + case 1: + udf_debug("ISO9660 Primary Volume Descriptor found\n"); + break; + case 2: + udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); + break; + case 3: + udf_debug("ISO9660 Volume Partition Descriptor found\n"); + break; + case 255: + udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); + break; + default: + udf_debug("ISO9660 VRS (%u) found\n", vsd->structType); + break; + } + } else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) + ; /* ret = 0 */ + else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) + ret = 1; + else if (!memcmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) + ret = 1; + else if (!memcmp(vsd->stdIdent, VSD_STD_ID_BOOT2, VSD_STD_ID_LEN)) + ; /* ret = 0 */ + else if (!memcmp(vsd->stdIdent, VSD_STD_ID_CDW02, VSD_STD_ID_LEN)) + ; /* ret = 0 */ + else { + /* TEA01 or invalid id : end of volume recognition area */ + ret = -1; + } + + return ret; +} + +/* + * Check Volume Structure Descriptors (ECMA 167 2/9.1) + * We also check any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) + * @return 1 if NSR02 or NSR03 found, + * -1 if first sector read error, 0 otherwise + */ +static int udf_check_vsd(struct super_block *sb) { struct volStructDesc *vsd = NULL; loff_t sector = VSD_FIRST_SECTOR_OFFSET; int sectorsize; struct buffer_head *bh = NULL; - int nsr02 = 0; - int nsr03 = 0; + int nsr = 0; struct udf_sb_info *sbi; sbi = UDF_SB(sb); @@ -679,71 +727,36 @@ static loff_t udf_check_vsd(struct super_block *sb) * 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) { + for (; !nsr && sector < VSD_MAX_SECTOR_OFFSET; sector += sectorsize) { /* Read a block */ bh = udf_tread(sb, sector >> sb->s_blocksize_bits); if (!bh) break; - /* Look for ISO descriptors */ vsd = (struct volStructDesc *)(bh->b_data + (sector & (sb->s_blocksize - 1))); - - if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, - VSD_STD_ID_LEN)) { - switch (vsd->structType) { - case 0: - udf_debug("ISO9660 Boot Record found\n"); - break; - case 1: - udf_debug("ISO9660 Primary Volume Descriptor found\n"); - break; - case 2: - udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); - break; - case 3: - udf_debug("ISO9660 Volume Partition Descriptor found\n"); - break; - case 255: - 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)) - ; /* 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)) - nsr02 = sector; - 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 */ + nsr = identify_vsd(vsd); + /* Found NSR or end? */ + if (nsr) { brelse(bh); break; } + /* + * Special handling for improperly formatted VRS (e.g., Win10) + * where components are separated by 2048 bytes even though + * sectors are 4K + */ + if (sb->s_blocksize == 4096) { + nsr = identify_vsd(vsd + 1); + /* Ignore unknown IDs... */ + if (nsr < 0) + nsr = 0; + } brelse(bh); } - if (nsr03) - return nsr03; - else if (nsr02) - return nsr02; + if (nsr > 0) + return 1; else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) == VSD_FIRST_SECTOR_OFFSET) return -1; @@ -751,34 +764,82 @@ static loff_t udf_check_vsd(struct super_block *sb) return 0; } +static int udf_verify_domain_identifier(struct super_block *sb, + struct regid *ident, char *dname) +{ + struct domainEntityIDSuffix *suffix; + + if (memcmp(ident->ident, UDF_ID_COMPLIANT, strlen(UDF_ID_COMPLIANT))) { + udf_warn(sb, "Not OSTA UDF compliant %s descriptor.\n", dname); + goto force_ro; + } + if (ident->flags & (1 << ENTITYID_FLAGS_DIRTY)) { + udf_warn(sb, "Possibly not OSTA UDF compliant %s descriptor.\n", + dname); + goto force_ro; + } + suffix = (struct domainEntityIDSuffix *)ident->identSuffix; + if (suffix->flags & (1 << ENTITYIDSUFFIX_FLAGS_HARDWRITEPROTECT) || + suffix->flags & (1 << ENTITYIDSUFFIX_FLAGS_SOFTWRITEPROTECT)) { + if (!sb_rdonly(sb)) { + udf_warn(sb, "Descriptor for %s marked write protected." + " Forcing read only mount.\n", dname); + } + goto force_ro; + } + return 0; + +force_ro: + if (!sb_rdonly(sb)) + return -EACCES; + UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); + return 0; +} + +static int udf_load_fileset(struct super_block *sb, struct fileSetDesc *fset, + struct kernel_lb_addr *root) +{ + int ret; + + ret = udf_verify_domain_identifier(sb, &fset->domainIdent, "file set"); + if (ret < 0) + return ret; + + *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); + UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum); + + udf_debug("Rootdir at block=%u, partition=%u\n", + root->logicalBlockNum, root->partitionReferenceNum); + return 0; +} + static int udf_find_fileset(struct super_block *sb, struct kernel_lb_addr *fileset, struct kernel_lb_addr *root) { struct buffer_head *bh = NULL; uint16_t ident; + int ret; - if (fileset->logicalBlockNum != 0xFFFFFFFF || - fileset->partitionReferenceNum != 0xFFFF) { - bh = udf_read_ptagged(sb, fileset, 0, &ident); - - if (!bh) { - return 1; - } else if (ident != TAG_IDENT_FSD) { - brelse(bh); - return 1; - } - - udf_debug("Fileset at block=%u, partition=%u\n", - fileset->logicalBlockNum, - fileset->partitionReferenceNum); + if (fileset->logicalBlockNum == 0xFFFFFFFF && + fileset->partitionReferenceNum == 0xFFFF) + return -EINVAL; - UDF_SB(sb)->s_partition = fileset->partitionReferenceNum; - udf_load_fileset(sb, bh, root); + bh = udf_read_ptagged(sb, fileset, 0, &ident); + if (!bh) + return -EIO; + if (ident != TAG_IDENT_FSD) { brelse(bh); - return 0; + return -EINVAL; } - return 1; + + udf_debug("Fileset at block=%u, partition=%u\n", + fileset->logicalBlockNum, fileset->partitionReferenceNum); + + UDF_SB(sb)->s_partition = fileset->partitionReferenceNum; + ret = udf_load_fileset(sb, (struct fileSetDesc *)bh->b_data, root); + brelse(bh); + return ret; } /* @@ -794,9 +855,7 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) struct buffer_head *bh; uint16_t ident; int ret = -ENOMEM; -#ifdef UDFFS_DEBUG struct timestamp *ts; -#endif outstr = kmalloc(128, GFP_NOFS); if (!outstr) @@ -817,13 +876,10 @@ static int udf_load_pvoldesc(struct super_block *sb, sector_t block) udf_disk_stamp_to_time(&UDF_SB(sb)->s_record_time, pvoldesc->recordingDateAndTime); -#ifdef UDFFS_DEBUG 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 - ret = udf_dstrCS0toChar(sb, outstr, 31, pvoldesc->volIdent, 32); if (ret < 0) { @@ -939,21 +995,6 @@ static int udf_load_metadata_files(struct super_block *sb, int partition, return 0; } -static void udf_load_fileset(struct super_block *sb, struct buffer_head *bh, - struct kernel_lb_addr *root) -{ - struct fileSetDesc *fset; - - fset = (struct fileSetDesc *)bh->b_data; - - *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); - - UDF_SB(sb)->s_serial_number = le16_to_cpu(fset->descTag.tagSerialNum); - - udf_debug("Rootdir at block=%u, partition=%u\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]; @@ -1238,9 +1279,7 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block) * 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]; @@ -1364,6 +1403,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, goto out_bh; } + ret = udf_verify_domain_identifier(sb, &lvd->domainIdent, + "logical volume"); + if (ret) + goto out_bh; ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); if (ret) goto out_bh; @@ -1915,7 +1958,7 @@ 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 nsr = 0; int ret; if (!sb_set_blocksize(sb, uopt->blocksize)) { @@ -1926,13 +1969,13 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, sbi->s_last_block = uopt->lastblock; if (!uopt->novrs) { /* Check that it is NSR02 compliant */ - nsr_off = udf_check_vsd(sb); - if (!nsr_off) { + nsr = udf_check_vsd(sb); + if (!nsr) { if (!silent) udf_warn(sb, "No VRS found\n"); return -EINVAL; } - if (nsr_off == -1) + if (nsr == -1) udf_debug("Failed to read sector at offset %d. " "Assuming open disc. Skipping validity " "check\n", VSD_FIRST_SECTOR_OFFSET); @@ -2216,9 +2259,9 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) UDF_SET_FLAG(sb, UDF_FLAG_RW_INCOMPAT); } - if (udf_find_fileset(sb, &fileset, &rootdir)) { + ret = udf_find_fileset(sb, &fileset, &rootdir); + if (ret < 0) { udf_warn(sb, "No fileset found\n"); - ret = -EINVAL; goto error_out; } diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h index 2ef0e212f08a..4245d1f63258 100644 --- a/fs/udf/udf_i.h +++ b/fs/udf/udf_i.h @@ -38,16 +38,20 @@ struct udf_inode_info { __u32 i_next_alloc_block; __u32 i_next_alloc_goal; __u32 i_checkpoint; + __u32 i_extraPerms; unsigned i_alloc_type : 3; unsigned i_efe : 1; /* extendedFileEntry */ unsigned i_use : 1; /* unallocSpaceEntry */ unsigned i_strat4096 : 1; - unsigned reserved : 26; + unsigned i_streamdir : 1; + unsigned reserved : 25; union { struct short_ad *i_sad; struct long_ad *i_lad; __u8 *i_data; } i_ext; + struct kernel_lb_addr i_locStreamdir; + __u64 i_lenStreams; struct rw_semaphore i_data_sem; struct udf_ext_cache cached_extent; /* Spinlock for protecting extent cache */ diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index d89ef71887fc..9dd0814f1077 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -31,16 +31,8 @@ extern __printf(3, 4) void _udf_warn(struct super_block *sb, #define udf_info(fmt, ...) \ pr_info("INFO " fmt, ##__VA_ARGS__) -#undef UDFFS_DEBUG - -#ifdef UDFFS_DEBUG -#define udf_debug(fmt, ...) \ - printk(KERN_DEBUG pr_fmt("%s:%d:%s: " fmt), \ - __FILE__, __LINE__, __func__, ##__VA_ARGS__) -#else #define udf_debug(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) -#endif + pr_debug("%s:%d:%s: " fmt, __FILE__, __LINE__, __func__, ##__VA_ARGS__) #define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) ) #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) @@ -178,6 +170,7 @@ extern int8_t udf_next_aext(struct inode *, struct extent_position *, struct kernel_lb_addr *, uint32_t *, int); extern int8_t udf_current_aext(struct inode *, struct extent_position *, struct kernel_lb_addr *, uint32_t *, int); +extern void udf_update_extra_perms(struct inode *inode, umode_t mode); /* misc.c */ extern struct buffer_head *udf_tgetblk(struct super_block *sb, |