patch-2.1.126 linux/fs/ufs/super.c

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

diff -u --recursive --new-file v2.1.125/linux/fs/ufs/super.c linux/fs/ufs/super.c
@@ -1,6 +1,35 @@
 /*
  *  linux/fs/ufs/super.c
  *
+ * Copyright (C) 1998
+ * Daniel Pirkl <daniel.pirkl@email.cz>
+ * Charles University, Faculty of Mathematics and Physics
+ */
+
+/* Derivated from
+ *
+ *  linux/fs/ext2/super.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/inode.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+ 
+/*
+ * Inspirated by
+ *
+ *  linux/fs/ufs/super.c
+ *
  * Copyright (C) 1996
  * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
  * Laboratory for Computer Science Research Computing Facility
@@ -28,20 +57,29 @@
  * 
  */
 
+
 #include <linux/module.h>
-#include <linux/init.h>
 
-#include <linux/kernel.h>
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
-#include <linux/locks.h>
-#include <asm/uaccess.h>
 #include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
 
 #include "swab.h"
 #include "util.h"
 
-
 #undef UFS_SUPER_DEBUG
 #undef UFS_SUPER_DEBUG_MORE
 
@@ -59,39 +97,41 @@
 	struct ufs_super_block_second * usb2, 
 	struct ufs_super_block_third * usb3, unsigned swab)
 {
-	printk("\nufs_print_super_stuff\n");
-	printk("size of usb:    %lu\n", sizeof(struct ufs_super_block));
-	printk("  magic:        0x%x\n", SWAB32(usb3->fs_magic));
-	printk("  sblkno:       %u\n", SWAB32(usb1->fs_sblkno));
-	printk("  cblkno:       %u\n", SWAB32(usb1->fs_cblkno));
-	printk("  iblkno:       %u\n", SWAB32(usb1->fs_iblkno));
-	printk("  dblkno:       %u\n", SWAB32(usb1->fs_dblkno));
-	printk("  cgoffset:     %u\n", SWAB32(usb1->fs_cgoffset));
-	printk("  ~cgmask:      0x%x\n", ~SWAB32(usb1->fs_cgmask));
-	printk("  size:         %u\n", SWAB32(usb1->fs_size));
-	printk("  dsize:        %u\n", SWAB32(usb1->fs_dsize));
-	printk("  ncg:          %u\n", SWAB32(usb1->fs_ncg));
-	printk("  bsize:        %u\n", SWAB32(usb1->fs_bsize));
-	printk("  fsize:        %u\n", SWAB32(usb1->fs_fsize));
-	printk("  frag:         %u\n", SWAB32(usb1->fs_frag));
-	printk("  fragshift:    %u\n", SWAB32(usb1->fs_fragshift));
-	printk("  ~fmask:       %u\n", ~SWAB32(usb1->fs_fmask));
-	printk("  fshift:       %u\n", SWAB32(usb1->fs_fshift));
-	printk("  sbsize:       %u\n", SWAB32(usb1->fs_sbsize));
-	printk("  spc:          %u\n", SWAB32(usb1->fs_spc));
-	printk("  cpg:          %u\n", SWAB32(usb1->fs_cpg));
-	printk("  ipg:          %u\n", SWAB32(usb1->fs_ipg));
-	printk("  fpg:          %u\n", SWAB32(usb1->fs_fpg));
-	printk("  csaddr:       %u\n", SWAB32(usb1->fs_csaddr));
-	printk("  cssize:       %u\n", SWAB32(usb1->fs_cssize));
-	printk("  cgsize:       %u\n", SWAB32(usb1->fs_cgsize));
-	printk("  fstodb:       %u\n", SWAB32(usb1->fs_fsbtodb));
-	printk("  postblformat: %u\n", SWAB32(usb3->fs_postblformat));
-	printk("  nrpos:        %u\n", SWAB32(usb3->fs_nrpos));
-	printk("  ndir          %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
-	printk("  nifree        %u\n", SWAB32(usb1->fs_cstotal.cs_nifree));
-	printk("  nbfree        %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree));
-	printk("  nffree        %u\n", SWAB32(usb1->fs_cstotal.cs_nffree));
+	printk("ufs_print_super_stuff\n");
+	printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
+	printk("  magic:         0x%x\n", SWAB32(usb3->fs_magic));
+	printk("  sblkno:        %u\n", SWAB32(usb1->fs_sblkno));
+	printk("  cblkno:        %u\n", SWAB32(usb1->fs_cblkno));
+	printk("  iblkno:        %u\n", SWAB32(usb1->fs_iblkno));
+	printk("  dblkno:        %u\n", SWAB32(usb1->fs_dblkno));
+	printk("  cgoffset:      %u\n", SWAB32(usb1->fs_cgoffset));
+	printk("  ~cgmask:       0x%x\n", ~SWAB32(usb1->fs_cgmask));
+	printk("  size:          %u\n", SWAB32(usb1->fs_size));
+	printk("  dsize:         %u\n", SWAB32(usb1->fs_dsize));
+	printk("  ncg:           %u\n", SWAB32(usb1->fs_ncg));
+	printk("  bsize:         %u\n", SWAB32(usb1->fs_bsize));
+	printk("  fsize:         %u\n", SWAB32(usb1->fs_fsize));
+	printk("  frag:          %u\n", SWAB32(usb1->fs_frag));
+	printk("  fragshift:     %u\n", SWAB32(usb1->fs_fragshift));
+	printk("  ~fmask:        %u\n", ~SWAB32(usb1->fs_fmask));
+	printk("  fshift:        %u\n", SWAB32(usb1->fs_fshift));
+	printk("  sbsize:        %u\n", SWAB32(usb1->fs_sbsize));
+	printk("  spc:           %u\n", SWAB32(usb1->fs_spc));
+	printk("  cpg:           %u\n", SWAB32(usb1->fs_cpg));
+	printk("  ipg:           %u\n", SWAB32(usb1->fs_ipg));
+	printk("  fpg:           %u\n", SWAB32(usb1->fs_fpg));
+	printk("  csaddr:        %u\n", SWAB32(usb1->fs_csaddr));
+	printk("  cssize:        %u\n", SWAB32(usb1->fs_cssize));
+	printk("  cgsize:        %u\n", SWAB32(usb1->fs_cgsize));
+	printk("  fstodb:        %u\n", SWAB32(usb1->fs_fsbtodb));
+	printk("  contigsumsize: %d\n", SWAB32(usb3->fs_u.fs_44.fs_contigsumsize));
+	printk("  postblformat:  %u\n", SWAB32(usb3->fs_postblformat));
+	printk("  nrpos:         %u\n", SWAB32(usb3->fs_nrpos));
+	printk("  ndir           %u\n", SWAB32(usb1->fs_cstotal.cs_ndir));
+	printk("  nifree         %u\n", SWAB32(usb1->fs_cstotal.cs_nifree));
+	printk("  nbfree         %u\n", SWAB32(usb1->fs_cstotal.cs_nbfree));
+	printk("  nffree         %u\n", SWAB32(usb1->fs_cstotal.cs_nffree));
+	printk("\n");
 }
 
 
@@ -101,107 +141,411 @@
 void ufs_print_cylinder_stuff(struct ufs_cylinder_group *cg, unsigned swab)
 {
 	printk("\nufs_print_cylinder_stuff\n");
-	printk("size of ucg: %lu\n", sizeof(struct ufs_cylinder_group));
-	printk("  magic:       %x\n", SWAB32(cg->cg_magic));
-	printk("  time:        %u\n", SWAB32(cg->cg_time));
-	printk("  cgx:         %u\n", SWAB32(cg->cg_cgx));
-	printk("  ncyl:        %u\n", SWAB16(cg->cg_ncyl));
-	printk("  niblk:       %u\n", SWAB16(cg->cg_niblk));
-	printk("  ndblk:       %u\n", SWAB32(cg->cg_ndblk));
-	printk("  cs_ndir:     %u\n", SWAB32(cg->cg_cs.cs_ndir));
-	printk("  cs_nbfree:   %u\n", SWAB32(cg->cg_cs.cs_nbfree));
-	printk("  cs_nifree:   %u\n", SWAB32(cg->cg_cs.cs_nifree));
-	printk("  cs_nffree:   %u\n", SWAB32(cg->cg_cs.cs_nffree));
-	printk("  rotor:       %u\n", SWAB32(cg->cg_rotor));
-	printk("  frotor:      %u\n", SWAB32(cg->cg_frotor));
-	printk("  irotor:      %u\n", SWAB32(cg->cg_irotor));
-	printk("  frsum:       %u, %u, %u, %u, %u, %u, %u, %u\n",
+	printk("size of ucg: %u\n", sizeof(struct ufs_cylinder_group));
+	printk("  magic:        %x\n", SWAB32(cg->cg_magic));
+	printk("  time:         %u\n", SWAB32(cg->cg_time));
+	printk("  cgx:          %u\n", SWAB32(cg->cg_cgx));
+	printk("  ncyl:         %u\n", SWAB16(cg->cg_ncyl));
+	printk("  niblk:        %u\n", SWAB16(cg->cg_niblk));
+	printk("  ndblk:        %u\n", SWAB32(cg->cg_ndblk));
+	printk("  cs_ndir:      %u\n", SWAB32(cg->cg_cs.cs_ndir));
+	printk("  cs_nbfree:    %u\n", SWAB32(cg->cg_cs.cs_nbfree));
+	printk("  cs_nifree:    %u\n", SWAB32(cg->cg_cs.cs_nifree));
+	printk("  cs_nffree:    %u\n", SWAB32(cg->cg_cs.cs_nffree));
+	printk("  rotor:        %u\n", SWAB32(cg->cg_rotor));
+	printk("  frotor:       %u\n", SWAB32(cg->cg_frotor));
+	printk("  irotor:       %u\n", SWAB32(cg->cg_irotor));
+	printk("  frsum:        %u, %u, %u, %u, %u, %u, %u, %u\n",
 	    SWAB32(cg->cg_frsum[0]), SWAB32(cg->cg_frsum[1]),
 	    SWAB32(cg->cg_frsum[2]), SWAB32(cg->cg_frsum[3]),
 	    SWAB32(cg->cg_frsum[4]), SWAB32(cg->cg_frsum[5]),
 	    SWAB32(cg->cg_frsum[6]), SWAB32(cg->cg_frsum[7]));
-	printk("  btotoff:     %u\n", SWAB32(cg->cg_btotoff));
-	printk("  boff:        %u\n", SWAB32(cg->cg_boff));
-	printk("  iuseoff:     %u\n", SWAB32(cg->cg_iusedoff));
-	printk("  freeoff:     %u\n", SWAB32(cg->cg_freeoff));
-	printk("  nextfreeoff: %u\n", SWAB32(cg->cg_nextfreeoff));
+	printk("  btotoff:      %u\n", SWAB32(cg->cg_btotoff));
+	printk("  boff:         %u\n", SWAB32(cg->cg_boff));
+	printk("  iuseoff:      %u\n", SWAB32(cg->cg_iusedoff));
+	printk("  freeoff:      %u\n", SWAB32(cg->cg_freeoff));
+	printk("  nextfreeoff:  %u\n", SWAB32(cg->cg_nextfreeoff));
+	printk("  clustersumoff %u\n", SWAB32(cg->cg_u.cg_44.cg_clustersumoff));
+	printk("  clusteroff    %u\n", SWAB32(cg->cg_u.cg_44.cg_clusteroff));
+	printk("  nclusterblks  %u\n", SWAB32(cg->cg_u.cg_44.cg_nclusterblks));
+	printk("\n");
 }
 #endif /* UFS_SUPER_DEBUG_MORE */
 
+static char error_buf[1024];
+
+void ufs_error (struct super_block * sb, const char * function,
+	const char * fmt, ...)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	va_list args;
+
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	
+	if (!(sb->s_flags & MS_RDONLY)) {
+		usb1->fs_clean = UFS_FSBAD;
+		ubh_mark_buffer_dirty(USPI_UBH, 1);
+		sb->s_dirt = 1;
+		sb->s_flags |= MS_RDONLY;
+	}
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_ONERROR) {
+	case UFS_MOUNT_ONERROR_PANIC:
+		panic ("UFS-fs panic (device %s): %s: %s\n", 
+			kdevname(sb->s_dev), function, error_buf);
+
+	case UFS_MOUNT_ONERROR_LOCK:
+	case UFS_MOUNT_ONERROR_UMOUNT:
+	case UFS_MOUNT_ONERROR_REPAIR:
+		printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n",
+			kdevname(sb->s_dev), function, error_buf);
+	}		
+}
+
+void ufs_panic (struct super_block * sb, const char * function,
+	const char * fmt, ...)
+{
+	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block_first * usb1;
+	va_list args;
+	
+	uspi = sb->u.ufs_sb.s_uspi;
+	usb1 = ubh_get_usb_first(USPI_UBH);
+	
+	if (!(sb->s_flags & MS_RDONLY)) {
+		usb1->fs_clean = UFS_FSBAD;
+		ubh_mark_buffer_dirty(USPI_UBH, 1);
+		sb->s_dirt = 1;
+	}
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	/* this is to prevent panic from syncing this filesystem */
+	if (sb->s_lock)
+		sb->s_lock = 0;
+	sb->s_flags |= MS_RDONLY;
+	printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
+		kdevname(sb->s_dev), function, error_buf);
+/*** 
+	panic ("UFS-fs panic (device %s): %s: %s\n", 
+		kdevname(sb->s_dev), function, error_buf);
+***/
+}
+
+void ufs_warning (struct super_block * sb, const char * function,
+	const char * fmt, ...)
+{
+	va_list args;
+
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n",
+		kdevname(sb->s_dev), function, error_buf);
+}
+
+static int ufs_parse_options (char * options, unsigned * mount_options)
+{
+	char * this_char;
+	char * value;
+	
+	UFSD(("ENTER\n"))
+	
+	if (!options)
+		return 1;
+		
+	for (this_char = strtok (options, ",");
+	     this_char != NULL;
+	     this_char = strtok (NULL, ",")) {
+	     
+		if ((value = strchr (this_char, '=')) != NULL)
+			*value++ = 0;
+		if (!strcmp (this_char, "ufstype")) {
+			ufs_clear_opt (*mount_options, UFSTYPE);
+			if (!strcmp (value, "old"))
+				ufs_set_opt (*mount_options, UFSTYPE_OLD);
+			else if (!strcmp (value, "sun"))
+				ufs_set_opt (*mount_options, UFSTYPE_SUN);
+			else if (!strcmp (value, "44bsd"))
+				ufs_set_opt (*mount_options, UFSTYPE_44BSD);
+			else if (!strcmp (value, "next"))
+				ufs_set_opt (*mount_options, UFSTYPE_NEXT);
+			else {
+				printk ("UFS-fs: Invalid type option: %s\n", value);
+				return 0;
+			}
+		}
+		else if (!strcmp (this_char, "onerror")) {
+			ufs_clear_opt (*mount_options, ONERROR);
+			if (!strcmp (value, "panic"))
+				ufs_set_opt (*mount_options, ONERROR_PANIC);
+			else if (!strcmp (value, "lock"))
+				ufs_set_opt (*mount_options, ONERROR_LOCK);
+			else if (!strcmp (value, "umount"))
+				ufs_set_opt (*mount_options, ONERROR_UMOUNT);
+			else if (!strcmp (value, "repair")) {
+				printk("UFS-fs: Unable to do repair on error, "
+					"will lock lock instead \n");
+				ufs_set_opt (*mount_options, ONERROR_REPAIR);
+			}
+			else {
+				printk ("UFS-fs: Invalid action onerror: %s\n", value);
+				return 0;
+			}
+		}
+		else {
+			printk("UFS-fs: Invalid option: %s\n", this_char);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+/*
+ * Read on-disk structures asscoiated with cylinder groups
+ */
+int ufs_read_cylinder_structures (struct super_block * sb) {
+	struct ufs_sb_private_info * uspi;
+	struct ufs_buffer_head * ubh;
+	unsigned char * base, * space;
+	unsigned size, blks, i;
+	unsigned swab;
+	
+	UFSD(("ENTER\n"))
+	
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
+	
+	/*
+	 * Read cs structures from (usually) first data block
+	 * on the device. 
+	 */
+	size = uspi->s_cssize;
+	blks = howmany(size, uspi->s_fsize);
+	base = space = kmalloc(size, GFP_KERNEL);
+	if (!base)
+		goto failed; 
+	for (i = 0; i < blks; i += uspi->s_fpb) {
+		size = uspi->s_bsize;
+		if (i + uspi->s_fpb > blks)
+			size = (blks - i) * uspi->s_fsize;
+		ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
+		if (!ubh)
+			goto failed;
+		ubh_ubhcpymem (space, ubh, size);
+		sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+		space += size;
+		ubh_brelse (ubh);
+		ubh = NULL;
+	}
+
+	/*
+	 * Read cylinder group (we read only first fragment from block
+	 * at this time) and prepare internal data structures for cg caching.
+	 */
+	if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
+		goto failed;
+	for (i = 0; i < uspi->s_ncg; i++) 
+		sb->u.ufs_sb.s_ucg[i] = NULL;
+	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+		sb->u.ufs_sb.s_ucpi[i] = NULL;
+		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+	}
+	for (i = 0; i < uspi->s_ncg; i++) {
+		UFSD(("read cg %u\n", i))
+		if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
+			goto failed;
+		if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
+			goto failed;
+#ifdef UFS_SUPER_DEBUG_MORE
+		ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab);
+#endif
+	}
+	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
+		if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+			goto failed;
+		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
+	}
+	sb->u.ufs_sb.s_cg_loaded = 0;
+	UFSD(("EXIT\n"))
+	return 1;
+
+failed:
+	if (base) kfree (base);
+	if (sb->u.ufs_sb.s_ucg) {
+		for (i = 0; i < uspi->s_ncg; i++)
+			if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
+		kfree (sb->u.ufs_sb.s_ucg);
+		for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
+			if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
+	}
+	UFSD(("EXIT (FAILED)\n"))
+	return 0;
+}
+
 /*
- * Called while file system is mounted, read super block
- * and create important internal structures.
+ * Put on-disk structures associated with cylidner groups and 
+ * write them back to disk
  */
-struct super_block * ufs_read_super (
-	struct super_block * sb,
-	void * data,
+void ufs_put_cylinder_structures (struct super_block * sb) {
+	struct ufs_sb_private_info * uspi;
+	struct ufs_buffer_head * ubh;
+	unsigned char * base, * space;
+	unsigned blks, size, i;
+	
+	UFSD(("ENTER\n"))
+	
+	uspi = sb->u.ufs_sb.s_uspi;
+
+	size = uspi->s_cssize;
+	blks = howmany(size, uspi->s_fsize);
+	base = space = (char*) sb->u.ufs_sb.s_csp[0];
+	for (i = 0; i < blks; i += uspi->s_fpb) {
+		size = uspi->s_bsize;
+		if (i + uspi->s_fpb > blks)
+			size = (blks - i) * uspi->s_fsize;
+		ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
+		ubh_memcpyubh (ubh, space, size);
+		space += size;
+		ubh_mark_buffer_uptodate (ubh, 1);
+		ubh_mark_buffer_dirty (ubh, 0);
+		ubh_brelse (ubh);
+	}
+	for (i = 0; i < sb->u.ufs_sb.s_cg_loaded; i++) {
+		ufs_put_cylinder (sb, i);
+		kfree (sb->u.ufs_sb.s_ucpi[i]);
+	}
+	for (; i < UFS_MAX_GROUP_LOADED; i++) 
+		kfree (sb->u.ufs_sb.s_ucpi[i]);
+	for (i = 0; i < uspi->s_ncg; i++) 
+		brelse (sb->u.ufs_sb.s_ucg[i]);
+	kfree (sb->u.ufs_sb.s_ucg);
+	kfree (base);
+	UFSD(("EXIT\n"))
+}
+
+struct super_block * ufs_read_super (struct super_block * sb, void * data,
 	int silent)
 {
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_second * usb2;
 	struct ufs_super_block_third * usb3;
-	struct ufs_buffer_head * ubh;
-	unsigned char * base, * space;
-	unsigned size, blks, i;
+	struct ufs_buffer_head * ubh;	
 	unsigned block_size, super_block_size;
 	unsigned flags, swab;
-	s64 tmp;
-	static unsigned offsets[] = {0, 96, 160};  /* different superblock locations */
-		    
-	UFSD(("ENTER\n"))
-	
+
 	uspi = NULL;
 	ubh = NULL;
-	base = space = NULL;
-	sb->u.ufs_sb.s_ucg = NULL;
 	flags = 0;
+	swab = 0;
 	
-	/* sb->s_dev and sb->s_flags are set by our caller
-	 * data is the mystery argument to sys_mount()
-	 *
-	 * Our caller also sets s_dev, s_covered, s_rd_only, s_dirt,
-	 *   and s_type when we return.
-	 */
-
+	UFSD(("ENTER\n"))
+		
 	MOD_INC_USE_COUNT;
 	lock_super (sb);
 
-	sb->u.ufs_sb.s_uspi = uspi = 
+	/*
+	 * Set default mount options
+	 * Parse mount options
+	 */
+	sb->u.ufs_sb.s_mount_opt = 0;
+	ufs_set_opt (sb->u.ufs_sb.s_mount_opt, ONERROR_LOCK);
+	if (!ufs_parse_options ((char *) data, &sb->u.ufs_sb.s_mount_opt)) {
+		printk("wrong mount options\n");
+		goto failed;
+	}
+	if (!(sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE)) {
+		printk("You didn't specify type of your ufs file system\n\n"
+		"       mount -t ufs -o ufstype=sun|44bsd|old|next ....\n\n"
+		"!!! WARNING !!! wrong value may corrupt you file system\n"
+		"default value is ufstype=old\n");
+		ufs_set_opt (sb->u.ufs_sb.s_mount_opt, UFSTYPE_OLD);
+	}
+
+	sb->u.ufs_sb.s_uspi = uspi =
 		kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL);
 	if (!uspi)
 		goto failed;
+
+	switch (sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) {
+	case UFS_MOUNT_UFSTYPE_44BSD:
+		UFSD(("44bsd ufstype\n"))
+		uspi->s_fsize = block_size = 512;
+		uspi->s_fmask = ~(512 - 1);
+		uspi->s_fshift = 9;
+		uspi->s_sbsize = super_block_size = 1536;
+		uspi->s_sbbase = 0;
+		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
+		break;
+		
+	case UFS_MOUNT_UFSTYPE_SUN:
+		UFSD(("sun  ufstype\n"))
+		uspi->s_fsize = block_size = 1024;
+		uspi->s_fmask = ~(1024 - 1);
+		uspi->s_fshift = 10;
+		uspi->s_sbsize = super_block_size = 2048;
+		uspi->s_sbbase = 0;
+		flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN;
+		break;
+
+	case UFS_MOUNT_UFSTYPE_OLD:
+		UFSD(("old ufstype\n"))
+		uspi->s_fsize = block_size = 1024;
+		uspi->s_fmask = ~(1024 - 1);
+		uspi->s_fshift = 10;
+		uspi->s_sbsize = super_block_size = 2048;
+		uspi->s_sbbase = 0;
+		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
+		if (!(sb->s_flags & MS_RDONLY)) {
+			printk("old type of ufs is supported read-only\n"); 
+			goto failed;
+		}
+		break;
+	
+	case UFS_MOUNT_UFSTYPE_NEXT:
+		UFSD(("next ufstype\n"))
+		uspi->s_fsize = block_size = 1024;
+		uspi->s_fmask = ~(1024 - 1);
+		uspi->s_fshift = 10;
+		uspi->s_sbsize = super_block_size = 2048;
+		uspi->s_sbbase = 0;
+		flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_OLD | UFS_CG_OLD;
+		if (!(sb->s_flags & MS_RDONLY)) {
+			printk("nextstep type of ufs is supported read-only\n");
+			goto failed;
+		}
+		break;
 	
-	block_size = BLOCK_SIZE;
-	super_block_size = BLOCK_SIZE * 2;
 	
-	uspi->s_fsize = block_size;
-	uspi->s_fmask = ~(BLOCK_SIZE - 1);
-	uspi->s_fshift = BLOCK_SIZE_BITS;
-	uspi->s_sbsize = super_block_size;
-	i = 0;
-	uspi->s_sbbase = offsets[i];
+	default:
+		printk("this fs type of ufs is not supported\n");
+		goto failed;
+	}
 	
-again:
+	if (!(sb->s_flags & MS_RDONLY))
+		printk("!!! warning !!! write support of ufs is still in experimental state\n"); 
+
+again:	
 	set_blocksize (sb->s_dev, block_size);
 
 	/*
 	 * read ufs super block from device
 	 */
-	ubh = ubh_bread2 (sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	ubh = ubh_bread_uspi (uspi, sb->s_dev, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
 	if (!ubh) 
 		goto failed;
 	
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	usb2 = ubh_get_usb_second(USPI_UBH);
 	usb3 = ubh_get_usb_third(USPI_UBH);
-	
+
 	/*
 	 * Check ufs magic number
-	 * This code uses goto, because it's a lesser evil than unbalanced
-	 * structure in conditional code. Brought to you by Fare' as a minimal
-	 * hack to live with Daniel's (unnecessary, IMNSHO) manual swab
-	 * optimization -- see swab.h.
 	 */
 #if defined(__LITTLE_ENDIAN) || defined(__BIG_ENDIAN) /* sane bytesex */
 	switch (usb3->fs_magic) {
@@ -222,108 +566,68 @@
 			goto magic_found;
 	}
 #endif
-	/*
-	 * Magic number not found -- try another super block location
-	 */
-	if (++i < sizeof(offsets)/sizeof(unsigned)) {
-		ubh_brelse2(ubh);
+
+	if ((sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE) == 
+	UFS_MOUNT_UFSTYPE_NEXT && uspi->s_sbbase < 256) {
+		ubh_brelse_uspi(uspi);
 		ubh = NULL;
-		uspi->s_sbbase = offsets[i];
+		uspi->s_sbbase += 8;
 		goto again;
-	} else {
-		printk("ufs_read_super: "
-		       "super block location not in "
-		       "{ 0, 96, 160} "
-		       "or bad magic number\n");
-		goto failed;
 	}
-	magic_found:
+	printk("ufs_read_super: bad magic number\n");
+	goto failed;
 
+magic_found:
 	/*
 	 * Check block and fragment sizes
 	 */
 	uspi->s_bsize = SWAB32(usb1->fs_bsize);
 	uspi->s_fsize = SWAB32(usb1->fs_fsize);
 	uspi->s_sbsize = SWAB32(usb1->fs_sbsize);
+	uspi->s_fmask = SWAB32(usb1->fs_fmask);
+	uspi->s_fshift = SWAB32(usb1->fs_fshift);
 
 	if (uspi->s_bsize != 4096 && uspi->s_bsize != 8192) {
-		printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n",
-		       uspi->s_bsize);
+		printk("ufs_read_super: fs_bsize %u != {4096, 8192}\n", uspi->s_bsize);
 		goto failed;
 	}
 	if (uspi->s_fsize != 512 && uspi->s_fsize != 1024) {
-		printk("ufs_read_super: fs_fsize %u != {512, 1024}\n",
-		       uspi->s_fsize);
+		printk("ufs_read_super: fs_fsize %u != {512, 1024}\n", uspi->s_fsize);
 		goto failed;
 	}
-	
-	/*
-	 * Block size is not 1024. Free buffers, set block_size and
-	 * super_block_size to superblock-declared values, and try again.
-	 */
 	if (uspi->s_fsize != block_size || uspi->s_sbsize != super_block_size) {
-		ubh_brelse2(ubh);
+		ubh_brelse_uspi(uspi);
 		ubh = NULL;
-		uspi->s_fmask = SWAB32(usb1->fs_fmask);
-		uspi->s_fshift = SWAB32(usb1->fs_fshift);
 		block_size = uspi->s_fsize;
 		super_block_size = uspi->s_sbsize;
+		UFSD(("another value of block_size or super_block_size %u, %u\n", block_size, super_block_size))
 		goto again;
 	}
 
 #ifdef UFS_SUPER_DEBUG_MORE
 	ufs_print_super_stuff (usb1, usb2, usb3, swab);
 #endif
-	/*
-	 * Check file system flavor
-	 */
-	flags |= UFS_VANILLA;
-	/* XXX more consistency check */
-	UFSD(("ufs_read_super: maxsymlinklen 0x%8.8x\n", usb3->fs_u.fs_44.fs_maxsymlinklen))
-	if (usb3->fs_u.fs_44.fs_maxsymlinklen >= 0) {
-		if (usb3->fs_u.fs_44.fs_inodefmt >= UFS_44INODEFMT) {
-			UFSD(("Flavor: 44BSD\n"))
-			flags |= UFS_44BSD;
-			sb->s_flags |= MS_RDONLY;
-		} else {
-			UFSD(("Flavor: OLD\n"))
-			sb->s_flags |= UFS_OLD;       /* 4.2BSD */
-		}
-	} else if (uspi->s_sbbase > 0) {
-		UFSD(("Flavor: NEXT\n"))
-		flags |= UFS_NEXT;
-		sb->s_flags |= MS_RDONLY;
-	} else {
-		UFSD(("Flavor: SUN\n"))
-		flags |= UFS_SUN;
-	}
 
 	/*
-	 * Check whether file system was correctly unmounted.
+	 * Check, if file system was correctly unmounted.
 	 * If not, make it read only.
 	 */
 	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(usb3) == UFS_FSOK - usb1->fs_time)) {
+	   (((flags & UFS_ST_MASK) == UFS_ST_SUN) && 
+	     (ufs_get_fs_state(usb3) == (UFS_FSOK - SWAB32(usb1->fs_time))))) {
 		switch(usb1->fs_clean) {
-		case UFS_FSACTIVE:	/* 0x00 */
-			printk("ufs_read_super: fs is active\n");
-			sb->s_flags |= MS_RDONLY;
-			break;
-		case UFS_FSCLEAN:	/* 0x01 */
-			UFSD(("ufs_read_super: fs is clean\n"))
+		case UFS_FSCLEAN:
+			UFSD(("fs is clean\n"))
 			break;
 		case UFS_FSSTABLE:
-			UFSD(("ufs_read_super: fs is stable\n"))
+			UFSD(("fs is stable\n"))
 			break;
-		case UFS_FSOSF1:	/* 0x03 */
-		/* XXX - is this the correct interpretation under DEC OSF/1? */
-			printk("ufs_read_super: "
-			       "fs is clean and stable (OSF/1)\n");
+		case UFS_FSACTIVE:
+			printk("ufs_read_super: fs is active\n");
+			sb->s_flags |= MS_RDONLY;
 			break;
-		case UFS_FSBAD:		/* 0xFF */
+		    case UFS_FSBAD:
 			printk("ufs_read_super: fs is bad\n");
 			sb->s_flags |= MS_RDONLY;
 			break;
@@ -333,19 +637,19 @@
 			sb->s_flags |= MS_RDONLY;
 			break;
 		}
-	} else {
+	}
+	else {
 		printk("ufs_read_super: fs needs fsck\n");
 		sb->s_flags |= MS_RDONLY;
 	}
 
-	sb->s_flags &= ~MS_RDONLY;
 	/*
 	 * Read ufs_super_block into internal data structures
 	 */
 	sb->s_blocksize =  SWAB32(usb1->fs_fsize);
 	sb->s_blocksize_bits = SWAB32(usb1->fs_fshift);
 	sb->s_op = &ufs_super_ops;
-	sb->dq_op = 0; /* XXX */
+	sb->dq_op = NULL; /***/
 	sb->s_magic = SWAB32(usb3->fs_magic);
 
 	uspi->s_sblkno = SWAB32(usb1->fs_sblkno);
@@ -385,12 +689,9 @@
 	uspi->s_ipg = SWAB32(usb1->fs_ipg);
 	uspi->s_fpg = SWAB32(usb1->fs_fpg);
 	uspi->s_cpc = SWAB32(usb2->fs_cpc);
-	((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qbmask[0];
-	((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qbmask[1];
-	uspi->s_qbmask = SWAB64(tmp);
-	((u32 *)&tmp)[0] = usb3->fs_u.fs_sun.fs_qfmask[0];
-	((u32 *)&tmp)[1] = usb3->fs_u.fs_sun.fs_qfmask[1];
-	uspi->s_qfmask = SWAB64(tmp);
+	uspi->s_contigsumsize = SWAB32(usb3->fs_u.fs_44.fs_contigsumsize);
+	uspi->s_qbmask = ufs_get_fs_qbmask(usb3);
+	uspi->s_qfmask = ufs_get_fs_qfmask(usb3);
 	uspi->s_postblformat = SWAB32(usb3->fs_postblformat);
 	uspi->s_nrpos = SWAB32(usb3->fs_nrpos);
 	uspi->s_postbloff = SWAB32(usb3->fs_postbloff);
@@ -410,86 +711,32 @@
 	uspi->s_nspfshift = uspi->s_fshift - UFS_SECTOR_BITS;
 	uspi->s_nspb = uspi->s_nspf << uspi->s_fpbshift;
 	uspi->s_inopf = uspi->s_inopb >> uspi->s_fpbshift;
-
-	/* we could merge back s_swab and s_flags by having
-	   foo.s_flags = flags | swab; here, and #defining
-	   s_swab to s_flags & UFS_BYTESEX in swab.h */
+	uspi->s_bpf = uspi->s_fsize << 3;
+	uspi->s_bpfshift = uspi->s_fshift + 3;
+	uspi->s_bpfmask = uspi->s_bpf - 1;
+	
 	sb->u.ufs_sb.s_flags = flags;
 	sb->u.ufs_sb.s_swab = swab;
 	sb->u.ufs_sb.s_rename_lock = 0;
 	sb->u.ufs_sb.s_rename_wait = NULL;
-									  
+	 	                                                          
 	sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
 
-	/*
-	 * Read cs structures from (usually) first data block
-	 * on the device. 
-	 */
-	size = uspi->s_cssize;
-	blks = howmany(size, uspi->s_fsize);
-	base = space = kmalloc(size, GFP_KERNEL);
-	if (!base)
-		goto failed; 
-	for (i = 0; i < blks; i += uspi->s_fpb) {
-		size = uspi->s_bsize;
-		if (i + uspi->s_fpb > blks)
-			size = (blks - i) * uspi->s_fsize;
-		ubh = ubh_bread(sb->s_dev, uspi->s_csaddr + i, size);
-		if (!ubh)
-			goto failed;
-		ubh_ubhcpymem (space, ubh, size);
-		sb->u.ufs_sb.s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
-		space += size;
-		ubh_brelse (ubh);
-		ubh = NULL;
-	}
 
 	/*
-	 * Read cylinder group (we read only first fragment from block
-	 * at this time) and prepare internal data structures for cg caching.
-	 * XXX - something here fails on CDROMs from DEC!
+	 * Read cylinder group structures
 	 */
-	if (!(sb->u.ufs_sb.s_ucg = kmalloc (sizeof(struct buffer_head *) * uspi->s_ncg, GFP_KERNEL)))
-		goto failed;
-	for (i = 0; i < uspi->s_ncg; i++) 
-		sb->u.ufs_sb.s_ucg[i] = NULL;
-	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
-		sb->u.ufs_sb.s_ucpi[i] = NULL;
-		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
-	}
-	for (i = 0; i < uspi->s_ncg; i++) {
-		UFSD(("read cg %u\n", i))
-		if (!(sb->u.ufs_sb.s_ucg[i] = bread (sb->s_dev, ufs_cgcmin(i), sb->s_blocksize)))
-			goto failed;
-		if (!ufs_cg_chkmagic ((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data))
-			goto failed;
-#ifdef UFS_SUPER_DEBUG_MORE
-		ufs_print_cylinder_stuff((struct ufs_cylinder_group *) sb->u.ufs_sb.s_ucg[i]->b_data, swab);
-#endif
-	}
-	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
-		if (!(sb->u.ufs_sb.s_ucpi[i] = kmalloc (sizeof(struct ufs_cg_private_info), GFP_KERNEL)))
+	if (!(sb->s_flags & MS_RDONLY))
+		if (!ufs_read_cylinder_structures(sb))
 			goto failed;
-		sb->u.ufs_sb.s_cgno[i] = UFS_CGNO_EMPTY;
-	}
-	sb->u.ufs_sb.s_cg_loaded = 0;
 
 	unlock_super(sb);
 	UFSD(("EXIT\n"))
 	return(sb);
 
 failed:
-	if (ubh) ubh_brelse2 (ubh);
+	if (ubh) ubh_brelse_uspi (uspi);
 	if (uspi) kfree (uspi);
-	if (base) kfree (base);
-
-	if (sb->u.ufs_sb.s_ucg) {
-		for (i = 0; i < uspi->s_ncg; i++)
-			if (sb->u.ufs_sb.s_ucg[i]) brelse (sb->u.ufs_sb.s_ucg[i]);
-		kfree (sb->u.ufs_sb.s_ucg);
-		for (i = 0; i < UFS_MAX_GROUP_LOADED; i++)
-			if (sb->u.ufs_sb.s_ucpi[i]) kfree (sb->u.ufs_sb.s_ucpi[i]);
-	}
 	sb->s_dev = 0;
 	unlock_super (sb);
 	MOD_DEC_USE_COUNT;
@@ -497,187 +744,132 @@
 	return(NULL);
 }
 
-/*
- * Put super block, release internal structures
- */
-void ufs_put_super (struct super_block * sb)
-{
-	struct ufs_sb_private_info * uspi;
-	struct ufs_buffer_head * ubh;
-	unsigned char * base, * space;
-	unsigned size, blks, i;
-	
-	UFSD(("ENTER\n"))
-	
-	uspi = sb->u.ufs_sb.s_uspi;
-	size = uspi->s_cssize;
-	blks = howmany(size, uspi->s_fsize);
-	base = space = (char*) sb->u.ufs_sb.s_csp[0];
-	for (i = 0; i < blks; i += uspi->s_fpb) {
-		size = uspi->s_bsize;
-		if (i + uspi->s_fpb > blks)
-			size = (blks - i) * uspi->s_fsize;
-		ubh = ubh_bread (sb->s_dev, uspi->s_csaddr + i, size);
-		if (!ubh)
-			goto go_on;
-		ubh_memcpyubh (ubh, space, size);
-		space += size;
-		ubh_mark_buffer_uptodate (ubh, 1);
-		ubh_mark_buffer_dirty (ubh, 0);
-		ubh_brelse (ubh);
-	}
-
-go_on:
-	for (i = 0; i < UFS_MAX_GROUP_LOADED; i++) {
-		ufs_put_cylinder (sb, i);
-		kfree (sb->u.ufs_sb.s_ucpi[i]);
-	}
-	for (i = 0; i < uspi->s_ncg; i++) 
-		brelse (sb->u.ufs_sb.s_ucg[i]);
-	kfree (sb->u.ufs_sb.s_ucg);
-	kfree (base);
-	ubh_brelse2 (USPI_UBH);
-	kfree (sb->u.ufs_sb.s_uspi);
-	sb->s_dev = 0;
-	MOD_DEC_USE_COUNT;
-	return;
-}
-
-/*
- * Write super block to device
- */
 void ufs_write_super (struct super_block * sb) {
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_third * usb3;
-	unsigned swab;
-	
+	unsigned flags, swab;
+
 	UFSD(("ENTER\n"))
 	swab = sb->u.ufs_sb.s_swab;
+	flags = sb->u.ufs_sb.s_flags;
 	uspi = sb->u.ufs_sb.s_uspi;
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	usb3 = ubh_get_usb_third(USPI_UBH);
-	
+
 	if (!(sb->s_flags & MS_RDONLY)) {
-		if (SWAB16(usb3->fs_u.fs_sun.fs_state) & UFS_FSOK)
-			usb3->fs_u.fs_sun.fs_state = SWAB16(SWAB16(usb3->fs_u.fs_sun.fs_state) & ~UFS_FSOK);
 		usb1->fs_time = SWAB32(CURRENT_TIME);
-		usb3->fs_u.fs_sun.fs_state = SWAB32(UFS_FSOK - SWAB32(usb1->fs_time));
+		if (usb1->fs_clean == UFS_FSCLEAN && (flags&UFS_ST_MASK) == UFS_ST_SUN)
+			ufs_set_fs_state(usb3, UFS_FSOK - SWAB32(usb1->fs_time));
 		ubh_mark_buffer_dirty (USPI_UBH, 1);
 	}
 	sb->s_dirt = 0;
 	UFSD(("EXIT\n"))
 }
 
-/*
- * Copy some info about file system to user
- */
-int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz)
+void ufs_put_super (struct super_block * sb)
 {
 	struct ufs_sb_private_info * uspi;
-	struct ufs_super_block_first * usb1;
-	struct statfs tmp;
-	struct statfs *sp = &tmp;
-	unsigned long used, avail;
 	unsigned swab;
-	
+		
 	UFSD(("ENTER\n"))
-	
-	swab = sb->u.ufs_sb.s_swab;
-	uspi = sb->u.ufs_sb.s_uspi;
-	usb1 = ubh_get_usb_first (USPI_UBH);
 
-	sp->f_type = UFS_MAGIC;
-	sp->f_bsize = sb->s_blocksize;
-	sp->f_blocks = uspi->s_dsize;
-	sp->f_bfree = (SWAB32(usb1->fs_cstotal.cs_nbfree) << uspi->s_fpbshift )+
-		SWAB32(usb1->fs_cstotal.cs_nffree);
+	uspi = sb->u.ufs_sb.s_uspi;
+	swab = sb->u.ufs_sb.s_swab;
 
-	avail = sp->f_blocks - (sp->f_blocks / 100) * uspi->s_minfree;
-	used = sp->f_blocks - sp->f_bfree;
-	if (avail > used)
-		sp->f_bavail = avail - used;
-	else
-		sp->f_bavail = 0;
-	sp->f_files = uspi->s_ncg * uspi->s_ipg;
-	sp->f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
-	sp->f_fsid.val[0] = SWAB32(usb1->fs_id[0]);
-	sp->f_fsid.val[1] = SWAB32(usb1->fs_id[1]);
-	sp->f_namelen = UFS_MAXNAMLEN;
+	if (!(sb->s_flags & MS_RDONLY))
+		ufs_put_cylinder_structures (sb);
 	
-	UFSD(("EXIT\n"))
-
-	return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0;
+	ubh_brelse_uspi (uspi);
+	kfree (sb->u.ufs_sb.s_uspi);
+	sb->s_dev = 0;
+	MOD_DEC_USE_COUNT;
+	return;
 }
 
 
-static char error_buf[1024];
-
-void ufs_warning (struct super_block * sb, const char * function,
-	const char * fmt, ...)
-{
-	va_list args;
-
-	va_start (args, fmt);
-	vsprintf (error_buf, fmt, args);
-	va_end (args);
-	printk (KERN_WARNING "UFS-fs warning (device %s): %s: %s\n",
-		kdevname(sb->s_dev), function, error_buf);
-}
-
-void ufs_error (struct super_block * sb, const char * function,
-	const char * fmt, ...)
+int ufs_remount (struct super_block * sb, int * mount_flags, char * data)
 {
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
-	va_list args;
-
+	struct ufs_super_block_third * usb3;
+	unsigned new_mount_opt, ufstype;
+	unsigned flags, swab;
+	
 	uspi = sb->u.ufs_sb.s_uspi;
+	flags = sb->u.ufs_sb.s_flags;
+	swab = sb->u.ufs_sb.s_swab;
 	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb3 = ubh_get_usb_third(USPI_UBH);
 	
-	if (!(sb->s_flags & MS_RDONLY)) {
-		usb1->fs_clean = UFS_FSBAD;
-		ubh_mark_buffer_dirty(USPI_UBH, 1);
-		sb->s_dirt = 1;
+	/*
+	 * Allow the "check" option to be passed as a remount option.
+	 * It is not possible to change ufstype option during remount
+	 */
+	ufstype = sb->u.ufs_sb.s_mount_opt & UFS_MOUNT_UFSTYPE;
+	new_mount_opt = 0;
+	ufs_set_opt (new_mount_opt, ONERROR_LOCK);
+	if (!ufs_parse_options (data, &new_mount_opt))
+		return -EINVAL;
+	if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) {
+		new_mount_opt |= ufstype;
+	}
+	else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {
+		printk("ufstype can't be changed during remount\n");
+		return -EINVAL;
+	}
+	sb->u.ufs_sb.s_mount_opt = new_mount_opt;
+
+	if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+		return 0;
+	if (*mount_flags & MS_RDONLY) {
+		ufs_put_cylinder_structures(sb);
+		usb1->fs_time = SWAB32(CURRENT_TIME);
+		if (usb1->fs_clean == UFS_FSCLEAN && (flags&UFS_ST_MASK) == UFS_ST_SUN)
+			ufs_set_fs_state(usb3, UFS_FSOK - SWAB32(usb1->fs_time));
+		ubh_mark_buffer_dirty (USPI_UBH, 1);
+		sb->s_dirt = 0;
 		sb->s_flags |= MS_RDONLY;
 	}
-	va_start (args, fmt);
-	vsprintf (error_buf, fmt, args);
-	va_end (args);
-	printk (KERN_CRIT "UFS-fs error (device %s): %s: %s\n",
-		kdevname(sb->s_dev), function, error_buf);
+	else {
+		if (ufstype != UFS_MOUNT_UFSTYPE_SUN && 
+		    ufstype != UFS_MOUNT_UFSTYPE_44BSD) {
+			printk("this ufstype is read-only supported\n");
+			return 0;
+		}
+		if (!ufs_read_cylinder_structures (sb)) {
+			printk("failed during remounting\n");
+			return 0;
+		}
+		sb->s_flags &= ~MS_RDONLY;
+	}
+	return 0;
 }
 
-void ufs_panic (struct super_block * sb, const char * function,
-	const char * fmt, ...)
+int ufs_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
 {
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
-	va_list args;
-	
+	struct statfs tmp;
+	unsigned swab;
+
+	swab = sb->u.ufs_sb.s_swab;
 	uspi = sb->u.ufs_sb.s_uspi;
-	usb1 = ubh_get_usb_first(USPI_UBH);
+	usb1 = ubh_get_usb_first (USPI_UBH);
 	
-	if (!(sb->s_flags & MS_RDONLY)) {
-		usb1->fs_clean = UFS_FSBAD;
-		ubh_mark_buffer_dirty(USPI_UBH, 1);
-		sb->s_dirt = 1;
-	}
-	va_start (args, fmt);
-	vsprintf (error_buf, fmt, args);
-	va_end (args);
-	/* this is to prevent panic from syncing this filesystem */
-	if (sb->s_lock)
-		sb->s_lock = 0;
-	sb->s_flags |= MS_RDONLY;
-	printk (KERN_CRIT "UFS-fs panic (device %s): %s: %s\n",
-		kdevname(sb->s_dev), function, error_buf);
-/*	panic ("UFS-fs panic (device %s): %s: %s\n", 
-		kdevname(sb->s_dev), function, error_buf);
-*/
+	tmp.f_type = UFS_MAGIC;
+	tmp.f_bsize = sb->s_blocksize;
+	tmp.f_blocks = uspi->s_dsize;
+	tmp.f_bfree = ufs_blkstofrags(SWAB32(usb1->fs_cstotal.cs_nbfree)) +
+		SWAB32(usb1->fs_cstotal.cs_nffree);
+	tmp.f_bavail = (tmp.f_bfree > ((tmp.f_blocks / 100) * uspi->s_minfree))
+		? (tmp.f_bfree - ((tmp.f_blocks / 100) * uspi->s_minfree)) : 0;
+	tmp.f_files = uspi->s_ncg * uspi->s_ipg;
+	tmp.f_ffree = SWAB32(usb1->fs_cstotal.cs_nifree);
+	tmp.f_namelen = UFS_MAXNAMLEN;
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
-
 static struct super_operations ufs_super_ops = {
 	ufs_read_inode,
 	ufs_write_inode,
@@ -687,20 +879,19 @@
 	ufs_put_super,
 	ufs_write_super,
 	ufs_statfs,
-	NULL,			/* XXX - ufs_remount() */
+	ufs_remount
 };
 
 static struct file_system_type ufs_fs_type = {
-	"ufs",
+	"ufs", 
 	FS_REQUIRES_DEV,
 	ufs_read_super,
 	NULL
 };
 
-
 __initfunc(int init_ufs_fs(void))
 {
-	return(register_filesystem(&ufs_fs_type));
+	return register_filesystem(&ufs_fs_type);
 }
 
 #ifdef MODULE
@@ -715,5 +906,5 @@
 {
 	unregister_filesystem(&ufs_fs_type);
 }
-#endif
 
+#endif

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