aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2010-08-10 21:03:34 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-11 11:59:23 -0400
commitab654bab04be435a9671e0dcf49c18f9782dd838 (patch)
tree0e6badaeb18eebeaeff1b8d8bc9049dde7e85ee6 /fs
parent0bcaa65a56ab74003666cf741b0bfa1e9263a11c (diff)
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] Signed-off-by: Lubomir Rintel <lkundrak@v3.sk> Cc: Christoph Hellwig <hch@lst.de> Cc: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/sysv/super.c75
1 files changed, 51 insertions, 24 deletions
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index 3785262b98e0..85359a8df605 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -24,6 +24,7 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/buffer_head.h> 26#include <linux/buffer_head.h>
27#include <linux/parser.h>
27#include "sysv.h" 28#include "sysv.h"
28 29
29/* 30/*
@@ -434,12 +435,46 @@ Ebadsize:
434 goto failed; 435 goto failed;
435} 436}
436 437
437static int v7_fill_super(struct super_block *sb, void *data, int silent) 438static int v7_sanity_check(struct super_block *sb, struct buffer_head *bh)
438{ 439{
439 struct sysv_sb_info *sbi;
440 struct buffer_head *bh, *bh2 = NULL;
441 struct v7_super_block *v7sb; 440 struct v7_super_block *v7sb;
442 struct sysv_inode *v7i; 441 struct sysv_inode *v7i;
442 struct buffer_head *bh2;
443 struct sysv_sb_info *sbi;
444
445 sbi = sb->s_fs_info;
446
447 /* plausibility check on superblock */
448 v7sb = (struct v7_super_block *) bh->b_data;
449 if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE ||
450 fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD ||
451 fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE)
452 return 0;
453
454 /* plausibility check on root inode: it is a directory,
455 with a nonzero size that is a multiple of 16 */
456 bh2 = sb_bread(sb, 2);
457 if (bh2 == NULL)
458 return 0;
459
460 v7i = (struct sysv_inode *)(bh2->b_data + 64);
461 if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||
462 (fs32_to_cpu(sbi, v7i->i_size) == 0) ||
463 (fs32_to_cpu(sbi, v7i->i_size) & 017) ||
464 (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES *
465 sizeof(struct sysv_dir_entry))) {
466 brelse(bh2);
467 return 0;
468 }
469
470 brelse(bh2);
471 return 1;
472}
473
474static int v7_fill_super(struct super_block *sb, void *data, int silent)
475{
476 struct sysv_sb_info *sbi;
477 struct buffer_head *bh;
443 478
444 if (440 != sizeof (struct v7_super_block)) 479 if (440 != sizeof (struct v7_super_block))
445 panic("V7 FS: bad super-block size"); 480 panic("V7 FS: bad super-block size");
@@ -453,7 +488,6 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
453 sbi->s_sb = sb; 488 sbi->s_sb = sb;
454 sbi->s_block_base = 0; 489 sbi->s_block_base = 0;
455 sbi->s_type = FSTYPE_V7; 490 sbi->s_type = FSTYPE_V7;
456 sbi->s_bytesex = BYTESEX_PDP;
457 sb->s_fs_info = sbi; 491 sb->s_fs_info = sbi;
458 492
459 sb_set_blocksize(sb, 512); 493 sb_set_blocksize(sb, 512);
@@ -465,34 +499,27 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
465 goto failed; 499 goto failed;
466 } 500 }
467 501
468 /* plausibility check on superblock */ 502 /* Try PDP-11 UNIX */
469 v7sb = (struct v7_super_block *) bh->b_data; 503 sbi->s_bytesex = BYTESEX_PDP;
470 if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE || 504 if (v7_sanity_check(sb, bh))
471 fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD || 505 goto detected;
472 fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE)
473 goto failed;
474 506
475 /* plausibility check on root inode: it is a directory, 507 /* Try PC/IX, v7/x86 */
476 with a nonzero size that is a multiple of 16 */ 508 sbi->s_bytesex = BYTESEX_LE;
477 if ((bh2 = sb_bread(sb, 2)) == NULL) 509 if (v7_sanity_check(sb, bh))
478 goto failed; 510 goto detected;
479 v7i = (struct sysv_inode *)(bh2->b_data + 64);
480 if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR ||
481 (fs32_to_cpu(sbi, v7i->i_size) == 0) ||
482 (fs32_to_cpu(sbi, v7i->i_size) & 017) ||
483 (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES *
484 sizeof(struct sysv_dir_entry)))
485 goto failed;
486 brelse(bh2);
487 bh2 = NULL;
488 511
512 goto failed;
513
514detected:
489 sbi->s_bh1 = bh; 515 sbi->s_bh1 = bh;
490 sbi->s_bh2 = bh; 516 sbi->s_bh2 = bh;
491 if (complete_read_super(sb, silent, 1)) 517 if (complete_read_super(sb, silent, 1))
492 return 0; 518 return 0;
493 519
494failed: 520failed:
495 brelse(bh2); 521 printk(KERN_ERR "VFS: could not find a valid V7 on %s.\n",
522 sb->s_id);
496 brelse(bh); 523 brelse(bh);
497 kfree(sbi); 524 kfree(sbi);
498 return -EINVAL; 525 return -EINVAL;