From 88b50ce3ab5af60c85905784c938a35c967addf4 Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Mon, 2 Jan 2017 19:20:55 -0800 Subject: fs: udf: Replace CURRENT_TIME with current_time() CURRENT_TIME is not y2038 safe. CURRENT_TIME macro is also not appropriate for filesystems as it doesn't use the right granularity for filesystem timestamps. Logical Volume Integrity format is described to have the same timestamp format for "Recording Date and time" as the other [a,c,m]timestamps. The function udf_time_to_disk_format() does this conversion. Hence the timestamp is passed directly to the function and not truncated. This is as per Arnd's suggestion on the thread. This is also in preparation for the patch that transitions vfs timestamps to use 64 bit time and hence make them y2038 safe. As part of the effort current_time() will be extended to do range checks. Signed-off-by: Deepa Dinamani Reviewed-by: Jan Kara Reviewed-by: Arnd Bergmann Signed-off-by: Jan Kara --- fs/udf/super.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 4942549e7dc8..967ad8775af2 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1986,6 +1986,7 @@ static void udf_open_lvid(struct super_block *sb) struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDescImpUse *lvidiu; + struct timespec ts; if (!bh) return; @@ -1997,8 +1998,8 @@ static void udf_open_lvid(struct super_block *sb) mutex_lock(&sbi->s_alloc_mutex); lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, - CURRENT_TIME); + ktime_get_real_ts(&ts); + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN); lvid->descTag.descCRC = cpu_to_le16( @@ -2019,6 +2020,7 @@ static void udf_close_lvid(struct super_block *sb) struct buffer_head *bh = sbi->s_lvid_bh; struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDescImpUse *lvidiu; + struct timespec ts; if (!bh) return; @@ -2030,7 +2032,8 @@ static void udf_close_lvid(struct super_block *sb) mutex_lock(&sbi->s_alloc_mutex); lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; - udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); + ktime_get_real_ts(&ts); + udf_time_to_disk_stamp(&lvid->recordingDateAndTime, ts); 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)) -- cgit v1.2.3 From a17f0cb5b9eaf8212b396d2381cf7594cd5315c7 Mon Sep 17 00:00:00 2001 From: Steve Kenton Date: Mon, 2 Jan 2017 13:25:34 -0500 Subject: fs/udf: make #ifdef UDF_PREALLOCATE unconditional Signed-off-by: Steve Kenton Signed-off-by: Jan Kara --- fs/udf/inode.c | 2 -- fs/udf/udfdecl.h | 1 - 2 files changed, 3 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 0f3db71753aa..3a5ac2221a88 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -857,14 +857,12 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, * block */ udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); -#ifdef UDF_PREALLOCATE /* We preallocate blocks only for regular files. It also makes sense * for directories but there's a problem when to drop the * preallocation. We might use some delayed work for that but I feel * it's overengineering for a filesystem like UDF. */ if (S_ISREG(inode->i_mode)) udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); -#endif /* merge any continuous blocks in laarr */ udf_merge_extents(inode, laarr, &endnum); diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 263829ef1873..b608624e7089 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -15,7 +15,6 @@ #include "udfend.h" #include "udf_i.h" -#define UDF_PREALLOCATE #define UDF_DEFAULT_PREALLOC_BLOCKS 8 extern __printf(3, 4) void _udf_err(struct super_block *sb, -- cgit v1.2.3 From ad4d05329df5e9825cac3132e12453a6c12915b8 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 2 Jan 2017 14:30:31 +0100 Subject: udf: Make stat on symlink report symlink length as st_size UDF encodes symlinks in a more complex fashion and thus i_size of a symlink does not match the lenght of a string returned by readlink(2). This confuses some applications (see bug 191241) and may be considered a violation of POSIX. Fix the problem by reading the link into page cache in response to stat(2) call and report the length of the decoded path. Signed-off-by: Jan Kara --- fs/udf/inode.c | 2 +- fs/udf/namei.c | 2 +- fs/udf/symlink.c | 30 ++++++++++++++++++++++++++++++ fs/udf/udfdecl.h | 1 + 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 3a5ac2221a88..5f643c93f564 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1547,7 +1547,7 @@ reread: break; case ICBTAG_FILE_TYPE_SYMLINK: inode->i_data.a_ops = &udf_symlink_aops; - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &udf_symlink_inode_operations; inode_nohighmem(inode); inode->i_mode = S_IFLNK | S_IRWXUGO; break; diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 2d65e280748b..babf48d0e553 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -931,7 +931,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, } inode->i_data.a_ops = &udf_symlink_aops; - inode->i_op = &page_symlink_inode_operations; + inode->i_op = &udf_symlink_inode_operations; inode_nohighmem(inode); if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 8d619773056b..f7dfef53f739 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -152,9 +152,39 @@ out_unmap: return err; } +static int udf_symlink_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = d_backing_inode(dentry); + struct page *page; + + generic_fillattr(inode, stat); + page = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(page)) + return PTR_ERR(page); + /* + * UDF uses non-trivial encoding of symlinks so i_size does not match + * number of characters reported by readlink(2) which apparently some + * applications expect. Also POSIX says that "The value returned in the + * st_size field shall be the length of the contents of the symbolic + * link, and shall not count a trailing null if one is present." So + * let's report the length of string returned by readlink(2) for + * st_size. + */ + stat->size = strlen(page_address(page)); + put_page(page); + + return 0; +} + /* * symlinks can't do much... */ const struct address_space_operations udf_symlink_aops = { .readpage = udf_symlink_filler, }; + +const struct inode_operations udf_symlink_inode_operations = { + .get_link = page_get_link, + .getattr = udf_symlink_getattr, +}; diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index b608624e7089..63b034984378 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -84,6 +84,7 @@ extern const struct inode_operations udf_dir_inode_operations; extern const struct file_operations udf_dir_operations; extern const struct inode_operations udf_file_inode_operations; extern const struct file_operations udf_file_operations; +extern const struct inode_operations udf_symlink_inode_operations; extern const struct address_space_operations udf_aops; extern const struct address_space_operations udf_adinicb_aops; extern const struct address_space_operations udf_symlink_aops; -- cgit v1.2.3 From 75f271380d49798cc313174e9976aabc5197c93e Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:49 +0100 Subject: udf: use __packed instead of __attribute__ ((packed)) defined in linux/compiler-gcc.h Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/ecma_167.h | 98 +++++++++++++++++++++++++++---------------------------- fs/udf/osta_udf.h | 34 +++++++++---------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h index 4792b771aa80..9f24bd1a9f44 100644 --- a/fs/udf/ecma_167.h +++ b/fs/udf/ecma_167.h @@ -41,7 +41,7 @@ struct charspec { uint8_t charSetType; uint8_t charSetInfo[63]; -} __attribute__ ((packed)); +} __packed; /* Character Set Type (ECMA 167r3 1/7.2.1.1) */ #define CHARSPEC_TYPE_CS0 0x00 /* (1/7.2.2) */ @@ -68,7 +68,7 @@ struct timestamp { uint8_t centiseconds; uint8_t hundredsOfMicroseconds; uint8_t microseconds; -} __attribute__ ((packed)); +} __packed; /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ #define TIMESTAMP_TYPE_MASK 0xF000 @@ -82,7 +82,7 @@ struct regid { uint8_t flags; uint8_t ident[23]; uint8_t identSuffix[8]; -} __attribute__ ((packed)); +} __packed; /* Flags (ECMA 167r3 1/7.4.1) */ #define ENTITYID_FLAGS_DIRTY 0x00 @@ -95,7 +95,7 @@ struct volStructDesc { uint8_t stdIdent[VSD_STD_ID_LEN]; uint8_t structVersion; uint8_t structData[2041]; -} __attribute__ ((packed)); +} __packed; /* Standard Identifier (EMCA 167r2 2/9.1.2) */ #define VSD_STD_ID_NSR02 "NSR02" /* (3/9.1) */ @@ -114,7 +114,7 @@ struct beginningExtendedAreaDesc { uint8_t stdIdent[VSD_STD_ID_LEN]; uint8_t structVersion; uint8_t structData[2041]; -} __attribute__ ((packed)); +} __packed; /* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */ struct terminatingExtendedAreaDesc { @@ -122,7 +122,7 @@ struct terminatingExtendedAreaDesc { uint8_t stdIdent[VSD_STD_ID_LEN]; uint8_t structVersion; uint8_t structData[2041]; -} __attribute__ ((packed)); +} __packed; /* Boot Descriptor (ECMA 167r3 2/9.4) */ struct bootDesc { @@ -140,7 +140,7 @@ struct bootDesc { __le16 flags; uint8_t reserved2[32]; uint8_t bootUse[1906]; -} __attribute__ ((packed)); +} __packed; /* Flags (ECMA 167r3 2/9.4.12) */ #define BOOT_FLAGS_ERASE 0x01 @@ -149,7 +149,7 @@ struct bootDesc { struct extent_ad { __le32 extLength; __le32 extLocation; -} __attribute__ ((packed)); +} __packed; struct kernel_extent_ad { uint32_t extLength; @@ -166,7 +166,7 @@ struct tag { __le16 descCRC; __le16 descCRCLength; __le32 tagLocation; -} __attribute__ ((packed)); +} __packed; /* Tag Identifier (ECMA 167r3 3/7.2.1) */ #define TAG_IDENT_PVD 0x0001 @@ -186,7 +186,7 @@ struct NSRDesc { uint8_t structVersion; uint8_t reserved; uint8_t structData[2040]; -} __attribute__ ((packed)); +} __packed; /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */ struct primaryVolDesc { @@ -212,7 +212,7 @@ struct primaryVolDesc { __le32 predecessorVolDescSeqLocation; __le16 flags; uint8_t reserved[22]; -} __attribute__ ((packed)); +} __packed; /* Flags (ECMA 167r3 3/10.1.21) */ #define PVD_FLAGS_VSID_COMMON 0x0001 @@ -223,7 +223,7 @@ struct anchorVolDescPtr { struct extent_ad mainVolDescSeqExt; struct extent_ad reserveVolDescSeqExt; uint8_t reserved[480]; -} __attribute__ ((packed)); +} __packed; /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */ struct volDescPtr { @@ -231,7 +231,7 @@ struct volDescPtr { __le32 volDescSeqNum; struct extent_ad nextVolDescSeqExt; uint8_t reserved[484]; -} __attribute__ ((packed)); +} __packed; /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */ struct impUseVolDesc { @@ -239,7 +239,7 @@ struct impUseVolDesc { __le32 volDescSeqNum; struct regid impIdent; uint8_t impUse[460]; -} __attribute__ ((packed)); +} __packed; /* Partition Descriptor (ECMA 167r3 3/10.5) */ struct partitionDesc { @@ -255,7 +255,7 @@ struct partitionDesc { struct regid impIdent; uint8_t impUse[128]; uint8_t reserved[156]; -} __attribute__ ((packed)); +} __packed; /* Partition Flags (ECMA 167r3 3/10.5.3) */ #define PD_PARTITION_FLAGS_ALLOC 0x0001 @@ -291,14 +291,14 @@ struct logicalVolDesc { uint8_t impUse[128]; struct extent_ad integritySeqExt; uint8_t partitionMaps[0]; -} __attribute__ ((packed)); +} __packed; /* Generic Partition Map (ECMA 167r3 3/10.7.1) */ struct genericPartitionMap { uint8_t partitionMapType; uint8_t partitionMapLength; uint8_t partitionMapping[0]; -} __attribute__ ((packed)); +} __packed; /* Partition Map Type (ECMA 167r3 3/10.7.1.1) */ #define GP_PARTITION_MAP_TYPE_UNDEF 0x00 @@ -311,14 +311,14 @@ struct genericPartitionMap1 { uint8_t partitionMapLength; __le16 volSeqNum; __le16 partitionNum; -} __attribute__ ((packed)); +} __packed; /* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */ struct genericPartitionMap2 { uint8_t partitionMapType; uint8_t partitionMapLength; uint8_t partitionIdent[62]; -} __attribute__ ((packed)); +} __packed; /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */ struct unallocSpaceDesc { @@ -326,13 +326,13 @@ struct unallocSpaceDesc { __le32 volDescSeqNum; __le32 numAllocDescs; struct extent_ad allocDescs[0]; -} __attribute__ ((packed)); +} __packed; /* Terminating Descriptor (ECMA 167r3 3/10.9) */ struct terminatingDesc { struct tag descTag; uint8_t reserved[496]; -} __attribute__ ((packed)); +} __packed; /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */ struct logicalVolIntegrityDesc { @@ -346,7 +346,7 @@ struct logicalVolIntegrityDesc { __le32 freeSpaceTable[0]; __le32 sizeTable[0]; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Integrity Type (ECMA 167r3 3/10.10.3) */ #define LVID_INTEGRITY_TYPE_OPEN 0x00000000 @@ -356,7 +356,7 @@ struct logicalVolIntegrityDesc { struct lb_addr { __le32 logicalBlockNum; __le16 partitionReferenceNum; -} __attribute__ ((packed)); +} __packed; /* ... and its in-core analog */ struct kernel_lb_addr { @@ -368,14 +368,14 @@ struct kernel_lb_addr { struct short_ad { __le32 extLength; __le32 extPosition; -} __attribute__ ((packed)); +} __packed; /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */ struct long_ad { __le32 extLength; struct lb_addr extLocation; uint8_t impUse[6]; -} __attribute__ ((packed)); +} __packed; struct kernel_long_ad { uint32_t extLength; @@ -389,7 +389,7 @@ struct ext_ad { __le32 recordedLength; __le32 informationLength; struct lb_addr extLocation; -} __attribute__ ((packed)); +} __packed; struct kernel_ext_ad { uint32_t extLength; @@ -434,7 +434,7 @@ struct fileSetDesc { struct long_ad nextExt; struct long_ad streamDirectoryICB; uint8_t reserved[32]; -} __attribute__ ((packed)); +} __packed; /* Partition Header Descriptor (ECMA 167r3 4/14.3) */ struct partitionHeaderDesc { @@ -444,7 +444,7 @@ struct partitionHeaderDesc { struct short_ad freedSpaceTable; struct short_ad freedSpaceBitmap; uint8_t reserved[88]; -} __attribute__ ((packed)); +} __packed; /* File Identifier Descriptor (ECMA 167r3 4/14.4) */ struct fileIdentDesc { @@ -457,7 +457,7 @@ struct fileIdentDesc { uint8_t impUse[0]; uint8_t fileIdent[0]; uint8_t padding[0]; -} __attribute__ ((packed)); +} __packed; /* File Characteristics (ECMA 167r3 4/14.4.3) */ #define FID_FILE_CHAR_HIDDEN 0x01 @@ -471,7 +471,7 @@ struct allocExtDesc { struct tag descTag; __le32 previousAllocExtLocation; __le32 lengthAllocDescs; -} __attribute__ ((packed)); +} __packed; /* ICB Tag (ECMA 167r3 4/14.6) */ struct icbtag { @@ -483,7 +483,7 @@ struct icbtag { uint8_t fileType; struct lb_addr parentICBLocation; __le16 flags; -} __attribute__ ((packed)); +} __packed; /* Strategy Type (ECMA 167r3 4/14.6.2) */ #define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000 @@ -531,13 +531,13 @@ struct indirectEntry { struct tag descTag; struct icbtag icbTag; struct long_ad indirectICB; -} __attribute__ ((packed)); +} __packed; /* Terminal Entry (ECMA 167r3 4/14.8) */ struct terminalEntry { struct tag descTag; struct icbtag icbTag; -} __attribute__ ((packed)); +} __packed; /* File Entry (ECMA 167r3 4/14.9) */ struct fileEntry { @@ -563,7 +563,7 @@ struct fileEntry { __le32 lengthAllocDescs; uint8_t extendedAttr[0]; uint8_t allocDescs[0]; -} __attribute__ ((packed)); +} __packed; /* Permissions (ECMA 167r3 4/14.9.5) */ #define FE_PERM_O_EXEC 0x00000001U @@ -607,7 +607,7 @@ struct extendedAttrHeaderDesc { struct tag descTag; __le32 impAttrLocation; __le32 appAttrLocation; -} __attribute__ ((packed)); +} __packed; /* Generic Format (ECMA 167r3 4/14.10.2) */ struct genericFormat { @@ -616,7 +616,7 @@ struct genericFormat { uint8_t reserved[3]; __le32 attrLength; uint8_t attrData[0]; -} __attribute__ ((packed)); +} __packed; /* Character Set Information (ECMA 167r3 4/14.10.3) */ struct charSetInfo { @@ -627,7 +627,7 @@ struct charSetInfo { __le32 escapeSeqLength; uint8_t charSetType; uint8_t escapeSeq[0]; -} __attribute__ ((packed)); +} __packed; /* Alternate Permissions (ECMA 167r3 4/14.10.4) */ struct altPerms { @@ -638,7 +638,7 @@ struct altPerms { __le16 ownerIdent; __le16 groupIdent; __le16 permission; -} __attribute__ ((packed)); +} __packed; /* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */ struct fileTimesExtAttr { @@ -649,7 +649,7 @@ struct fileTimesExtAttr { __le32 dataLength; __le32 fileTimeExistence; uint8_t fileTimes; -} __attribute__ ((packed)); +} __packed; /* FileTimeExistence (ECMA 167r3 4/14.10.5.6) */ #define FTE_CREATION 0x00000001 @@ -666,7 +666,7 @@ struct infoTimesExtAttr { __le32 dataLength; __le32 infoTimeExistence; uint8_t infoTimes[0]; -} __attribute__ ((packed)); +} __packed; /* Device Specification (ECMA 167r3 4/14.10.7) */ struct deviceSpec { @@ -678,7 +678,7 @@ struct deviceSpec { __le32 majorDeviceIdent; __le32 minorDeviceIdent; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */ struct impUseExtAttr { @@ -689,7 +689,7 @@ struct impUseExtAttr { __le32 impUseLength; struct regid impIdent; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */ struct appUseExtAttr { @@ -700,7 +700,7 @@ struct appUseExtAttr { __le32 appUseLength; struct regid appIdent; uint8_t appUse[0]; -} __attribute__ ((packed)); +} __packed; #define EXTATTR_CHAR_SET 1 #define EXTATTR_ALT_PERMS 3 @@ -716,7 +716,7 @@ struct unallocSpaceEntry { struct icbtag icbTag; __le32 lengthAllocDescs; uint8_t allocDescs[0]; -} __attribute__ ((packed)); +} __packed; /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */ struct spaceBitmapDesc { @@ -724,7 +724,7 @@ struct spaceBitmapDesc { __le32 numOfBits; __le32 numOfBytes; uint8_t bitmap[0]; -} __attribute__ ((packed)); +} __packed; /* Partition Integrity Entry (ECMA 167r3 4/14.13) */ struct partitionIntegrityEntry { @@ -735,7 +735,7 @@ struct partitionIntegrityEntry { uint8_t reserved[175]; struct regid impIdent; uint8_t impUse[256]; -} __attribute__ ((packed)); +} __packed; /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */ @@ -753,7 +753,7 @@ struct partitionIntegrityEntry { struct logicalVolHeaderDesc { __le64 uniqueID; uint8_t reserved[24]; -} __attribute__ ((packed)); +} __packed; /* Path Component (ECMA 167r3 4/14.16.1) */ struct pathComponent { @@ -761,7 +761,7 @@ struct pathComponent { uint8_t lengthComponentIdent; __le16 componentFileVersionNum; dstring componentIdent[0]; -} __attribute__ ((packed)); +} __packed; /* File Entry (ECMA 167r3 4/14.17) */ struct extendedFileEntry { @@ -791,6 +791,6 @@ struct extendedFileEntry { __le32 lengthAllocDescs; uint8_t extendedAttr[0]; uint8_t allocDescs[0]; -} __attribute__ ((packed)); +} __packed; #endif /* _ECMA_167_H */ diff --git a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h index fbff74654df2..a4da59e38b7f 100644 --- a/fs/udf/osta_udf.h +++ b/fs/udf/osta_udf.h @@ -70,17 +70,17 @@ struct UDFIdentSuffix { uint8_t OSClass; uint8_t OSIdentifier; uint8_t reserved[4]; -} __attribute__ ((packed)); +} __packed; struct impIdentSuffix { uint8_t OSClass; uint8_t OSIdentifier; uint8_t reserved[6]; -} __attribute__ ((packed)); +} __packed; struct appIdentSuffix { uint8_t impUse[8]; -} __attribute__ ((packed)); +} __packed; /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */ /* Implementation Use (UDF 2.50 2.2.6.4) */ @@ -92,7 +92,7 @@ struct logicalVolIntegrityDescImpUse { __le16 minUDFWriteRev; __le16 maxUDFWriteRev; uint8_t impUse[0]; -} __attribute__ ((packed)); +} __packed; /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */ /* Implementation Use (UDF 2.50 2.2.7.2) */ @@ -104,7 +104,7 @@ struct impUseVolDescImpUse { dstring LVInfo3[36]; struct regid impIdent; uint8_t impUse[128]; -} __attribute__ ((packed)); +} __packed; struct udfPartitionMap2 { uint8_t partitionMapType; @@ -113,7 +113,7 @@ struct udfPartitionMap2 { struct regid partIdent; __le16 volSeqNum; __le16 partitionNum; -} __attribute__ ((packed)); +} __packed; /* Virtual Partition Map (UDF 2.50 2.2.8) */ struct virtualPartitionMap { @@ -124,7 +124,7 @@ struct virtualPartitionMap { __le16 volSeqNum; __le16 partitionNum; uint8_t reserved2[24]; -} __attribute__ ((packed)); +} __packed; /* Sparable Partition Map (UDF 2.50 2.2.9) */ struct sparablePartitionMap { @@ -139,7 +139,7 @@ struct sparablePartitionMap { uint8_t reserved2[1]; __le32 sizeSparingTable; __le32 locSparingTable[4]; -} __attribute__ ((packed)); +} __packed; /* Metadata Partition Map (UDF 2.4.0 2.2.10) */ struct metadataPartitionMap { @@ -156,14 +156,14 @@ struct metadataPartitionMap { __le16 alignUnitSize; uint8_t flags; uint8_t reserved2[5]; -} __attribute__ ((packed)); +} __packed; /* Virtual Allocation Table (UDF 1.5 2.2.10) */ struct virtualAllocationTable15 { __le32 VirtualSector[0]; struct regid vatIdent; __le32 previousVATICBLoc; -} __attribute__ ((packed)); +} __packed; #define ICBTAG_FILE_TYPE_VAT15 0x00U @@ -181,7 +181,7 @@ struct virtualAllocationTable20 { __le16 reserved; uint8_t impUse[0]; __le32 vatEntry[0]; -} __attribute__ ((packed)); +} __packed; #define ICBTAG_FILE_TYPE_VAT20 0xF8U @@ -189,7 +189,7 @@ struct virtualAllocationTable20 { struct sparingEntry { __le32 origLocation; __le32 mappedLocation; -} __attribute__ ((packed)); +} __packed; struct sparingTable { struct tag descTag; @@ -199,7 +199,7 @@ struct sparingTable { __le32 sequenceNum; struct sparingEntry mapEntry[0]; -} __attribute__ ((packed)); +} __packed; /* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */ #define ICBTAG_FILE_TYPE_MAIN 0xFA @@ -210,7 +210,7 @@ struct sparingTable { struct allocDescImpUse { __le16 flags; uint8_t impUse[4]; -} __attribute__ ((packed)); +} __packed; #define AD_IU_EXT_ERASED 0x0001 @@ -222,7 +222,7 @@ struct allocDescImpUse { struct freeEaSpace { __le16 headerChecksum; uint8_t freeEASpace[0]; -} __attribute__ ((packed)); +} __packed; /* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */ struct DVDCopyrightImpUse { @@ -230,14 +230,14 @@ struct DVDCopyrightImpUse { uint8_t CGMSInfo; uint8_t dataType; uint8_t protectionSystemInfo[4]; -} __attribute__ ((packed)); +} __packed; /* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */ /* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */ struct freeAppEASpace { __le16 headerChecksum; uint8_t freeEASpace[0]; -} __attribute__ ((packed)); +} __packed; /* UDF Defined System Stream (UDF 2.50 3.3.7) */ #define UDF_ID_UNIQUE_ID "*UDF Unique ID Mapping Data" -- cgit v1.2.3 From 3cc6f8444a9d9e4a167c575e4da7b6c6d626501a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:50 +0100 Subject: udf: use pointer for kernel_long_ad argument Having struct kernel_long_ad laarr[EXTENT_MERGE_SIZE] in all function arguments could be understood as by-value parameter. Use kernel_long_ad pointer for functions depending on inode_getblk() Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 5f643c93f564..8d8eda8379ca 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -57,14 +57,12 @@ static sector_t inode_getblk(struct inode *, sector_t, int *, int *); static int8_t udf_insert_aext(struct inode *, struct extent_position, struct kernel_lb_addr, uint32_t); static void udf_split_extents(struct inode *, int *, int, int, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int *); + struct kernel_long_ad *, int *); static void udf_prealloc_extents(struct inode *, int, int, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int *); -static void udf_merge_extents(struct inode *, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int *); -static void udf_update_extents(struct inode *, - struct kernel_long_ad[EXTENT_MERGE_SIZE], int, int, - struct extent_position *); + struct kernel_long_ad *, int *); +static void udf_merge_extents(struct inode *, struct kernel_long_ad *, int *); +static void udf_update_extents(struct inode *, struct kernel_long_ad *, int, + int, struct extent_position *); static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); static void __udf_clear_extent_cache(struct inode *inode) @@ -896,8 +894,7 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, } static void udf_split_extents(struct inode *inode, int *c, int offset, - int newblocknum, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], + int newblocknum, struct kernel_long_ad *laarr, int *endnum) { unsigned long blocksize = inode->i_sb->s_blocksize; @@ -961,7 +958,7 @@ static void udf_split_extents(struct inode *inode, int *c, int offset, } static void udf_prealloc_extents(struct inode *inode, int c, int lastblock, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], + struct kernel_long_ad *laarr, int *endnum) { int start, length = 0, currlength = 0, i; @@ -1056,8 +1053,7 @@ static void udf_prealloc_extents(struct inode *inode, int c, int lastblock, } } -static void udf_merge_extents(struct inode *inode, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], +static void udf_merge_extents(struct inode *inode, struct kernel_long_ad *laarr, int *endnum) { int i; @@ -1156,8 +1152,7 @@ static void udf_merge_extents(struct inode *inode, } } -static void udf_update_extents(struct inode *inode, - struct kernel_long_ad laarr[EXTENT_MERGE_SIZE], +static void udf_update_extents(struct inode *inode, struct kernel_long_ad *laarr, int startnum, int endnum, struct extent_position *epos) { -- cgit v1.2.3 From 02d4ca49fa222021988b2791c8efefd70d3228ac Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:51 +0100 Subject: udf: merge bh free Merge all bh free at one place. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 8d8eda8379ca..582d6b2f0d5f 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -745,11 +745,8 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, ~(inode->i_sb->s_blocksize - 1)); udf_write_aext(inode, &cur_epos, &eloc, elen, 1); } - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); newblock = udf_get_lb_pblock(inode->i_sb, &eloc, offset); - return newblock; + goto out_free; } /* Are we beyond EOF? */ @@ -772,11 +769,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, /* Create extents for the hole between EOF and offset */ ret = udf_do_extend_file(inode, &prev_epos, laarr, offset); if (ret < 0) { - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); *err = ret; - return 0; + newblock = 0; + goto out_free; } c = 0; offset = 0; @@ -839,11 +834,9 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, iinfo->i_location.partitionReferenceNum, goal, err); if (!newblocknum) { - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); *err = -ENOSPC; - return 0; + newblock = 0; + goto out_free; } if (isBeyondEOF) iinfo->i_lenExtents += inode->i_sb->s_blocksize; @@ -870,15 +863,11 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, * the new number of extents is less than the old number */ udf_update_extents(inode, laarr, startnum, endnum, &prev_epos); - brelse(prev_epos.bh); - brelse(cur_epos.bh); - brelse(next_epos.bh); - newblock = udf_get_pblock(inode->i_sb, newblocknum, iinfo->i_location.partitionReferenceNum, 0); if (!newblock) { *err = -EIO; - return 0; + goto out_free; } *new = 1; iinfo->i_next_alloc_block = block; @@ -889,7 +878,10 @@ static sector_t inode_getblk(struct inode *inode, sector_t block, udf_sync_inode(inode); else mark_inode_dirty(inode); - +out_free: + brelse(prev_epos.bh); + brelse(cur_epos.bh); + brelse(next_epos.bh); return newblock; } -- cgit v1.2.3 From bbc9abd239917b838d82d580be843395ceb9c36b Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:52 +0100 Subject: udf: remove unneeded line break Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 582d6b2f0d5f..ea8f544df5b8 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -2271,8 +2271,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block, uint32_t *elen, sector_t *offset) { unsigned char blocksize_bits = inode->i_sb->s_blocksize_bits; - loff_t lbcount = 0, bcount = - (loff_t) block << blocksize_bits; + loff_t lbcount = 0, bcount = (loff_t) block << blocksize_bits; int8_t etype; struct udf_inode_info *iinfo; -- cgit v1.2.3 From d50c4dd5279b6a2b3ae2c66435ec5c9825b7cff3 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:53 +0100 Subject: udf: remove empty condition loc & 0x02 is empty since first git version in 2005 in udf_add_extendedattr() Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/misc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/udf/misc.c b/fs/udf/misc.c index 71d1c25f360d..3949c4bec3a3 100644 --- a/fs/udf/misc.c +++ b/fs/udf/misc.c @@ -141,8 +141,6 @@ struct genericFormat *udf_add_extendedattr(struct inode *inode, uint32_t size, iinfo->i_lenEAttr += size; return (struct genericFormat *)&ea[offset]; } - if (loc & 0x02) - ; return NULL; } -- cgit v1.2.3 From 7ed0fbd7e3187cc24a47565afcf7fc1f46684755 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:54 +0100 Subject: udf: Factor out trimming of crtime Factor out trimming of crtime field. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index ea8f544df5b8..8cc5dbccebc7 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1612,6 +1612,14 @@ static int udf_sync_inode(struct inode *inode) return udf_update_inode(inode, 1); } +static void udf_adjust_time(struct udf_inode_info *iinfo, struct timespec time) +{ + if (iinfo->i_crtime.tv_sec > time.tv_sec || + (iinfo->i_crtime.tv_sec == time.tv_sec && + iinfo->i_crtime.tv_nsec > time.tv_nsec)) + iinfo->i_crtime = time; +} + static int udf_update_inode(struct inode *inode, int do_sync) { struct buffer_head *bh = NULL; @@ -1738,20 +1746,9 @@ static int udf_update_inode(struct inode *inode, int do_sync) efe->objectSize = cpu_to_le64(inode->i_size); efe->logicalBlocksRecorded = cpu_to_le64(lb_recorded); - if (iinfo->i_crtime.tv_sec > inode->i_atime.tv_sec || - (iinfo->i_crtime.tv_sec == inode->i_atime.tv_sec && - iinfo->i_crtime.tv_nsec > inode->i_atime.tv_nsec)) - iinfo->i_crtime = inode->i_atime; - - if (iinfo->i_crtime.tv_sec > inode->i_mtime.tv_sec || - (iinfo->i_crtime.tv_sec == inode->i_mtime.tv_sec && - iinfo->i_crtime.tv_nsec > inode->i_mtime.tv_nsec)) - iinfo->i_crtime = inode->i_mtime; - - if (iinfo->i_crtime.tv_sec > inode->i_ctime.tv_sec || - (iinfo->i_crtime.tv_sec == inode->i_ctime.tv_sec && - iinfo->i_crtime.tv_nsec > inode->i_ctime.tv_nsec)) - iinfo->i_crtime = inode->i_ctime; + udf_adjust_time(iinfo, inode->i_atime); + udf_adjust_time(iinfo, inode->i_mtime); + udf_adjust_time(iinfo, inode->i_ctime); udf_time_to_disk_stamp(&efe->accessTime, inode->i_atime); udf_time_to_disk_stamp(&efe->modificationTime, inode->i_mtime); -- cgit v1.2.3 From b31c9ed99ed17f9572ee8babf2e89f1f002a7cce Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:56 +0100 Subject: udf: remove next_epos from udf_update_extent_cache() udf_update_extent_cache() is only called from inode_bmap() with 1 for next_epos Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 8cc5dbccebc7..b6c652d34413 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -109,7 +109,7 @@ static int udf_read_extent_cache(struct inode *inode, loff_t bcount, /* Add extent to extent cache */ static void udf_update_extent_cache(struct inode *inode, loff_t estart, - struct extent_position *pos, int next_epos) + struct extent_position *pos) { struct udf_inode_info *iinfo = UDF_I(inode); @@ -118,19 +118,16 @@ static void udf_update_extent_cache(struct inode *inode, loff_t estart, __udf_clear_extent_cache(inode); if (pos->bh) get_bh(pos->bh); - memcpy(&iinfo->cached_extent.epos, pos, - sizeof(struct extent_position)); + memcpy(&iinfo->cached_extent.epos, pos, sizeof(struct extent_position)); iinfo->cached_extent.lstart = estart; - if (next_epos) - switch (iinfo->i_alloc_type) { - case ICBTAG_FLAG_AD_SHORT: - iinfo->cached_extent.epos.offset -= - sizeof(struct short_ad); - break; - case ICBTAG_FLAG_AD_LONG: - iinfo->cached_extent.epos.offset -= - sizeof(struct long_ad); - } + switch (iinfo->i_alloc_type) { + case ICBTAG_FLAG_AD_SHORT: + iinfo->cached_extent.epos.offset -= sizeof(struct short_ad); + break; + case ICBTAG_FLAG_AD_LONG: + iinfo->cached_extent.epos.offset -= sizeof(struct long_ad); + break; + } spin_unlock(&iinfo->i_extent_cache_lock); } @@ -2289,7 +2286,7 @@ int8_t inode_bmap(struct inode *inode, sector_t block, lbcount += *elen; } while (lbcount <= bcount); /* update extent cache */ - udf_update_extent_cache(inode, lbcount - *elen, pos, 1); + udf_update_extent_cache(inode, lbcount - *elen, pos); *offset = (bcount + *elen - lbcount) >> blocksize_bits; return etype; -- cgit v1.2.3 From 54bb60d53114b83473ba1c622be4cca9533b9827 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:53:57 +0100 Subject: udf: merge module informations in super.c Move all module attributes at the end of one file like other FS. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 4 ---- fs/udf/super.c | 9 ++++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index b6c652d34413..2296c8708052 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -43,10 +43,6 @@ #include "udf_i.h" #include "udf_sb.h" -MODULE_AUTHOR("Ben Fennema"); -MODULE_DESCRIPTION("Universal Disk Format Filesystem"); -MODULE_LICENSE("GPL"); - #define EXTENT_MERGE_SIZE 5 static umode_t udf_convert_permissions(struct fileEntry *); diff --git a/fs/udf/super.c b/fs/udf/super.c index 967ad8775af2..9256117ffa27 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -264,9 +264,6 @@ static void __exit exit_udf_fs(void) destroy_inodecache(); } -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); @@ -2500,3 +2497,9 @@ static unsigned int udf_count_free(struct super_block *sb) return accum; } + +MODULE_AUTHOR("Ben Fennema"); +MODULE_DESCRIPTION("Universal Disk Format Filesystem"); +MODULE_LICENSE("GPL"); +module_init(init_udf_fs) +module_exit(exit_udf_fs) -- cgit v1.2.3 From 23bcda112f77da278898841615c7530c3e91a537 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:54:41 +0100 Subject: udf: atomically read inode size See i_size_read() comments in include/linux/fs.h Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/lowlevel.c | 2 +- fs/udf/super.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c index 6ad5a453af97..5c7ec121990d 100644 --- a/fs/udf/lowlevel.c +++ b/fs/udf/lowlevel.c @@ -58,7 +58,7 @@ unsigned long udf_get_last_block(struct super_block *sb) */ if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock) || lblock == 0) - lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; + lblock = i_size_read(bdev->bd_inode) >> sb->s_blocksize_bits; if (lblock) return lblock - 1; diff --git a/fs/udf/super.c b/fs/udf/super.c index 9256117ffa27..6b5a1a45a6c1 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1213,7 +1213,8 @@ static int udf_load_vat(struct super_block *sb, int p_index, int type1_index) struct udf_inode_info *vati; uint32_t pos; struct virtualAllocationTable20 *vat20; - sector_t blocks = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; + sector_t blocks = i_size_read(sb->s_bdev->bd_inode) >> + sb->s_blocksize_bits; udf_find_vat_block(sb, p_index, type1_index, sbi->s_last_block); if (!sbi->s_vat_inode && @@ -1803,7 +1804,7 @@ static int udf_check_anchor_block(struct super_block *sb, sector_t block, if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV) && udf_fixed_to_variable(block) >= - sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits) + i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits) return -EAGAIN; bh = udf_read_tagged(sb, block, block, &ident); @@ -1865,7 +1866,7 @@ static int udf_scan_anchors(struct super_block *sb, sector_t *lastblock, last[last_count++] = *lastblock - 152; for (i = 0; i < last_count; i++) { - if (last[i] >= sb->s_bdev->bd_inode->i_size >> + if (last[i] >= i_size_read(sb->s_bdev->bd_inode) >> sb->s_blocksize_bits) continue; ret = udf_check_anchor_block(sb, last[i], fileset); -- cgit v1.2.3 From 1d82a56bc5bf820b7c65d8130b44c0bc101b546c Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 6 Jan 2017 21:54:43 +0100 Subject: udf: check partition reference in udf_read_inode() We were checking block number without checking partition. sbi->s_partmaps[iloc->partitionReferenceNum] could lead to bad memory access. See udf_nfs_get_inode() path for instance. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 2296c8708052..8ec6b3df0bc7 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1277,6 +1277,12 @@ static int udf_read_inode(struct inode *inode, bool hidden_inode) int ret = -EIO; reread: + if (iloc->partitionReferenceNum >= sbi->s_partitions) { + udf_debug("partition reference: %d > logical volume partitions: %d\n", + iloc->partitionReferenceNum, sbi->s_partitions); + return -EIO; + } + if (iloc->logicalBlockNum >= sbi->s_partmaps[iloc->partitionReferenceNum].s_partition_len) { udf_debug("block=%d, partition=%d out of range\n", -- cgit v1.2.3 From 70f16cef06b5bf72d50b8016e1188995eddc073a Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 18 Jan 2017 19:39:35 +0100 Subject: udf: allow implicit blocksize specification during mount udf_fill_super() used udf_parse_options() to flag UDF_FLAG_BLOCKSIZE_SET when blocksize was specified otherwise used 512 bytes (bdev_logical_block_size) and 2048 bytes (UDF_DEFAULT_BLOCKSIZE) IOW both 1024 and 4096 specifications were required or resulted in "mount: wrong fs type, bad option, bad superblock on /dev/loop1" This patch loops through different block values but also updates udf_load_vrs() to return -EINVAL instead of 0 when udf_check_vsd() fails (and uopt->novrs = 0). The later being the reason for the RFC; we have that case when mounting a 4kb blocksize against other values but maybe VRS is not mandatory there ? Tested with 512, 1024, 2048 and 4096 blocksize Reported-by: Jan Kara Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/super.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/fs/udf/super.c b/fs/udf/super.c index 6b5a1a45a6c1..14b4bc1f6801 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1955,7 +1955,7 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt, if (!nsr_off) { if (!silent) udf_warn(sb, "No VRS found\n"); - return 0; + return -EINVAL; } if (nsr_off == -1) udf_debug("Failed to read sector at offset %d. " @@ -2159,15 +2159,25 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ret = udf_load_vrs(sb, &uopt, silent, &fileset); } else { uopt.blocksize = bdev_logical_block_size(sb->s_bdev); - ret = udf_load_vrs(sb, &uopt, silent, &fileset); - if (ret == -EAGAIN && uopt.blocksize != UDF_DEFAULT_BLOCKSIZE) { - if (!silent) - pr_notice("Rescanning with blocksize %d\n", - UDF_DEFAULT_BLOCKSIZE); - brelse(sbi->s_lvid_bh); - sbi->s_lvid_bh = NULL; - uopt.blocksize = UDF_DEFAULT_BLOCKSIZE; + while (uopt.blocksize <= 4096) { ret = udf_load_vrs(sb, &uopt, silent, &fileset); + if (ret < 0) { + if (!silent && ret != -EACCES) { + pr_notice("Scanning with blocksize %d failed\n", + uopt.blocksize); + } + brelse(sbi->s_lvid_bh); + sbi->s_lvid_bh = NULL; + /* + * EACCES is special - we want to propagate to + * upper layers that we cannot handle RW mount. + */ + if (ret == -EACCES) + break; + } else + break; + + uopt.blocksize <<= 1; } } if (ret < 0) { -- cgit v1.2.3 From 782deb2eecc018bfa278f7453f367e01f5479ccb Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 24 Jan 2017 21:48:34 +0100 Subject: udf: fix ioctl errors Currently, lsattr for instance in udf directory gives "udf: Invalid argument While reading flags on ..." This patch returns -ENOIOCTLCMD when command is unknown to have more accurate message like this: "Inappropriate ioctl for device While reading flags on ..." Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/file.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/udf/file.c b/fs/udf/file.c index dbcb3a4a0cb9..87551b77933a 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -184,7 +184,8 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto out; } - if (!arg) { + if (!arg && ((cmd == UDF_GETVOLIDENT) || (cmd == UDF_GETEASIZE) || + (cmd == UDF_RELOCATE_BLOCKS) || (cmd == UDF_GETEABLOCK))) { udf_debug("invalid argument to udf_ioctl\n"); result = -EINVAL; goto out; @@ -220,6 +221,8 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) UDF_I(inode)->i_ext.i_data, UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0; goto out; + default: + return -ENOIOCTLCMD; } out: -- cgit v1.2.3 From a074faad512605a5bb5f7862e796485e6df572d2 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Tue, 24 Jan 2017 21:48:35 +0100 Subject: udf: simplify udf_ioctl() "out" label was only returning error code. Signed-off-by: Fabian Frederick Signed-off-by: Jan Kara --- fs/udf/file.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/fs/udf/file.c b/fs/udf/file.c index 87551b77933a..e04cc0cdca9d 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -176,57 +176,46 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct inode *inode = file_inode(filp); long old_block, new_block; - int result = -EINVAL; + int result; if (inode_permission(inode, MAY_READ) != 0) { udf_debug("no permission to access inode %lu\n", inode->i_ino); - result = -EPERM; - goto out; + return -EPERM; } if (!arg && ((cmd == UDF_GETVOLIDENT) || (cmd == UDF_GETEASIZE) || (cmd == UDF_RELOCATE_BLOCKS) || (cmd == UDF_GETEABLOCK))) { udf_debug("invalid argument to udf_ioctl\n"); - result = -EINVAL; - goto out; + return -EINVAL; } switch (cmd) { case UDF_GETVOLIDENT: if (copy_to_user((char __user *)arg, UDF_SB(inode->i_sb)->s_volume_ident, 32)) - result = -EFAULT; - else - result = 0; - goto out; + return -EFAULT; + return 0; case UDF_RELOCATE_BLOCKS: - if (!capable(CAP_SYS_ADMIN)) { - result = -EPERM; - goto out; - } - if (get_user(old_block, (long __user *)arg)) { - result = -EFAULT; - goto out; - } + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (get_user(old_block, (long __user *)arg)) + return -EFAULT; result = udf_relocate_blocks(inode->i_sb, old_block, &new_block); if (result == 0) result = put_user(new_block, (long __user *)arg); - goto out; + return result; case UDF_GETEASIZE: - result = put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg); - goto out; + return put_user(UDF_I(inode)->i_lenEAttr, (int __user *)arg); case UDF_GETEABLOCK: - result = copy_to_user((char __user *)arg, - UDF_I(inode)->i_ext.i_data, - UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0; - goto out; + return copy_to_user((char __user *)arg, + UDF_I(inode)->i_ext.i_data, + UDF_I(inode)->i_lenEAttr) ? -EFAULT : 0; default: return -ENOIOCTLCMD; } -out: - return result; + return 0; } static int udf_release_file(struct inode *inode, struct file *filp) -- cgit v1.2.3