Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6d0b5456 authored by Lubomir Rintel's avatar Lubomir Rintel Committed by Al Viro
Browse files

fs/sysv/super.c: add support for non-PDP11 v7 filesystems



This adds byte order autodetection (of PDP-11 and LE filesystems).  No
attempt is made to detect big-endian filesystems -- were there any?
Tested with PDP-11 v7 filesystems and PC-IX maintenance floppy.

[akpm@linux-foundation.org: coding-style fixes]
[AV: parser.h inclusion was a rudiment of discarded stuff]
Signed-off-by: default avatarLubomir Rintel <lkundrak@v3.sk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 496ee9b8
Loading
Loading
Loading
Loading
+50 −24
Original line number Diff line number Diff line
@@ -434,12 +434,46 @@ Ebadsize:
	goto failed;
}

static int v7_fill_super(struct super_block *sb, void *data, int silent)
static int v7_sanity_check(struct super_block *sb, struct buffer_head *bh)
{
	struct sysv_sb_info *sbi;
	struct buffer_head *bh, *bh2 = NULL;
	struct v7_super_block *v7sb;
	struct sysv_inode *v7i;
	struct buffer_head *bh2;
	struct sysv_sb_info *sbi;

	sbi = sb->s_fs_info;

	/* plausibility check on superblock */
	v7sb = (struct v7_super_block *) bh->b_data;
	if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE ||
	    fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD ||
	    fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE)
		return 0;

	/* plausibility check on root inode: it is a directory,
	   with a nonzero size that is a multiple of 16 */
	bh2 = sb_bread(sb, 2);
	if (bh2 == NULL)
		return 0;

	v7i = (struct sysv_inode *)(bh2->b_data + 64);
	if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||
	    (fs32_to_cpu(sbi, v7i->i_size) == 0) ||
	    (fs32_to_cpu(sbi, v7i->i_size) & 017) ||
	    (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES *
	     sizeof(struct sysv_dir_entry))) {
		brelse(bh2);
		return 0;
	}

	brelse(bh2);
	return 1;
}

static int v7_fill_super(struct super_block *sb, void *data, int silent)
{
	struct sysv_sb_info *sbi;
	struct buffer_head *bh;

	if (440 != sizeof (struct v7_super_block))
		panic("V7 FS: bad super-block size");
@@ -453,7 +487,6 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
	sbi->s_sb = sb;
	sbi->s_block_base = 0;
	sbi->s_type = FSTYPE_V7;
	sbi->s_bytesex = BYTESEX_PDP;
	sb->s_fs_info = sbi;
	
	sb_set_blocksize(sb, 512);
@@ -465,34 +498,27 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
		goto failed;
	}

	/* plausibility check on superblock */
	v7sb = (struct v7_super_block *) bh->b_data;
	if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE ||
	    fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD ||
	    fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE)
		goto failed;
	/* Try PDP-11 UNIX */
	sbi->s_bytesex = BYTESEX_PDP;
	if (v7_sanity_check(sb, bh))
		goto detected;

	/* Try PC/IX, v7/x86 */
	sbi->s_bytesex = BYTESEX_LE;
	if (v7_sanity_check(sb, bh))
		goto detected;

	/* plausibility check on root inode: it is a directory,
	   with a nonzero size that is a multiple of 16 */
	if ((bh2 = sb_bread(sb, 2)) == NULL)
		goto failed;
	v7i = (struct sysv_inode *)(bh2->b_data + 64);
	if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||
	    (fs32_to_cpu(sbi, v7i->i_size) == 0) ||
	    (fs32_to_cpu(sbi, v7i->i_size) & 017) ||
	    (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES *
	     sizeof (struct sysv_dir_entry)))
	goto failed;
	brelse(bh2);
	bh2 = NULL;

detected:
	sbi->s_bh1 = bh;
	sbi->s_bh2 = bh;
	if (complete_read_super(sb, silent, 1))
		return 0;

failed:
	brelse(bh2);
	printk(KERN_ERR "VFS: could not find a valid V7 on %s.\n",
		sb->s_id);
	brelse(bh);
	kfree(sbi);
	return -EINVAL;