All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] fs: FAT: Add support for DOS 1.x formatted volumes
@ 2014-03-31 15:22 Conrad Meyer
  2014-04-01  1:17 ` [PATCH v4] " Conrad Meyer
  0 siblings, 1 reply; 4+ messages in thread
From: Conrad Meyer @ 2014-03-31 15:22 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, Conrad Meyer

Add dos1xfloppy mount option to infer DOS 2.x BIOS Parameter Block
defaults from block device geometry for ancient floppies and floppy
images.

Validate that the entire BPB is zero like we expect, and that the floppy
has a DOS-style 8086 code bootstrapping header.

Fixes kernel.org bug #42617.

Values are inferred from media size and a table.[0] Media size is
assumed to be static for archaic FAT volumes. See also [1].

[0]: https://en.wikipedia.org/wiki/File_Allocation_Table#Exceptions
[1]: http://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html

Signed-off-by: Conrad Meyer <cse.cem@gmail.com>
---
Based on next-20140328.

Changes since v2:
  * Only attempt to infer BPB values if mounted with -o dos1xfloppy
  * Set sbi->* values directly instead of writing out BPB

Works fine in local tests. Can mount 1985 floppy image and explore files (with
dos1xfloppy option). Without option, mount fails (expected).

Thanks.
---
 fs/fat/fat.h   |   3 +-
 fs/fat/inode.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 137 insertions(+), 20 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 7270bdb..13b7202 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -52,7 +52,8 @@ struct fat_mount_options {
 		 usefree:1,	   /* Use free_clusters for FAT32 */
 		 tz_set:1,	   /* Filesystem timestamps' offset set */
 		 rodir:1,	   /* allow ATTR_RO for directory */
-		 discard:1;	   /* Issue discard requests on deletions */
+		 discard:1,	   /* Issue discard requests on deletions */
+		 dos1xfloppy:1;	   /* Assume default BPB for DOS 1.x floppies */
 };
 
 #define FAT_HASH_BITS	8
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 992e8cb..d032e3c 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -35,9 +35,47 @@
 #define CONFIG_FAT_DEFAULT_IOCHARSET	""
 #endif
 
+#define KB_IN_SECTORS 2
+
 static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
 static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
 
+static struct fat_floppy_defaults {
+	unsigned nr_sectors;
+	unsigned sec_per_clus;
+	unsigned dir_entries;
+	unsigned media;
+	unsigned fat_length;
+} floppy_defaults[] = {
+{
+	.nr_sectors = 160 * KB_IN_SECTORS,
+	.sec_per_clus = 1,
+	.dir_entries = 64,
+	.media = 0xFE,
+	.fat_length = 1,
+},
+{
+	.nr_sectors = 180 * KB_IN_SECTORS,
+	.sec_per_clus = 1,
+	.dir_entries = 64,
+	.media = 0xFC,
+	.fat_length = 2,
+},
+{
+	.nr_sectors = 320 * KB_IN_SECTORS,
+	.sec_per_clus = 2,
+	.dir_entries = 112,
+	.media = 0xFF,
+	.fat_length = 1,
+},
+{
+	.nr_sectors = 360 * KB_IN_SECTORS,
+	.sec_per_clus = 2,
+	.dir_entries = 112,
+	.media = 0xFD,
+	.fat_length = 2,
+},
+{ 0 } };
 
 static int fat_add_cluster(struct inode *inode)
 {
@@ -945,7 +983,7 @@ enum {
 	Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
 	Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
 	Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
-	Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err,
+	Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy,
 };
 
 static const match_table_t fat_tokens = {
@@ -978,6 +1016,7 @@ static const match_table_t fat_tokens = {
 	{Opt_nfs_stale_rw, "nfs"},
 	{Opt_nfs_stale_rw, "nfs=stale_rw"},
 	{Opt_nfs_nostale_ro, "nfs=nostale_ro"},
+	{Opt_dos1xfloppy, "dos1xfloppy"},
 	{Opt_obsolete, "conv=binary"},
 	{Opt_obsolete, "conv=text"},
 	{Opt_obsolete, "conv=auto"},
@@ -1180,6 +1219,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
 		case Opt_nfs_nostale_ro:
 			opts->nfs = FAT_NFS_NOSTALE_RO;
 			break;
+		case Opt_dos1xfloppy:
+			opts->dos1xfloppy = 1;
+			break;
 
 		/* msdos specific */
 		case Opt_dots:
@@ -1332,13 +1374,16 @@ static unsigned long calc_fat_clusters(struct super_block *sb)
 int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		   void (*setup)(struct super_block *))
 {
+	static const char *notdos1x = "This doesn't look like a DOS 1.x volume";
 	struct inode *root_inode = NULL, *fat_inode = NULL;
+	struct fat_floppy_defaults *fdefaults = NULL;
 	struct inode *fsinfo_inode = NULL;
 	struct buffer_head *bh;
 	struct fat_boot_sector *b;
 	struct msdos_sb_info *sbi;
 	u16 logical_sector_size;
 	u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
+	sector_t bd_sects;
 	int debug;
 	unsigned int media;
 	long error;
@@ -1378,17 +1423,66 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	}
 
 	b = (struct fat_boot_sector *) bh->b_data;
-	if (!b->reserved) {
-		if (!silent)
-			fat_msg(sb, KERN_ERR, "bogus number of reserved sectors");
-		brelse(bh);
-		goto out_invalid;
-	}
-	if (!b->fats) {
-		if (!silent)
-			fat_msg(sb, KERN_ERR, "bogus number of FAT structure");
-		brelse(bh);
-		goto out_invalid;
+
+	bd_sects = part_nr_sects_read(sb->s_bdev->bd_part);
+	if (sbi->options.dos1xfloppy) {
+		/* 16-bit DOS 1.x reliably wrote bootstrap short-jmp code */
+		if (b->ignored[0] != 0xeb || b->ignored[2] != 0x90) {
+			fat_msg(sb, KERN_ERR, "%s; no bootstrapping code",
+				notdos1x);
+			brelse(bh);
+			goto out_invalid;
+		}
+
+		/*
+		 * If any value in this region is non-zero, it isn't archaic
+		 * DOS.
+		 */
+		if (get_unaligned_le16(&b->sector_size) != 0 ||
+			b->sec_per_clus != 0 || b->reserved != 0 ||
+			b->fats != 0 ||
+			get_unaligned_le16(&b->dir_entries) != 0 ||
+			get_unaligned_le16(&b->sectors) != 0 || b->media != 0 ||
+			b->fat_length != 0 || b->secs_track != 0 ||
+			b->heads != 0 || b->secs_track != 0 || b->heads != 0) {
+
+			fat_msg(sb, KERN_ERR, "%s; DOS 2.x BPB is non-zero",
+				notdos1x);
+			brelse(bh);
+			goto out_invalid;
+		}
+
+		for (fdefaults = floppy_defaults; fdefaults->nr_sectors;
+			fdefaults++) {
+			if (fdefaults->nr_sectors == bd_sects)
+				break;
+		}
+
+		if (fdefaults->nr_sectors == 0) {
+			fat_msg(sb, KERN_WARNING,
+				"This looks like a DOS 1.x volume, but isn't a recognized floppy size (%ld sectors)",
+				(long)bd_sects);
+			brelse(bh);
+			goto out_invalid;
+		}
+
+		fat_msg(sb, KERN_INFO,
+			"This looks like a DOS 1.x volume; assuming default BPB values");
+	} else {
+		if (!b->reserved) {
+			if (!silent)
+				fat_msg(sb, KERN_ERR,
+					"bogus number of reserved sectors");
+			brelse(bh);
+			goto out_invalid;
+		}
+		if (!b->fats) {
+			if (!silent)
+				fat_msg(sb, KERN_ERR,
+					"bogus number of FAT structure");
+			brelse(bh);
+			goto out_invalid;
+		}
 	}
 
 	/*
@@ -1397,6 +1491,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	 */
 
 	media = b->media;
+	if (sbi->options.dos1xfloppy)
+		media = fdefaults->media;
 	if (!fat_valid_media(media)) {
 		if (!silent)
 			fat_msg(sb, KERN_ERR, "invalid media value (0x%02x)",
@@ -1404,7 +1500,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		brelse(bh);
 		goto out_invalid;
 	}
-	logical_sector_size = get_unaligned_le16(&b->sector_size);
+	if (sbi->options.dos1xfloppy)
+		logical_sector_size = SECTOR_SIZE;
+	else
+		logical_sector_size = get_unaligned_le16(&b->sector_size);
 	if (!is_power_of_2(logical_sector_size)
 	    || (logical_sector_size < 512)
 	    || (logical_sector_size > 4096)) {
@@ -1414,7 +1513,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		brelse(bh);
 		goto out_invalid;
 	}
-	sbi->sec_per_clus = b->sec_per_clus;
+	if (sbi->options.dos1xfloppy)
+		sbi->sec_per_clus = fdefaults->sec_per_clus;
+	else
+		sbi->sec_per_clus = b->sec_per_clus;
 	if (!is_power_of_2(sbi->sec_per_clus)) {
 		if (!silent)
 			fat_msg(sb, KERN_ERR, "bogus sectors per cluster %u",
@@ -1450,10 +1552,18 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	mutex_init(&sbi->s_lock);
 	sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus;
 	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
-	sbi->fats = b->fats;
+	if (sbi->options.dos1xfloppy)
+		sbi->fats = 2;
+	else
+		sbi->fats = b->fats;
 	sbi->fat_bits = 0;		/* Don't know yet */
-	sbi->fat_start = le16_to_cpu(b->reserved);
-	sbi->fat_length = le16_to_cpu(b->fat_length);
+	if (sbi->options.dos1xfloppy) {
+		sbi->fat_start = 1;
+		sbi->fat_length = fdefaults->fat_length;
+	} else {
+		sbi->fat_start = le16_to_cpu(b->reserved);
+		sbi->fat_length = le16_to_cpu(b->fat_length);
+	}
 	sbi->root_cluster = 0;
 	sbi->free_clusters = -1;	/* Don't know yet */
 	sbi->free_clus_valid = 0;
@@ -1515,7 +1625,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
 
 	sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
-	sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
+	if (sbi->options.dos1xfloppy)
+		sbi->dir_entries = fdefaults->dir_entries;
+	else
+		sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
 	if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
 		if (!silent)
 			fat_msg(sb, KERN_ERR, "bogus directory-entries per block"
@@ -1527,7 +1640,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	rootdir_sectors = sbi->dir_entries
 		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
 	sbi->data_start = sbi->dir_start + rootdir_sectors;
-	total_sectors = get_unaligned_le16(&b->sectors);
+	if (sbi->options.dos1xfloppy)
+		total_sectors = fdefaults->nr_sectors;
+	else
+		total_sectors = get_unaligned_le16(&b->sectors);
 	if (total_sectors == 0)
 		total_sectors = le32_to_cpu(b->total_sect);
 
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v4] fs: FAT: Add support for DOS 1.x formatted volumes
  2014-03-31 15:22 [PATCH v3] fs: FAT: Add support for DOS 1.x formatted volumes Conrad Meyer
@ 2014-04-01  1:17 ` Conrad Meyer
  2014-04-13  3:57   ` OGAWA Hirofumi
  0 siblings, 1 reply; 4+ messages in thread
From: Conrad Meyer @ 2014-04-01  1:17 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel, Conrad Meyer

Add dos1xfloppy mount option to infer DOS 2.x BIOS Parameter Block
defaults from block device geometry for ancient floppies and floppy
images.

Validate that the entire BPB is zero like we expect, and that the floppy
has a DOS-style 8086 code bootstrapping header.

Fixes kernel.org bug #42617.

Values are inferred from media size and a table.[0] Media size is
assumed to be static for archaic FAT volumes. See also [1].

[0]: https://en.wikipedia.org/wiki/File_Allocation_Table#Exceptions
[1]: http://www.win.tue.nl/~aeb/linux/fs/fat/fat-1.html

Signed-off-by: Conrad Meyer <cse.cem@gmail.com>
---
Changes since v3!

* No EOF on floppy_defaults array (use ARRAY_SIZE instead)
* Use correct format string/types for sector_t in fat_msg()
* Pull out massive if () zero boolean expression into a hopefully expressively
  named helper function, fat_is_bpb_zero()

Thanks for the feedback.
---
 fs/fat/fat.h   |   3 +-
 fs/fat/inode.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 157 insertions(+), 21 deletions(-)

diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 7270bdb..13b7202 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -52,7 +52,8 @@ struct fat_mount_options {
 		 usefree:1,	   /* Use free_clusters for FAT32 */
 		 tz_set:1,	   /* Filesystem timestamps' offset set */
 		 rodir:1,	   /* allow ATTR_RO for directory */
-		 discard:1;	   /* Issue discard requests on deletions */
+		 discard:1,	   /* Issue discard requests on deletions */
+		 dos1xfloppy:1;	   /* Assume default BPB for DOS 1.x floppies */
 };
 
 #define FAT_HASH_BITS	8
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 992e8cb..0f08ca4 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -35,9 +35,47 @@
 #define CONFIG_FAT_DEFAULT_IOCHARSET	""
 #endif
 
+#define KB_IN_SECTORS 2
+
 static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE;
 static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET;
 
+static struct fat_floppy_defaults {
+	unsigned nr_sectors;
+	unsigned sec_per_clus;
+	unsigned dir_entries;
+	unsigned media;
+	unsigned fat_length;
+} floppy_defaults[] = {
+{
+	.nr_sectors = 160 * KB_IN_SECTORS,
+	.sec_per_clus = 1,
+	.dir_entries = 64,
+	.media = 0xFE,
+	.fat_length = 1,
+},
+{
+	.nr_sectors = 180 * KB_IN_SECTORS,
+	.sec_per_clus = 1,
+	.dir_entries = 64,
+	.media = 0xFC,
+	.fat_length = 2,
+},
+{
+	.nr_sectors = 320 * KB_IN_SECTORS,
+	.sec_per_clus = 2,
+	.dir_entries = 112,
+	.media = 0xFF,
+	.fat_length = 1,
+},
+{
+	.nr_sectors = 360 * KB_IN_SECTORS,
+	.sec_per_clus = 2,
+	.dir_entries = 112,
+	.media = 0xFD,
+	.fat_length = 2,
+},
+};
 
 static int fat_add_cluster(struct inode *inode)
 {
@@ -945,7 +983,7 @@ enum {
 	Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
 	Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
 	Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
-	Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err,
+	Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy,
 };
 
 static const match_table_t fat_tokens = {
@@ -978,6 +1016,7 @@ static const match_table_t fat_tokens = {
 	{Opt_nfs_stale_rw, "nfs"},
 	{Opt_nfs_stale_rw, "nfs=stale_rw"},
 	{Opt_nfs_nostale_ro, "nfs=nostale_ro"},
+	{Opt_dos1xfloppy, "dos1xfloppy"},
 	{Opt_obsolete, "conv=binary"},
 	{Opt_obsolete, "conv=text"},
 	{Opt_obsolete, "conv=auto"},
@@ -1180,6 +1219,9 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
 		case Opt_nfs_nostale_ro:
 			opts->nfs = FAT_NFS_NOSTALE_RO;
 			break;
+		case Opt_dos1xfloppy:
+			opts->dos1xfloppy = 1;
+			break;
 
 		/* msdos specific */
 		case Opt_dots:
@@ -1326,21 +1368,49 @@ static unsigned long calc_fat_clusters(struct super_block *sb)
 	return sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits;
 }
 
+static bool fat_bpb_is_zero(struct fat_boot_sector *b)
+{
+	if (get_unaligned_le16(&b->sector_size))
+		return false;
+	if (b->sec_per_clus)
+		return false;
+	if (b->reserved)
+		return false;
+	if (b->fats)
+		return false;
+	if (get_unaligned_le16(&b->dir_entries))
+		return false;
+	if (get_unaligned_le16(&b->sectors))
+		return false;
+	if (b->media)
+		return false;
+	if (b->fat_length)
+		return false;
+	if (b->secs_track)
+		return false;
+	if (b->heads)
+		return false;
+	return true;
+}
+
 /*
  * Read the super block of an MS-DOS FS.
  */
 int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		   void (*setup)(struct super_block *))
 {
+	static const char *notdos1x = "This doesn't look like a DOS 1.x volume";
 	struct inode *root_inode = NULL, *fat_inode = NULL;
+	struct fat_floppy_defaults *fdefaults = NULL;
 	struct inode *fsinfo_inode = NULL;
 	struct buffer_head *bh;
 	struct fat_boot_sector *b;
 	struct msdos_sb_info *sbi;
 	u16 logical_sector_size;
 	u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors;
+	sector_t bd_sects;
 	int debug;
-	unsigned int media;
+	unsigned int media, i;
 	long error;
 	char buf[50];
 
@@ -1378,17 +1448,60 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	}
 
 	b = (struct fat_boot_sector *) bh->b_data;
-	if (!b->reserved) {
-		if (!silent)
-			fat_msg(sb, KERN_ERR, "bogus number of reserved sectors");
-		brelse(bh);
-		goto out_invalid;
-	}
-	if (!b->fats) {
-		if (!silent)
-			fat_msg(sb, KERN_ERR, "bogus number of FAT structure");
-		brelse(bh);
-		goto out_invalid;
+
+	bd_sects = part_nr_sects_read(sb->s_bdev->bd_part);
+	if (sbi->options.dos1xfloppy) {
+		/* 16-bit DOS 1.x reliably wrote bootstrap short-jmp code */
+		if (b->ignored[0] != 0xeb || b->ignored[2] != 0x90) {
+			fat_msg(sb, KERN_ERR, "%s; no bootstrapping code",
+				notdos1x);
+			brelse(bh);
+			goto out_invalid;
+		}
+
+		/*
+		 * If any value in this region is non-zero, it isn't archaic
+		 * DOS.
+		 */
+		if (!fat_bpb_is_zero(b)) {
+			fat_msg(sb, KERN_ERR, "%s; DOS 2.x BPB is non-zero",
+				notdos1x);
+			brelse(bh);
+			goto out_invalid;
+		}
+
+		for (i = 0; i < ARRAY_SIZE(floppy_defaults); i++) {
+			if (floppy_defaults[i].nr_sectors == bd_sects) {
+				fdefaults = &floppy_defaults[i];
+				break;
+			}
+		}
+
+		if (fdefaults == NULL) {
+			fat_msg(sb, KERN_WARNING,
+				"This looks like a DOS 1.x volume, but isn't a recognized floppy size (%llu sectors)",
+				(u64)bd_sects);
+			brelse(bh);
+			goto out_invalid;
+		}
+
+		fat_msg(sb, KERN_INFO,
+			"This looks like a DOS 1.x volume; assuming default BPB values");
+	} else {
+		if (!b->reserved) {
+			if (!silent)
+				fat_msg(sb, KERN_ERR,
+					"bogus number of reserved sectors");
+			brelse(bh);
+			goto out_invalid;
+		}
+		if (!b->fats) {
+			if (!silent)
+				fat_msg(sb, KERN_ERR,
+					"bogus number of FAT structure");
+			brelse(bh);
+			goto out_invalid;
+		}
 	}
 
 	/*
@@ -1397,6 +1510,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	 */
 
 	media = b->media;
+	if (sbi->options.dos1xfloppy)
+		media = fdefaults->media;
 	if (!fat_valid_media(media)) {
 		if (!silent)
 			fat_msg(sb, KERN_ERR, "invalid media value (0x%02x)",
@@ -1404,7 +1519,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		brelse(bh);
 		goto out_invalid;
 	}
-	logical_sector_size = get_unaligned_le16(&b->sector_size);
+	if (sbi->options.dos1xfloppy)
+		logical_sector_size = SECTOR_SIZE;
+	else
+		logical_sector_size = get_unaligned_le16(&b->sector_size);
 	if (!is_power_of_2(logical_sector_size)
 	    || (logical_sector_size < 512)
 	    || (logical_sector_size > 4096)) {
@@ -1414,7 +1532,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 		brelse(bh);
 		goto out_invalid;
 	}
-	sbi->sec_per_clus = b->sec_per_clus;
+	if (sbi->options.dos1xfloppy)
+		sbi->sec_per_clus = fdefaults->sec_per_clus;
+	else
+		sbi->sec_per_clus = b->sec_per_clus;
 	if (!is_power_of_2(sbi->sec_per_clus)) {
 		if (!silent)
 			fat_msg(sb, KERN_ERR, "bogus sectors per cluster %u",
@@ -1450,10 +1571,18 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	mutex_init(&sbi->s_lock);
 	sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus;
 	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
-	sbi->fats = b->fats;
+	if (sbi->options.dos1xfloppy)
+		sbi->fats = 2;
+	else
+		sbi->fats = b->fats;
 	sbi->fat_bits = 0;		/* Don't know yet */
-	sbi->fat_start = le16_to_cpu(b->reserved);
-	sbi->fat_length = le16_to_cpu(b->fat_length);
+	if (sbi->options.dos1xfloppy) {
+		sbi->fat_start = 1;
+		sbi->fat_length = fdefaults->fat_length;
+	} else {
+		sbi->fat_start = le16_to_cpu(b->reserved);
+		sbi->fat_length = le16_to_cpu(b->fat_length);
+	}
 	sbi->root_cluster = 0;
 	sbi->free_clusters = -1;	/* Don't know yet */
 	sbi->free_clus_valid = 0;
@@ -1515,7 +1644,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
 
 	sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
-	sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
+	if (sbi->options.dos1xfloppy)
+		sbi->dir_entries = fdefaults->dir_entries;
+	else
+		sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
 	if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
 		if (!silent)
 			fat_msg(sb, KERN_ERR, "bogus directory-entries per block"
@@ -1527,7 +1659,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
 	rootdir_sectors = sbi->dir_entries
 		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
 	sbi->data_start = sbi->dir_start + rootdir_sectors;
-	total_sectors = get_unaligned_le16(&b->sectors);
+	if (sbi->options.dos1xfloppy)
+		total_sectors = fdefaults->nr_sectors;
+	else
+		total_sectors = get_unaligned_le16(&b->sectors);
 	if (total_sectors == 0)
 		total_sectors = le32_to_cpu(b->total_sect);
 
-- 
1.9.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] fs: FAT: Add support for DOS 1.x formatted volumes
  2014-04-01  1:17 ` [PATCH v4] " Conrad Meyer
@ 2014-04-13  3:57   ` OGAWA Hirofumi
  2014-04-13 12:35     ` Conrad Meyer
  0 siblings, 1 reply; 4+ messages in thread
From: OGAWA Hirofumi @ 2014-04-13  3:57 UTC (permalink / raw)
  To: Conrad Meyer; +Cc: linux-kernel, Conrad Meyer

Conrad Meyer <cemeyer@uw.edu> writes:

Hi,

Sorry for late reply.

> +
> +	bd_sects = part_nr_sects_read(sb->s_bdev->bd_part);

This would be better to use i_read_size(&sb->s_bdev->bd_inode->i_size)

> +		if (!fat_bpb_is_zero(b)) {
> +			fat_msg(sb, KERN_ERR, "%s; DOS 2.x BPB is non-zero",
> +				notdos1x);
> +			brelse(bh);
> +			goto out_invalid;
> +		}

Please don't message if silent. While auto detection, user don't want to
see message from kernel.

> +	if (sbi->options.dos1xfloppy) {
> +		/* 16-bit DOS 1.x reliably wrote bootstrap short-jmp code */
> +		if (b->ignored[0] != 0xeb || b->ignored[2] != 0x90) {
> +			fat_msg(sb, KERN_ERR, "%s; no bootstrapping code",
> +				notdos1x);
> +			brelse(bh);
> +			goto out_invalid;
> +		}

[...]

Looks like I was not explain my suggestion correctly. I was intended to
allow dos1xfloppy by option, not allow dos1xfloppy only.

I.e.

	err = read-from-bpb();
	if (err == -ENOTFATFS)
		if (dos1xfloppy)
			err = read-from-static-bpb();
	if (err)
		goto error;

> +	if (sbi->options.dos1xfloppy)
> +		total_sectors = fdefaults->nr_sectors;
> +	else
> +		total_sectors = get_unaligned_le16(&b->sectors);
>  	if (total_sectors == 0)
>  		total_sectors = le32_to_cpu(b->total_sect);

Can we make 2 helpers to read from BPB and static BPB? If possible, we
would not be bothered by if (dos1xfloppy), like above crappy pseudo.

Thanks.
-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
> +
> +		for (i = 0; i < ARRAY_SIZE(floppy_defaults); i++) {
> +			if (floppy_defaults[i].nr_sectors == bd_sects) {
> +				fdefaults = &floppy_defaults[i];
> +				break;
> +			}
> +		}
> +
> +		if (fdefaults == NULL) {
> +			fat_msg(sb, KERN_WARNING,
> +				"This looks like a DOS 1.x volume, but isn't a recognized floppy size (%llu sectors)",
> +				(u64)bd_sects);
> +			brelse(bh);
> +			goto out_invalid;
> +		}
> +
> +		fat_msg(sb, KERN_INFO,
> +			"This looks like a DOS 1.x volume; assuming default BPB values");
> +	} else {
> +		if (!b->reserved) {
> +			if (!silent)
> +				fat_msg(sb, KERN_ERR,
> +					"bogus number of reserved sectors");
> +			brelse(bh);
> +			goto out_invalid;
> +		}
> +		if (!b->fats) {
> +			if (!silent)
> +				fat_msg(sb, KERN_ERR,
> +					"bogus number of FAT structure");
> +			brelse(bh);
> +			goto out_invalid;
> +		}
>  	}
>  
>  	/*
> @@ -1397,6 +1510,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
>  	 */
>  
>  	media = b->media;
> +	if (sbi->options.dos1xfloppy)
> +		media = fdefaults->media;
>  	if (!fat_valid_media(media)) {
>  		if (!silent)
>  			fat_msg(sb, KERN_ERR, "invalid media value (0x%02x)",
> @@ -1404,7 +1519,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
>  		brelse(bh);
>  		goto out_invalid;
>  	}
> -	logical_sector_size = get_unaligned_le16(&b->sector_size);
> +	if (sbi->options.dos1xfloppy)
> +		logical_sector_size = SECTOR_SIZE;
> +	else
> +		logical_sector_size = get_unaligned_le16(&b->sector_size);
>  	if (!is_power_of_2(logical_sector_size)
>  	    || (logical_sector_size < 512)
>  	    || (logical_sector_size > 4096)) {
> @@ -1414,7 +1532,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
>  		brelse(bh);
>  		goto out_invalid;
>  	}
> -	sbi->sec_per_clus = b->sec_per_clus;
> +	if (sbi->options.dos1xfloppy)
> +		sbi->sec_per_clus = fdefaults->sec_per_clus;
> +	else
> +		sbi->sec_per_clus = b->sec_per_clus;
>  	if (!is_power_of_2(sbi->sec_per_clus)) {
>  		if (!silent)
>  			fat_msg(sb, KERN_ERR, "bogus sectors per cluster %u",
> @@ -1450,10 +1571,18 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
>  	mutex_init(&sbi->s_lock);
>  	sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus;
>  	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
> -	sbi->fats = b->fats;
> +	if (sbi->options.dos1xfloppy)
> +		sbi->fats = 2;
> +	else
> +		sbi->fats = b->fats;
>  	sbi->fat_bits = 0;		/* Don't know yet */
> -	sbi->fat_start = le16_to_cpu(b->reserved);
> -	sbi->fat_length = le16_to_cpu(b->fat_length);
> +	if (sbi->options.dos1xfloppy) {
> +		sbi->fat_start = 1;
> +		sbi->fat_length = fdefaults->fat_length;
> +	} else {
> +		sbi->fat_start = le16_to_cpu(b->reserved);
> +		sbi->fat_length = le16_to_cpu(b->fat_length);
> +	}
>  	sbi->root_cluster = 0;
>  	sbi->free_clusters = -1;	/* Don't know yet */
>  	sbi->free_clus_valid = 0;
> @@ -1515,7 +1644,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
>  	sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
>  
>  	sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
> -	sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
> +	if (sbi->options.dos1xfloppy)
> +		sbi->dir_entries = fdefaults->dir_entries;
> +	else
> +		sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
>  	if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
>  		if (!silent)
>  			fat_msg(sb, KERN_ERR, "bogus directory-entries per block"
> @@ -1527,7 +1659,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,
>  	rootdir_sectors = sbi->dir_entries
>  		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
>  	sbi->data_start = sbi->dir_start + rootdir_sectors;
> -	total_sectors = get_unaligned_le16(&b->sectors);
> +	if (sbi->options.dos1xfloppy)
> +		total_sectors = fdefaults->nr_sectors;
> +	else
> +		total_sectors = get_unaligned_le16(&b->sectors);
>  	if (total_sectors == 0)
>  		total_sectors = le32_to_cpu(b->total_sect);

-- 
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v4] fs: FAT: Add support for DOS 1.x formatted volumes
  2014-04-13  3:57   ` OGAWA Hirofumi
@ 2014-04-13 12:35     ` Conrad Meyer
  0 siblings, 0 replies; 4+ messages in thread
From: Conrad Meyer @ 2014-04-13 12:35 UTC (permalink / raw)
  To: OGAWA Hirofumi; +Cc: linux-kernel

On Sun, 13 Apr 2014 12:57:42 +0900
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> wrote:

> Conrad Meyer <cemeyer@uw.edu> writes:
> 
> Hi,
> 
> Sorry for late reply.
> 
> > +
> > +	bd_sects =
> > part_nr_sects_read(sb->s_bdev->bd_part);
> 
> This would be better to use
> i_read_size(&sb->s_bdev->bd_inode->i_size)

Ok, easy to fix.

> 
> > +		if (!fat_bpb_is_zero(b)) {
> > +			fat_msg(sb, KERN_ERR, "%s; DOS
> > 2.x BPB is non-zero",
> > +				notdos1x);
> > +			brelse(bh);
> > +			goto out_invalid;
> > +		}
> 
> Please don't message if silent. While auto detection, user
> don't want to see message from kernel.

Okay, fixed.

> 
> > +	if (sbi->options.dos1xfloppy) {
> > +		/* 16-bit DOS 1.x reliably wrote
> > bootstrap short-jmp code */
> > +		if (b->ignored[0] != 0xeb ||
> > b->ignored[2] != 0x90) {
> > +			fat_msg(sb, KERN_ERR, "%s; no
> > bootstrapping code",
> > +				notdos1x);
> > +			brelse(bh);
> > +			goto out_invalid;
> > +		}
> 
> [...]
> 
> Looks like I was not explain my suggestion correctly. I was
> intended to allow dos1xfloppy by option, not allow
> dos1xfloppy only.
> 
> I.e.
> 
> 	err = read-from-bpb();
> 	if (err == -ENOTFATFS)
> 		if (dos1xfloppy)
> 			err = read-from-static-bpb();
> 	if (err)
> 		goto error;
> 
> > +	if (sbi->options.dos1xfloppy)
> > +		total_sectors = fdefaults->nr_sectors;
> > +	else
> > +		total_sectors =
> > get_unaligned_le16(&b->sectors); if (total_sectors == 0)
> >  		total_sectors =
> > le32_to_cpu(b->total_sect);
> 
> Can we make 2 helpers to read from BPB and static BPB? If
> possible, we would not be bothered by if (dos1xfloppy),
> like above crappy pseudo.
> 
> Thanks.


We would have to duplicate, replace, or skip large parts of
fat_fill_super(). This is why my initial approach was to just
fill in BPB values in the SB copy in memory. We read from BPB
over the course of 215 lines of code, ending here:

> @@ -1527,7 +1659,10 @@ int fat_fill_super(struct
> super_block *sb, void *data, int silent, int isvfat,
> rootdir_sectors = sbi->dir_entries
>  		* sizeof(struct msdos_dir_entry) /
> sb->s_blocksize; sbi->data_start = sbi->dir_start +
> rootdir_sectors;
> -	total_sectors = get_unaligned_le16(&b->sectors);
> +	if (sbi->options.dos1xfloppy)
> +		total_sectors = fdefaults->nr_sectors;
> +	else
> +		total_sectors =
> get_unaligned_le16(&b->sectors); if (total_sectors == 0)
>  		total_sectors =
> le32_to_cpu(b->total_sect); 


I will make an attempt at it.

Thanks,
Conrad

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2014-04-13 12:35 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-31 15:22 [PATCH v3] fs: FAT: Add support for DOS 1.x formatted volumes Conrad Meyer
2014-04-01  1:17 ` [PATCH v4] " Conrad Meyer
2014-04-13  3:57   ` OGAWA Hirofumi
2014-04-13 12:35     ` Conrad Meyer

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.