aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
authorPeter A. Felvegi <petschy@gmail.com>2013-10-18 14:07:44 -0400
committerJan Kara <jack@suse.cz>2013-10-18 16:39:07 -0400
commit444996027e80f96c9948d8d5b8f067a8aff9861d (patch)
tree878a4fe01b1070c972334f543c7fbf2bde2a7e93 /fs/udf
parent2046fd1873886e8c774d7c1b0961624c164e7db2 (diff)
udf: fix for pathetic mount times in case of invalid file system
The UDF driver was not strict enough about checking the IDs in the VSDs when mounting, which resulted in reading through all the sectors of the block device in some unfortunate cases. Eg, trying to mount my uninitialized 200G SSD partition (all 0xFF bytes) took ~350 minutes to fail, because the code expected some of the valid IDs or a zero byte. During this, the mount couldn't be killed, sync from the cmdline blocked, and the machine froze into the shutdown. Valid filesystems (extX, btrfs, ntfs) were rejected by the mere accident of having a zero byte at just the right place in some of their sectors, close enough to the beginning not to generate excess I/O. The fix adds a hard limit on the VSD sector offset, adds the two missing VSD IDs, and stops scanning when encountering an invalid ID. Also replaced the magic number 32768 with a more meaningful #define, and supressed the bogus message about failing to read the first sector if no UDF fs was detected. Signed-off-by: Peter A. Felvegi <petschy@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/super.c45
1 files changed, 36 insertions, 9 deletions
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 91219385691d..3306b9f69bed 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -76,6 +76,9 @@
76 76
77#define UDF_DEFAULT_BLOCKSIZE 2048 77#define UDF_DEFAULT_BLOCKSIZE 2048
78 78
79#define VSD_FIRST_SECTOR_OFFSET 32768
80#define VSD_MAX_SECTOR_OFFSET 0x800000
81
79enum { UDF_MAX_LINKS = 0xffff }; 82enum { UDF_MAX_LINKS = 0xffff };
80 83
81/* These are the "meat" - everything else is stuffing */ 84/* These are the "meat" - everything else is stuffing */
@@ -685,7 +688,7 @@ out_unlock:
685static loff_t udf_check_vsd(struct super_block *sb) 688static loff_t udf_check_vsd(struct super_block *sb)
686{ 689{
687 struct volStructDesc *vsd = NULL; 690 struct volStructDesc *vsd = NULL;
688 loff_t sector = 32768; 691 loff_t sector = VSD_FIRST_SECTOR_OFFSET;
689 int sectorsize; 692 int sectorsize;
690 struct buffer_head *bh = NULL; 693 struct buffer_head *bh = NULL;
691 int nsr02 = 0; 694 int nsr02 = 0;
@@ -703,8 +706,18 @@ static loff_t udf_check_vsd(struct super_block *sb)
703 udf_debug("Starting at sector %u (%ld byte sectors)\n", 706 udf_debug("Starting at sector %u (%ld byte sectors)\n",
704 (unsigned int)(sector >> sb->s_blocksize_bits), 707 (unsigned int)(sector >> sb->s_blocksize_bits),
705 sb->s_blocksize); 708 sb->s_blocksize);
706 /* Process the sequence (if applicable) */ 709 /* Process the sequence (if applicable). The hard limit on the sector
707 for (; !nsr02 && !nsr03; sector += sectorsize) { 710 * offset is arbitrary, hopefully large enough so that all valid UDF
711 * filesystems will be recognised. There is no mention of an upper
712 * bound to the size of the volume recognition area in the standard.
713 * The limit will prevent the code to read all the sectors of a
714 * specially crafted image (like a bluray disc full of CD001 sectors),
715 * potentially causing minutes or even hours of uninterruptible I/O
716 * activity. This actually happened with uninitialised SSD partitions
717 * (all 0xFF) before the check for the limit and all valid IDs were
718 * added */
719 for (; !nsr02 && !nsr03 && sector < VSD_MAX_SECTOR_OFFSET;
720 sector += sectorsize) {
708 /* Read a block */ 721 /* Read a block */
709 bh = udf_tread(sb, sector >> sb->s_blocksize_bits); 722 bh = udf_tread(sb, sector >> sb->s_blocksize_bits);
710 if (!bh) 723 if (!bh)
@@ -714,10 +727,7 @@ static loff_t udf_check_vsd(struct super_block *sb)
714 vsd = (struct volStructDesc *)(bh->b_data + 727 vsd = (struct volStructDesc *)(bh->b_data +
715 (sector & (sb->s_blocksize - 1))); 728 (sector & (sb->s_blocksize - 1)));
716 729
717 if (vsd->stdIdent[0] == 0) { 730 if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
718 brelse(bh);
719 break;
720 } else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001,
721 VSD_STD_ID_LEN)) { 731 VSD_STD_ID_LEN)) {
722 switch (vsd->structType) { 732 switch (vsd->structType) {
723 case 0: 733 case 0:
@@ -753,6 +763,17 @@ static loff_t udf_check_vsd(struct super_block *sb)
753 else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, 763 else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03,
754 VSD_STD_ID_LEN)) 764 VSD_STD_ID_LEN))
755 nsr03 = sector; 765 nsr03 = sector;
766 else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BOOT2,
767 VSD_STD_ID_LEN))
768 ; /* nothing */
769 else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CDW02,
770 VSD_STD_ID_LEN))
771 ; /* nothing */
772 else {
773 /* invalid id : end of volume recognition area */
774 brelse(bh);
775 break;
776 }
756 brelse(bh); 777 brelse(bh);
757 } 778 }
758 779
@@ -760,7 +781,8 @@ static loff_t udf_check_vsd(struct super_block *sb)
760 return nsr03; 781 return nsr03;
761 else if (nsr02) 782 else if (nsr02)
762 return nsr02; 783 return nsr02;
763 else if (sector - (sbi->s_session << sb->s_blocksize_bits) == 32768) 784 else if (!bh && sector - (sbi->s_session << sb->s_blocksize_bits) ==
785 VSD_FIRST_SECTOR_OFFSET)
764 return -1; 786 return -1;
765 else 787 else
766 return 0; 788 return 0;
@@ -1270,6 +1292,9 @@ static int udf_load_partdesc(struct super_block *sb, sector_t block)
1270 * PHYSICAL partitions are already set up 1292 * PHYSICAL partitions are already set up
1271 */ 1293 */
1272 type1_idx = i; 1294 type1_idx = i;
1295#ifdef UDFFS_DEBUG
1296 map = NULL; /* supress 'maybe used uninitialized' warning */
1297#endif
1273 for (i = 0; i < sbi->s_partitions; i++) { 1298 for (i = 0; i < sbi->s_partitions; i++) {
1274 map = &sbi->s_partmaps[i]; 1299 map = &sbi->s_partmaps[i];
1275 1300
@@ -1891,7 +1916,9 @@ static int udf_load_vrs(struct super_block *sb, struct udf_options *uopt,
1891 return 0; 1916 return 0;
1892 } 1917 }
1893 if (nsr_off == -1) 1918 if (nsr_off == -1)
1894 udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n"); 1919 udf_debug("Failed to read sector at offset %d. "
1920 "Assuming open disc. Skipping validity "
1921 "check\n", VSD_FIRST_SECTOR_OFFSET);
1895 if (!sbi->s_last_block) 1922 if (!sbi->s_last_block)
1896 sbi->s_last_block = udf_get_last_block(sb); 1923 sbi->s_last_block = udf_get_last_block(sb);
1897 } else { 1924 } else {