Skip to contentSkip to conversation

fs: FAT: Add support for DOS 1.x formatted volumes

PATCH Superseded Conrad Meyer 3 participants 3 messages Apr 13, 2014 VFAT/FAT/msdos filesystem

v5 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

PATCH v5 1/1 fs: FAT: Add support for DOS 1.x formatted volumes

Add dos1xfloppy mount option to infer DOS 2.x BIOS Parameter Block defaults from block device geometry for ancient floppies and floppy images, as a fall-back from the default BPB parsing logic.

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

---
Changes since v4:
* Read FAT FS block device size with i_size_read()
* In silent (probing) mode, don't message
* Use dos1xfloppy as a gate to allow trying static BPB values (don't require floppy to be archaic with this option)
* Split out BPB-parsing functionality of fat_fill_super() into two helpers, fat_read_bpb() and fat_read_static_bpb()

Thanks for your patience. I apologize for it taking so many revisions to get it right :).

---
 fs/fat/fat.h   |   3 +-
 fs/fat/inode.c | 353 ++++++++++++++++++++++++++++++++++++++++++---------------
 2 files changed, 266 insertions(+), 90 deletions(-)
fs/fat/fat.h +2 -1
index 7270bdb..13b7202 100644
@@ -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
fs/fat/inode.c +264 -89

488 lines not on this page · raw message

Signature · 1 line
1.9.0
maintainer
#1 lore raw
Quoted 15 lines · Conrad Meyer
fs/fat/inode.c +15 -0
+	sbi->sec_per_clus = fdefaults->sec_per_clus;
+	sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus;
+	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
+	sbi->fats = 2;
+	sbi->fat_start = 1;
+	sbi->fat_length = fdefaults->fat_length;
+
+	sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry);
+	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 = fdefaults->dir_entries;
+
+	rootdir_sectors = sbi->dir_entries
+		* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
+	sbi->data_start = sbi->dir_start + rootdir_sectors;

fs/fat/inode.c int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, · line 1657

Quoted 10 lines
fs/fat/inode.c +10 -0
+	total_sectors = fdefaults->nr_sectors;
+	total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus;
+	sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12;
+
+	/* some OSes set FAT_STATE_DIRTY and clean it on unmount. */
+	sbi->dirty = b->fat16.state & FAT_STATE_DIRTY;
+
+	/* check that FAT table does not overflow */
+	fat_clusters = calc_fat_clusters(sb);
+	total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT);

Ah, you meant this duplicated one.

Let's use structure like fat_boot_sector (but more cpu friendly) on stack or something, instead of modify bh (BPB). Modifying bh in bdev is visible via /dev/foo, this is why I want to avoid to modify.

With this, we can share almost all codes on both of read_bpb() and static_bpb(), and avoids to modify bdev buffer? And those 2 helpers only has small chunk of code, and provide the required parameters?

Thanks.

Signature · 1 line
OGAWA Hirofumi <[email protected]>
#2 lore raw
Quoted 44 lines · On Mon, 14 Apr 2014 07:14:51 +0900 OGAWA Hirofumi…
Quoted 33 lines · Conrad Meyer
(quoted diff) +2 -0
+	sbi->sec_per_clus = fdefaults->sec_per_clus;
+	sbi->cluster_size = sb->s_blocksize *

sbi->sec_per_clus;

fs/fat/inode.c +6 -0
+	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;
+	sbi->fats = 2;
+	sbi->fat_start = 1;
+	sbi->fat_length = fdefaults->fat_length;
+
+	sbi->dir_per_block = sb->s_blocksize /

sizeof(struct msdos_dir_entry);

(quoted diff) +1 -0
+	sbi->dir_per_block_bits =

ffs(sbi->dir_per_block) - 1;

(quoted diff) +1 -0
+	sbi->dir_start = sbi->fat_start + sbi->fats *

sbi->fat_length;

fs/fat/inode.c +4 -0
+	sbi->dir_entries = fdefaults->dir_entries;
+
+	rootdir_sectors = sbi->dir_entries
+		* sizeof(struct msdos_dir_entry) /

sb->s_blocksize;

(quoted diff) +1 -0
+	sbi->data_start = sbi->dir_start +

rootdir_sectors;

(quoted diff) +2 -0
+	total_sectors = fdefaults->nr_sectors;
+	total_clusters = (total_sectors -

sbi->data_start) / sbi->sec_per_clus;

(quoted diff) +1 -0
+	sbi->fat_bits = (total_clusters > MAX_FAT12) ?

16 : 12; +

(quoted diff) +1 -0
+	/* some OSes set FAT_STATE_DIRTY and clean it on

unmount. */

fs/fat/inode.c +5 -0
+	sbi->dirty = b->fat16.state & FAT_STATE_DIRTY;
+
+	/* check that FAT table does not overflow */
+	fat_clusters = calc_fat_clusters(sb);
+	total_clusters = min(total_clusters,
Quoted 1 line

fat_clusters - FAT_START_ENT);

Ah, you meant this duplicated one.

Let's use structure like fat_boot_sector (but more cpu friendly) on stack or something, instead of modify bh (BPB). Modifying bh in bdev is visible via /dev/foo, this is why I want to avoid to modify.

Quoted 6 lines

With this, we can share almost all codes on both of read_bpb() and static_bpb(), and avoids to modify bdev buffer? And those 2 helpers only has small chunk of code, and provide the required parameters?

Thanks.

Hi,

I think I understand the idea, sounds good to me. Working to clean up now.

Thanks again,
Conrad