mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
\n
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEq1nRK9aeMoq1VSgcnJ2qBz9kQNkFAl2EssMACgkQnJ2qBz9k QNn+LQgApjz2kxt/0foigI5WEdzrS7aFDwyH9NMNRN8b5+cTlYcZCv/UWk8OOtKY bZL5WJetmTan7K+6iFozbIICx/FVij9eIPpqHCxVV34huyHb8pdEH5kn/K0Zos3g h+J9+6efwHuyuWDCWVYYPUAtSIRTNbdF3lCCvaiO/V2AKhqejtRt9u2/LK+eJAKv k7tnuYi0R26HmSabTZMRcMiexRBuCsmCfxvZ01z93htCucAhc4BEJvCaQCgPQKGT vnr+rb7QxrakO0zB0v5MWjv6FveDq+5IzKTYz7OHhiitWeXZz+ATYMeXFL2tjfJH 18BbnalcksQJOqq95yPxwtKZ/2tPKQ== =CNjT -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
7ce1e15d9a
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
261
fs/udf/super.c
261
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 (fileset->logicalBlockNum == 0xFFFFFFFF &&
|
||||
fileset->partitionReferenceNum == 0xFFFF)
|
||||
return -EINVAL;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
@ -22,7 +22,7 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb)
|
||||
/* i_mutex must being held */
|
||||
static inline bool is_quota_modification(struct inode *inode, struct iattr *ia)
|
||||
{
|
||||
return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) ||
|
||||
return (ia->ia_valid & ATTR_SIZE) ||
|
||||
(ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) ||
|
||||
(ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user