patch-2.1.87 linux/fs/ufs/ufs_super.c

Next file: linux/fs/ufs/ufs_swab.c
Previous file: linux/fs/ufs/ufs_namei.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.86/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
@@ -19,8 +19,19 @@
  *
  * Clean swab support on 19970406 by
  * Francois-Rene Rideau <rideau@ens.fr>
+ *
+ * 4.4BSD (FreeBSD) support added on February 1st 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
+ * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
+ *
+ * NeXTstep support added on February 5th 1998 by
+ * Niels Kristian Bech Jensen <nkbj@image.dk>.
  */
 
+#undef DEBUG_UFS_SUPER
+/*#define DEBUG_UFS_SUPER 1*/
+/* Uncomment the line above when hacking ufs superblock code */
+
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -42,7 +53,7 @@
 	NULL,			/* XXX - ufs_write_inode() */
 	ufs_put_inode,
 	NULL,			/* XXX - ufs_delete_inode() */
-	NULL,			/* notify_change() */
+	NULL,			/* XXX - notify_change() */
 	ufs_put_super,
 	NULL,			/* XXX - ufs_write_super() */
 	ufs_statfs,
@@ -89,23 +100,26 @@
 		kdevname(sb->s_dev), function, error_buf);
 }
 
-#if 0 /* unused */
+#ifdef DEBUG_UFS_SUPER
 static void
 ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb)
 {
+	__u32 flags = sb->u.ufs_sb.s_flags;
 
 	printk("fs_sblkno: 0x%8.8x\n", usb->fs_sblkno);
-	printk("fs_size: 0x%8.8x\n", usb->fs_size);
-	printk("fs_ncg: 0x%8.8x\n", usb->fs_ncg);
-	printk("fs_bsize: 0x%8.8x\n", usb->fs_bsize);
-	printk("fs_frag: 0x%8.8x\n", usb->fs_frag);
+	printk("fs_size:   0x%8.8x\n", usb->fs_size);
+	printk("fs_ncg:    0x%8.8x\n", usb->fs_ncg);
+	printk("fs_bsize:  0x%8.8x\n", usb->fs_bsize);
+	printk("fs_fsize:  0x%8.8x\n", usb->fs_fsize);
+	printk("fs_frag:   0x%8.8x\n", usb->fs_frag);
 	printk("fs_nindir: 0x%8.8x\n", usb->fs_nindir);
-	printk("fs_inopb: 0x%8.8x\n", usb->fs_inopb);
-	printk("fs_optim: 0x%8.8x\n", usb->fs_optim);
-	printk("fs_ncyl: 0x%8.8x\n", usb->fs_ncyl);
-	printk("fs_state: 0x%8.8x\n", usb->fs_state);
-	printk("fs_magic: 0x%8.8x\n", usb->fs_magic);
-	printk("fs_fsmnt: `%s'\n", usb->fs_fsmnt);
+	printk("fs_inopb:  0x%8.8x\n", usb->fs_inopb);
+	printk("fs_optim:  0x%8.8x\n", usb->fs_optim);
+	printk("fs_ncyl:   0x%8.8x\n", usb->fs_ncyl);
+	printk("fs_clean:  0x%8.8x\n", usb->fs_clean);
+	printk("fs_state:  0x%8.8x\n", UFS_STATE(usb));
+	printk("fs_magic:  0x%8.8x\n", usb->fs_magic);
+	printk("fs_fsmnt:  `%s'\n", usb->fs_fsmnt);
 
 	return;
 }
@@ -116,7 +130,9 @@
 {
 	struct ufs_superblock * usb;	/* normalized to local byteorder */
 	struct buffer_head * bh1, *bh2;
-	__u32 bytesex = 0;
+	__u32 flags = UFS_DEBUG_INITIAL; /* for sb->u.ufs_sb.s_flags */
+	static int offsets[] = { 0, 96, 160 };	/* different superblock locations */
+	int i;
 
 	/* sb->s_dev and sb->s_flags are set by our caller
 	 * data is the mystery argument to sys_mount()
@@ -127,102 +143,137 @@
 
 	MOD_INC_USE_COUNT;
 	lock_super (sb);
+	set_blocksize (sb->s_dev, BLOCK_SIZE);
 
 	/* XXX - make everything read only for testing */
 	sb->s_flags |= MS_RDONLY;
 
-	if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) ||
-	    !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE,
-	                  BLOCK_SIZE))) {
-		brelse(bh1);
-	        printk ("ufs_read_super: unable to read superblock\n");
+	for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) {
+		if (!(bh1 = bread(sb->s_dev, offsets[i] + UFS_SBLOCK/BLOCK_SIZE,
+		            BLOCK_SIZE)) ||
+		    !(bh2 = bread(sb->s_dev, offsets[i] +
+		            UFS_SBLOCK/BLOCK_SIZE + 1, BLOCK_SIZE))) {
+			brelse(bh1);
+		        printk ("ufs_read_super: unable to read superblock\n");
+			goto ufs_read_super_lose;
+		}
+		/* XXX - redo this so we can free it later... */
+		usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
+		if (usb == NULL) {
+			brelse(bh1);
+			brelse(bh2);
+		        printk ("ufs_read_super: get_free_page() failed\n");
+			goto ufs_read_super_lose;
+		}
+
+		memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
+		memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
+		       sizeof(struct ufs_superblock) - BLOCK_SIZE);
 
-		goto ufs_read_super_lose;
-	}
-	/* XXX - redo this so we can free it later... */
-	usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL);
-	if (usb == NULL) {
 		brelse(bh1);
 		brelse(bh2);
-	        printk ("ufs_read_super: get_free_page() failed\n");
 
-		goto ufs_read_super_lose;
-	}
-
-	memcpy((char *)usb, bh1->b_data, BLOCK_SIZE);
-	memcpy((char *)usb + BLOCK_SIZE, bh2->b_data,
-	       sizeof(struct ufs_superblock) - BLOCK_SIZE);
-
-	brelse(bh1);
-	brelse(bh2);
-
-	switch (le32_to_cpup(&usb->fs_magic)) {
-		case UFS_MAGIC:
-			bytesex = UFS_LITTLE_ENDIAN;
-			ufs_superblock_le_to_cpus(usb);
-			break;
-		case UFS_CIGAM:
-			bytesex = UFS_BIG_ENDIAN;
-			ufs_superblock_be_to_cpus(usb);
-			break;
-			/* usb is now normalized to local byteorder */
-		default:
-	                printk ("ufs_read_super: bad magic number 0x%8.8x "
-				"on dev %d/%d\n", usb->fs_magic,
-				MAJOR(sb->s_dev), MINOR(sb->s_dev));
-			goto ufs_read_super_lose;
+		switch (le32_to_cpup(&usb->fs_magic)) {
+			case UFS_MAGIC:
+				flags |= UFS_LITTLE_ENDIAN;
+				ufs_superblock_le_to_cpus(usb);
+				goto found;
+			case UFS_CIGAM:
+				flags |= UFS_BIG_ENDIAN;
+				ufs_superblock_be_to_cpus(usb);
+				goto found;
+				/* usb is now normalized to local byteorder */
+			default:
+		}
 	}
-
+	printk ("ufs_read_super: bad magic number 0x%8.8x "
+		"on dev %d/%d\n", usb->fs_magic,
+		MAJOR(sb->s_dev), MINOR(sb->s_dev));
+	goto ufs_read_super_lose;
+found:
+#ifdef DEBUG_UFS_SUPER
+	printk("ufs_read_super: superblock offset 0x%2.2x\n", offsets[i]);
+#endif
 	/* We found a UFS filesystem on this device. */
 
 	/* XXX - parse args */
 
-	if (usb->fs_bsize != UFS_BSIZE) {
-	        printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize,
-	               UFS_BSIZE);
+	if ((usb->fs_bsize != 4096) && (usb->fs_bsize != 8192)) {
+	        printk("ufs_read_super: invalid fs_bsize = %d\n",
+	               usb->fs_bsize);
 	        goto ufs_read_super_lose;
 	}
 
-	if (usb->fs_fsize != UFS_FSIZE) {
-	        printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize,
-	               UFS_FSIZE);
+	if ((usb->fs_fsize != 512) && (usb->fs_fsize != 1024)) {
+	        printk("ufs_read_super: invalid fs_fsize = %d\n",
+	               usb->fs_fsize);
 	        goto ufs_read_super_lose;
 	}
+	if (usb->fs_fsize != BLOCK_SIZE) {
+		set_blocksize (sb->s_dev, usb->fs_fsize);
+	}
 
+	flags |= UFS_VANILLA;
+	/* XXX more consistency check */
 #ifdef DEBUG_UFS_SUPER
-	printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt);
+	printk("ufs_read_super: maxsymlinklen 0x%8.8x\n",
+	        usb->fs_u.fs_44.fs_maxsymlinklen);
 #endif
+	if (usb->fs_u.fs_44.fs_maxsymlinklen >= 0) {
+        	if (usb->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
+                	flags |= UFS_44BSD;
+                } else {
+                	flags |= UFS_OLD;	/* 4.2BSD */
+                }
+	} else if (offsets[i] > 0) {
+		flags |= UFS_NEXT;
+	} else {
+		flags |= UFS_SUN;
+	}
 
-	if (usb->fs_state == UFS_FSOK - usb->fs_time) {
-	        switch(usb->fs_clean) {
-	                case UFS_FSCLEAN:
 #ifdef DEBUG_UFS_SUPER
-	                  printk("ufs_read_super: fs is clean\n");
+	ufs_print_super_stuff(sb, usb);
+#endif
+	if (    ((flags&UFS_ST_MASK)==UFS_ST_44BSD)
+             || ((flags&UFS_ST_MASK)==UFS_ST_OLD)
+             || ((flags&UFS_ST_MASK)==UFS_ST_NEXT)
+             || ( ((flags&UFS_ST_MASK)==UFS_ST_SUN)
+                  && UFS_STATE(usb) == UFS_FSOK - usb->fs_time)) {
+		switch(usb->fs_clean) {
+			case UFS_FSACTIVE:	/* 0x00 */
+				printk("ufs_read_super: fs is active\n");
+				sb->s_flags |= MS_RDONLY;
+				break;
+			case UFS_FSCLEAN:	/* 0x01 */
+#ifdef DEBUG_UFS_SUPER
+				printk("ufs_read_super: fs is clean\n");
+#endif
+				break;
+			case UFS_FSSTABLE:	/* 0x02 */
+#ifdef DEBUG_UFS_SUPER
+				printk("ufs_read_super: fs is stable\n");
 #endif
-	                  break;
-	                case UFS_FSSTABLE:
+				break;
+			case UFS_FSOSF1:	/* 0x03 */
+				/* XXX is this correct for DEC OSF/1? */
 #ifdef DEBUG_UFS_SUPER
-	                  printk("ufs_read_super: fs is stable\n");
+				printk("ufs_read_super: fs is clean and stable (OSF/1)\n");
 #endif
-	                  break;
-	                case UFS_FSACTIVE:
-	                  printk("ufs_read_super: fs is active\n");
-	                  sb->s_flags |= MS_RDONLY;
-	                  break;
-	                case UFS_FSBAD:
-	                  printk("ufs_read_super: fs is bad\n");
-	                  sb->s_flags |= MS_RDONLY;
-	                  break;
-	                default:
-	                  printk("ufs_read_super: can't grok fs_clean 0x%x\n",
-	                         usb->fs_clean);
-	                  sb->s_flags |= MS_RDONLY;
-	                  break;
-	        }
+				break;
+			case UFS_FSBAD:		/* 0xFF */
+				printk("ufs_read_super: fs is bad\n");
+				sb->s_flags |= MS_RDONLY;
+				break;
+			default:
+				printk("ufs_read_super: can't grok fs_clean 0x%x\n",
+					usb->fs_clean);
+				sb->s_flags |= MS_RDONLY;
+				break;
+		}
 	} else {
-	        printk("ufs_read_super: fs needs fsck\n");
-	        sb->s_flags |= MS_RDONLY;
-	        /* XXX - make it read only or barf if it's not (/, /usr) */
+		printk("ufs_read_super: fs needs fsck\n");
+		sb->s_flags |= MS_RDONLY;
+		/* XXX - make it read only or barf if it's not (/, /usr) */
 	}
 
 	/* XXX - sanity check sb fields */
@@ -238,7 +289,7 @@
 	/* sb->s_wait */
 	/* XXX - sb->u.ufs_sb */
 	sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */
-	sb->u.ufs_sb.s_flags = bytesex | UFS_DEBUG_INITIAL ;
+	sb->u.ufs_sb.s_flags = flags ;
 	sb->u.ufs_sb.s_ncg = usb->fs_ncg;
 	sb->u.ufs_sb.s_ipg = usb->fs_ipg;
 	sb->u.ufs_sb.s_fpg = usb->fs_fpg;
@@ -257,6 +308,7 @@
 	sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask)
 					>> usb->fs_fshift);
 	sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */
+	sb->u.ufs_sb.s_blockbase = offsets[i];
 	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
 
 #ifdef DEBUG_UFS_SUPER
@@ -271,6 +323,7 @@
 
 ufs_read_super_lose:
 	/* XXX - clean up */
+	set_blocksize (sb->s_dev, BLOCK_SIZE);
 	sb->s_dev = 0;
 	unlock_super (sb);
 	MOD_DEC_USE_COUNT;
@@ -285,6 +338,7 @@
 
 	lock_super (sb);
 	/* XXX - sync fs data, set state to ok, and flush buffers */
+	set_blocksize (sb->s_dev, BLOCK_SIZE);
 	sb->s_dev = 0;
 
 	/* XXX - free allocated kernel memory */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov