From: Niraj Kumar <niraj17@iitbombay.org>

This patch adds read-only support for ufs2 (used in FreeBSD 5.x) variant of
ufs filesystem.  For filesystem specific tools, see
http://ufs-linux.sourceforge.com .


---

 Documentation/filesystems/ufs.txt |    3 
 fs/Kconfig                        |    3 
 fs/ufs/inode.c                    |  149 ++++++++++++++++++++++++++++++++-
 fs/ufs/namei.c                    |    3 
 fs/ufs/super.c                    |  137 ++++++++++++++++++++++++++----
 fs/ufs/util.c                     |   10 +-
 fs/ufs/util.h                     |    4 
 include/linux/ufs_fs.h            |  170 ++++++++++++++++++++++++++++++++++----
 include/linux/ufs_fs_i.h          |    1 
 9 files changed, 434 insertions(+), 46 deletions(-)

diff -puN fs/ufs/inode.c~ufs2-01 fs/ufs/inode.c
--- 25/fs/ufs/inode.c~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/fs/ufs/inode.c	2004-02-23 00:32:57.000000000 -0800
@@ -82,7 +82,12 @@ static int ufs_block_to_path(struct inod
 	return n;
 }
 
-int ufs_frag_map(struct inode *inode, int frag)
+/*
+ * Returns the location of the fragment from
+ * the begining of the filesystem.
+ */
+
+u64  ufs_frag_map(struct inode *inode, int frag)
 {
 	struct ufs_inode_info *ufsi = UFS_I(inode);
 	struct super_block *sb = inode->i_sb;
@@ -93,6 +98,9 @@ int ufs_frag_map(struct inode *inode, in
 	int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets);
 	int ret = 0;
 	u32 block;
+	u64 u2_block = 0;
+	unsigned flags = UFS_SB(sb)->s_flags;
+	u64 temp = 0;
 
 	if (depth == 0)
 		return 0;
@@ -100,6 +108,9 @@ int ufs_frag_map(struct inode *inode, in
 	p = offsets;
 
 	lock_kernel();
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+		goto ufs2;
+
 	block = ufsi->i_u1.i_data[*p++];
 	if (!block)
 		goto out;
@@ -116,6 +127,28 @@ int ufs_frag_map(struct inode *inode, in
 			goto out;
 	}
 	ret = uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask);
+	goto out;
+ufs2:
+	u2_block = ufsi->i_u1.u2_i_data[*p++];
+	if (!u2_block)
+		goto out;
+
+	temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block);
+
+	while (--depth) {
+		struct buffer_head *bh;
+		u64 n = *p++;
+
+		bh = sb_bread(sb, temp +(n>>shift));
+		if (!bh)
+			goto out;
+		u2_block = ((u64*)bh->b_data)[n & mask];
+		brelse(bh);
+		if (!u2_block)
+			goto out;
+	}
+	ret = temp + (frag & uspi->s_fpbmask);
+
 out:
 	unlock_kernel();
 	return ret;
@@ -132,12 +165,20 @@ static struct buffer_head * ufs_inode_ge
 	unsigned block, blockoff, lastfrag, lastblock, lastblockoff;
 	unsigned tmp, goal;
 	u32 * p, * p2;
+	unsigned flags = 0;
 
 	UFSD(("ENTER, ino %lu, fragment %u, new_fragment %u, required %u\n",
 		inode->i_ino, fragment, new_fragment, required))         
 
 	sb = inode->i_sb;
 	uspi = UFS_SB(sb)->s_uspi;
+
+	flags = UFS_SB(sb)->s_flags;
+        /* TODO : to be done for write support
+        if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+             goto ufs2;
+         */
+
 	block = ufs_fragstoblks (fragment);
 	blockoff = ufs_fragnum (fragment);
 	p = ufsi->i_u1.i_data + block;
@@ -230,6 +271,21 @@ repeat:
 	mark_inode_dirty(inode);
 	UFSD(("EXIT, result %u\n", tmp + blockoff))
 	return result;
+
+     /* This part : To be implemented ....
+        Required only for writing, not required for READ-ONLY.
+ufs2:
+
+	u2_block = ufs_fragstoblks(fragment);
+	u2_blockoff = ufs_fragnum(fragment);
+	p = ufsi->i_u1.u2_i_data + block;
+	goal = 0;
+
+repeat2:
+	tmp = fs32_to_cpu(sb, *p);
+	lastfrag = ufsi->i_lastfrag;
+
+     */
 }
 
 static struct buffer_head * ufs_block_getfrag (struct inode *inode,
@@ -308,21 +364,28 @@ out:
 	return result;
 }
 
+/*
+ * This function gets the block which contains the fragment.
+ */
+
 static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
 {
 	struct super_block * sb = inode->i_sb;
 	struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
 	struct buffer_head * bh;
 	int ret, err, new;
-	unsigned long ptr, phys;
+	unsigned long ptr,phys;
+	u64 phys64 = 0;
 	
 	if (!create) {
-		phys = ufs_frag_map(inode, fragment);
-		if (phys)
-			map_bh(bh_result, sb, phys);
+		phys64 = ufs_frag_map(inode, fragment);
+		if (phys64)
+			map_bh(bh_result, sb, phys64);
 		return 0;
 	}
 
+        /* This code entered only while writing ....? */
+
 	err = -EIO;
 	new = 0;
 	ret = 0;
@@ -474,6 +537,7 @@ void ufs_read_inode (struct inode * inod
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_inode * ufs_inode;	
+	struct ufs2_inode *ufs2_inode;
 	struct buffer_head * bh;
 	mode_t mode;
 	unsigned i;
@@ -496,6 +560,9 @@ void ufs_read_inode (struct inode * inod
 		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
 		goto bad_inode;
 	}
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+		goto ufs2_inode;
+
 	ufs_inode = (struct ufs_inode *) (bh->b_data + sizeof(struct ufs_inode) * ufs_inotofsbo(inode->i_ino));
 
 	/*
@@ -564,6 +631,78 @@ void ufs_read_inode (struct inode * inod
 bad_inode:
 	make_bad_inode(inode);
 	return;
+
+ufs2_inode :
+	UFSD(("Reading ufs2 inode, ino %lu\n", inode->i_ino))
+
+	ufs2_inode = (struct ufs2_inode *)(bh->b_data + sizeof(struct ufs2_inode) * ufs_inotofsbo(inode->i_ino));
+
+	/*
+	 * Copy data to the in-core inode.
+	 */
+	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode);
+	inode->i_nlink = fs16_to_cpu(sb, ufs2_inode->ui_nlink);
+	if (inode->i_nlink == 0)
+		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
+
+        /*
+         * Linux now has 32-bit uid and gid, so we can support EFT.
+         */
+	inode->i_uid = fs32_to_cpu(sb, ufs2_inode->ui_uid);
+	inode->i_gid = fs32_to_cpu(sb, ufs2_inode->ui_gid);
+
+	inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size);
+	inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_atime.tv_sec);
+	inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_ctime.tv_sec);
+	inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs2_inode->ui_mtime.tv_sec);
+	inode->i_mtime.tv_nsec = 0;
+	inode->i_atime.tv_nsec = 0;
+	inode->i_ctime.tv_nsec = 0;
+	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
+	inode->i_blksize = PAGE_SIZE; /*This is the optimal IO size(for stat)*/
+
+	inode->i_version++;
+	ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags);
+	ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen);
+	/*
+	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
+	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
+	*/
+	ufsi->i_lastfrag= (inode->i_size + uspi->s_fsize- 1) >> uspi->s_fshift;
+
+	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++)
+			ufsi->i_u1.u2_i_data[i] =
+				ufs2_inode->ui_u2.ui_addr.ui_db[i];
+	}
+	else {
+		for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++)
+			ufsi->i_u1.i_symlink[i] = ufs2_inode->ui_u2.ui_symlink[i];
+	}
+	ufsi->i_osync = 0;
+
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &ufs_file_inode_operations;
+		inode->i_fop = &ufs_file_operations;
+		inode->i_mapping->a_ops = &ufs_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &ufs_dir_inode_operations;
+		inode->i_fop = &ufs_dir_operations;
+	} else if (S_ISLNK(inode->i_mode)) {
+		if (!inode->i_blocks)
+			inode->i_op = &ufs_fast_symlink_inode_operations;
+		else {
+			inode->i_op = &page_symlink_inode_operations;
+			inode->i_mapping->a_ops = &ufs_aops;
+		}
+	} else   /* TODO  : here ...*/
+		init_special_inode(inode, inode->i_mode,
+			old_decode_dev(fs32_to_cpu(sb, ufsi->i_u1.i_data[0])));
+
+	brelse(bh);
+
+	UFSD(("EXIT\n"))
+	return;
 }
 
 static int ufs_update_inode(struct inode * inode, int do_sync)
diff -puN fs/ufs/namei.c~ufs2-01 fs/ufs/namei.c
--- 25/fs/ufs/namei.c~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/fs/ufs/namei.c	2004-02-23 00:32:57.000000000 -0800
@@ -31,7 +31,10 @@
 #include <linux/buffer_head.h>
 #include "swab.h"	/* will go away - see comment in mknod() */
 
+/*
 #undef UFS_NAMEI_DEBUG
+*/
+#define UFS_NAMEI_DEBUG
 
 #ifdef UFS_NAMEI_DEBUG
 #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
diff -puN fs/ufs/super.c~ufs2-01 fs/ufs/super.c
--- 25/fs/ufs/super.c~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/fs/ufs/super.c	2004-02-23 00:32:57.000000000 -0800
@@ -58,6 +58,9 @@
  * HP/UX hfs filesystem support added by
  * Martin K. Petersen <mkp@mkp.net>, August 1999
  *
+ * UFS2 (of FreeBSD 5.x) support added by
+ * Niraj Kumar <niraj17@iitbombay.org>, Jan 2004
+ *
  */
 
 
@@ -142,6 +145,28 @@ void ufs_print_super_stuff(struct super_
 	printk("\n");
 }
 
+/*
+ * Print contents of ufs2 ufs_super_block, useful for debugging
+ */
+void ufs2_print_super_stuff(
+     struct super_block *sb,
+      struct ufs_super_block *usb)
+{
+	printk("ufs_print_super_stuff\n");
+	printk("size of usb:     %u\n", sizeof(struct ufs_super_block));
+	printk("  magic:         0x%x\n", fs32_to_cpu(sb, usb->fs_magic));
+	printk("  fs_size:   %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size));
+	printk("  fs_dsize:  %u\n",fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize));
+	printk("  fs_volname:  %s\n", usb->fs_u11.fs_u2.fs_volname);
+	printk("  fs_fsmnt:  %s\n", usb->fs_u11.fs_u2.fs_fsmnt);
+	printk("  fs_sblockloc: %u\n",fs64_to_cpu(sb,
+			usb->fs_u11.fs_u2.fs_sblockloc));
+	printk("  cs_ndir(No of dirs):  %u\n",fs64_to_cpu(sb,
+			usb->fs_u11.fs_u2.fs_cstotal.cs_ndir));
+	printk("  cs_nbfree(No of free blocks):  %u\n",fs64_to_cpu(sb,
+			usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree));
+	printk("\n");
+}
 
 /*
  * Print contents of ufs_cylinder_group, useful for debugging
@@ -253,7 +278,7 @@ void ufs_warning (struct super_block * s
 
 enum {
 	Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd,
-	Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep,
+	Opt_type_ufs2, Opt_type_hp, Opt_type_nextstepcd, Opt_type_nextstep,
 	Opt_type_openstep, Opt_onerror_panic, Opt_onerror_lock,
 	Opt_onerror_umount, Opt_onerror_repair, Opt_err
 };
@@ -263,6 +288,8 @@ static match_table_t tokens = {
 	{Opt_type_sunx86, "ufstype=sunx86"},
 	{Opt_type_sun, "ufstype=sun"},
 	{Opt_type_44bsd, "ufstype=44bsd"},
+	{Opt_type_ufs2, "ufstype=ufs2"},
+	{Opt_type_ufs2, "ufstype=5xbsd"},
 	{Opt_type_hp, "ufstype=hp"},
 	{Opt_type_nextstepcd, "ufstype=nextstep-cd"},
 	{Opt_type_nextstep, "ufstype=nextstep"},
@@ -307,6 +334,10 @@ static int ufs_parse_options (char * opt
 			ufs_clear_opt (*mount_options, UFSTYPE);
 			ufs_set_opt (*mount_options, UFSTYPE_44BSD);
 			break;
+		case Opt_type_ufs2:
+			ufs_clear_opt(*mount_options, UFSTYPE);
+			ufs_set_opt(*mount_options, UFSTYPE_UFS2);
+			break;
 		case Opt_type_hp:
 			ufs_clear_opt (*mount_options, UFSTYPE);
 			ufs_set_opt (*mount_options, UFSTYPE_HP);
@@ -356,13 +387,20 @@ static int ufs_parse_options (char * opt
 int ufs_read_cylinder_structures (struct super_block * sb) {
 	struct ufs_sb_info * sbi = UFS_SB(sb);
 	struct ufs_sb_private_info * uspi;
+	struct ufs_super_block *usb;
 	struct ufs_buffer_head * ubh;
 	unsigned char * base, * space;
 	unsigned size, blks, i;
+	unsigned flags = 0;
 	
 	UFSD(("ENTER\n"))
 	
 	uspi = sbi->s_uspi;
+
+	usb  = (struct ufs_super_block *)
+		((struct ufs_buffer_head *)uspi)->bh[0]->b_data;
+
+        flags = UFS_SB(sb)->s_flags;
 	
 	/*
 	 * Read cs structures from (usually) first data block
@@ -377,11 +415,22 @@ int ufs_read_cylinder_structures (struct
 		size = uspi->s_bsize;
 		if (i + uspi->s_fpb > blks)
 			size = (blks - i) * uspi->s_fsize;
-		ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
-		if (!ubh)
-			goto failed;
-		ubh_ubhcpymem (space, ubh, size);
-		sbi->s_csp[ufs_fragstoblks(i)] = (struct ufs_csum *)space;
+
+		if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+			ubh = ubh_bread(sb,
+				fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_csaddr) + i, size);
+			if (!ubh)
+				goto failed;
+			ubh_ubhcpymem (space, ubh, size);
+			sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
+		}
+		else {
+			ubh = ubh_bread(sb, uspi->s_csaddr + i, size);
+			if (!ubh)
+				goto failed;
+			ubh_ubhcpymem(space, ubh, size);
+			sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
+		}
 		space += size;
 		ubh_brelse (ubh);
 		ubh = NULL;
@@ -480,6 +529,7 @@ static int ufs_fill_super(struct super_b
 	struct ufs_super_block_first * usb1;
 	struct ufs_super_block_second * usb2;
 	struct ufs_super_block_third * usb3;
+	struct ufs_super_block *usb;
 	struct ufs_buffer_head * ubh;	
 	struct inode *inode;
 	unsigned block_size, super_block_size;
@@ -520,7 +570,7 @@ static int ufs_fill_super(struct super_b
 		if (!silent)
 			printk("You didn't specify the type of your ufs filesystem\n\n"
 			"mount -t ufs -o ufstype="
-			"sun|sunx86|44bsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n"
+			"sun|sunx86|44bsd|ufs2|5xbsd|old|hp|nextstep|netxstep-cd|openstep ...\n\n"
 			">>>WARNING<<< Wrong ufstype may corrupt your filesystem, "
 			"default is ufstype=old\n");
 		ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD);
@@ -545,6 +595,19 @@ static int ufs_fill_super(struct super_b
 		uspi->s_sbbase = 0;
 		flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
 		break;
+	case UFS_MOUNT_UFSTYPE_UFS2:
+		UFSD(("ufstype=ufs2\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_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD;
+		if (!(sb->s_flags & MS_RDONLY)) {
+			printk(KERN_INFO "ufstype=ufs2 is supported read-only\n");
+			sb->s_flags |= MS_RDONLY;
+ 		}
+		break;
 		
 	case UFS_MOUNT_UFSTYPE_SUN:
 		UFSD(("ufstype=sun\n"))
@@ -657,27 +720,37 @@ again:	
 	/*
 	 * read ufs super block from device
 	 */
-	ubh = ubh_bread_uspi (uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + SBLOCK_UFS2/block_size, super_block_size);
+	}
+	else {
+		ubh = ubh_bread_uspi(uspi, sb, uspi->s_sbbase + UFS_SBLOCK/block_size, super_block_size);
+	}
 	if (!ubh) 
-		goto failed;
+            goto failed;
+
 	
 	usb1 = ubh_get_usb_first(USPI_UBH);
 	usb2 = ubh_get_usb_second(USPI_UBH);
 	usb3 = ubh_get_usb_third(USPI_UBH);
+	usb  = (struct ufs_super_block *)
+		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 
 	/*
 	 * Check ufs magic number
 	 */
-	switch (__constant_le32_to_cpu(usb3->fs_magic)) {
+	switch ((uspi->fs_magic = __constant_le32_to_cpu(usb3->fs_magic))) {
 		case UFS_MAGIC:
+		case UFS2_MAGIC:
 		case UFS_MAGIC_LFN:
 	        case UFS_MAGIC_FEA:
 	        case UFS_MAGIC_4GB:
 			sbi->s_bytesex = BYTESEX_LE;
 			goto magic_found;
 	}
-	switch (__constant_be32_to_cpu(usb3->fs_magic)) {
+	switch ((uspi->fs_magic = __constant_be32_to_cpu(usb3->fs_magic))) {
 		case UFS_MAGIC:
+		case UFS2_MAGIC:
 		case UFS_MAGIC_LFN:
 	        case UFS_MAGIC_FEA:
 	        case UFS_MAGIC_4GB:
@@ -748,7 +821,10 @@ magic_found:
 	}
 
 #ifdef UFS_SUPER_DEBUG_MORE
-	ufs_print_super_stuff(sb, usb1, usb2, usb3);
+        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
+		ufs2_print_super_stuff(sb,usb);
+        else
+		ufs_print_super_stuff(sb, usb1, usb2, usb3);
 #endif
 
 	/*
@@ -802,8 +878,16 @@ magic_found:
 	uspi->s_dblkno = fs32_to_cpu(sb, usb1->fs_dblkno);
 	uspi->s_cgoffset = fs32_to_cpu(sb, usb1->fs_cgoffset);
 	uspi->s_cgmask = fs32_to_cpu(sb, usb1->fs_cgmask);
-	uspi->s_size = fs32_to_cpu(sb, usb1->fs_size);
-	uspi->s_dsize = fs32_to_cpu(sb, usb1->fs_dsize);
+
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		uspi->s_u2_size  = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_size);
+		uspi->s_u2_dsize = fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_dsize);
+	}
+	else {
+		uspi->s_size  =  fs32_to_cpu(sb, usb1->fs_size);
+		uspi->s_dsize =  fs32_to_cpu(sb, usb1->fs_dsize);
+	}
+
 	uspi->s_ncg = fs32_to_cpu(sb, usb1->fs_ncg);
 	/* s_bsize already set */
 	/* s_fsize already set */
@@ -1021,21 +1105,36 @@ int ufs_statfs (struct super_block * sb,
 {
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
+	struct ufs_super_block * usb;
+	unsigned  flags = 0;
 
 	lock_kernel();
 
 	uspi = UFS_SB(sb)->s_uspi;
 	usb1 = ubh_get_usb_first (USPI_UBH);
+	usb  = (struct ufs_super_block *)
+		((struct ufs_buffer_head *)uspi)->bh[0]->b_data ;
 	
-	buf->f_type = UFS_MAGIC;
+	flags = UFS_SB(sb)->s_flags;
+	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
+		buf->f_type = UFS2_MAGIC;
+		buf->f_blocks = usb->fs_u11.fs_u2.fs_dsize;
+		buf->f_bfree = ufs_blkstofrags(fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nbfree)) +
+			fs64_to_cpu(sb, usb->fs_u11.fs_u2.fs_cstotal.cs_nffree);
+		buf->f_ffree = fs64_to_cpu(sb,
+        		usb->fs_u11.fs_u2.fs_cstotal.cs_nifree);
+	}
+	else {
+		buf->f_type = UFS_MAGIC;
+		buf->f_blocks = uspi->s_dsize;
+		buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
+			fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
+		buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
+	}
 	buf->f_bsize = sb->s_blocksize;
-	buf->f_blocks = uspi->s_dsize;
-	buf->f_bfree = ufs_blkstofrags(fs32_to_cpu(sb, usb1->fs_cstotal.cs_nbfree)) +
-		fs32_to_cpu(sb, usb1->fs_cstotal.cs_nffree);
 	buf->f_bavail = (buf->f_bfree > (((long)buf->f_blocks / 100) * uspi->s_minfree))
 		? (buf->f_bfree - (((long)buf->f_blocks / 100) * uspi->s_minfree)) : 0;
 	buf->f_files = uspi->s_ncg * uspi->s_ipg;
-	buf->f_ffree = fs32_to_cpu(sb, usb1->fs_cstotal.cs_nifree);
 	buf->f_namelen = UFS_MAXNAMLEN;
 
 	unlock_kernel();
diff -puN fs/ufs/util.c~ufs2-01 fs/ufs/util.c
--- 25/fs/ufs/util.c~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/fs/ufs/util.c	2004-02-23 00:32:57.000000000 -0800
@@ -24,10 +24,11 @@
 
 
 struct ufs_buffer_head * _ubh_bread_ (struct ufs_sb_private_info * uspi,
-	struct super_block *sb, unsigned fragment, unsigned size)
+	struct super_block *sb, u64 fragment, u64 size)
 {
 	struct ufs_buffer_head * ubh;
-	unsigned i, j, count;
+	unsigned i, j ;
+	u64  count = 0;
 	if (size & ~uspi->s_fmask)
 		return NULL;
 	count = size >> uspi->s_fshift;
@@ -53,9 +54,10 @@ failed:
 }
 
 struct ufs_buffer_head * ubh_bread_uspi (struct ufs_sb_private_info * uspi,
-	struct super_block *sb, unsigned fragment, unsigned size)
+	struct super_block *sb, u64 fragment, u64 size)
 {
-	unsigned i, j, count;
+	unsigned i, j;
+	u64 count = 0;
 	if (size & ~uspi->s_fmask)
 		return NULL;
 	count = size >> uspi->s_fshift;
diff -puN fs/ufs/util.h~ufs2-01 fs/ufs/util.h
--- 25/fs/ufs/util.h~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/fs/ufs/util.h	2004-02-23 00:32:57.000000000 -0800
@@ -228,8 +228,8 @@ ufs_set_inode_gid(struct super_block *sb
  * These functions manipulate ufs buffers
  */
 #define ubh_bread(sb,fragment,size) _ubh_bread_(uspi,sb,fragment,size)  
-extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned);
-extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, unsigned, unsigned);
+extern struct ufs_buffer_head * _ubh_bread_(struct ufs_sb_private_info *, struct super_block *, u64 , u64);
+extern struct ufs_buffer_head * ubh_bread_uspi(struct ufs_sb_private_info *, struct super_block *, u64, u64);
 extern void ubh_brelse (struct ufs_buffer_head *);
 extern void ubh_brelse_uspi (struct ufs_sb_private_info *);
 extern void ubh_mark_buffer_dirty (struct ufs_buffer_head *);
diff -puN include/linux/ufs_fs.h~ufs2-01 include/linux/ufs_fs.h
--- 25/include/linux/ufs_fs.h~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/include/linux/ufs_fs.h	2004-02-23 00:32:57.000000000 -0800
@@ -22,6 +22,9 @@
  * HP/UX hfs filesystem support added by
  * Martin K. Petersen <mkp@mkp.net>, August 1999
  *
+ * UFS2 (of FreeBSD 5.x) support added by
+ * Niraj Kumar <niraj17@iitbombay.org>  , Jan 2004
+ *
  */
 
 #ifndef __LINUX_UFS_FS_H
@@ -43,8 +46,50 @@
 
 #define UFS_SECTOR_SIZE 512
 #define UFS_SECTOR_BITS 9
-#define UFS_MAGIC 0x00011954
-#define UFS_CIGAM 0x54190100 /* byteswapped MAGIC */
+#define UFS_MAGIC  0x00011954
+#define UFS2_MAGIC 0x19540119
+#define UFS_CIGAM  0x54190100 /* byteswapped MAGIC */
+
+/* Copied from FreeBSD */
+/*
+ * Each disk drive contains some number of filesystems.
+ * A filesystem consists of a number of cylinder groups.
+ * Each cylinder group has inodes and data.
+ *
+ * A filesystem is described by its super-block, which in turn
+ * describes the cylinder groups.  The super-block is critical
+ * data and is replicated in each cylinder group to protect against
+ * catastrophic loss.  This is done at `newfs' time and the critical
+ * super-block data does not change, so the copies need not be
+ * referenced further unless disaster strikes.
+ *
+ * For filesystem fs, the offsets of the various blocks of interest
+ * are given in the super block as:
+ *      [fs->fs_sblkno]         Super-block
+ *      [fs->fs_cblkno]         Cylinder group block
+ *      [fs->fs_iblkno]         Inode blocks
+ *      [fs->fs_dblkno]         Data blocks
+ * The beginning of cylinder group cg in fs, is given by
+ * the ``cgbase(fs, cg)'' macro.
+ *
+ * Depending on the architecture and the media, the superblock may
+ * reside in any one of four places. For tiny media where every block
+ * counts, it is placed at the very front of the partition. Historically,
+ * UFS1 placed it 8K from the front to leave room for the disk label and
+ * a small bootstrap. For UFS2 it got moved to 64K from the front to leave
+ * room for the disk label and a bigger bootstrap, and for really piggy
+ * systems we check at 256K from the front if the first three fail. In
+ * all cases the size of the superblock will be SBLOCKSIZE. All values are
+ * given in byte-offset form, so they do not imply a sector size. The
+ * SBLOCKSEARCH specifies the order in which the locations should be searched.
+ */
+#define SBLOCK_FLOPPY        0
+#define SBLOCK_UFS1       8192
+#define SBLOCK_UFS2      65536
+#define SBLOCK_PIGGY    262144
+#define SBLOCKSIZE        8192
+#define SBLOCKSEARCH \
+        { SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
 
 
 /* HP specific MAGIC values */
@@ -120,6 +165,11 @@
 #define UFS_CG_OLD		0x00000000
 #define UFS_CG_44BSD		0x00002000
 #define UFS_CG_SUN		0x00001000
+/* filesystem type encoding */
+#define UFS_TYPE_MASK		0x00010000	/* mask for the following */
+#define UFS_TYPE_UFS1		0x00000000
+#define UFS_TYPE_UFS2		0x00010000
+
 
 /* fs_inodefmt options */
 #define UFS_42INODEFMT	-1
@@ -132,7 +182,7 @@
 #define UFS_MOUNT_ONERROR_UMOUNT	0x00000004
 #define UFS_MOUNT_ONERROR_REPAIR	0x00000008
 
-#define UFS_MOUNT_UFSTYPE		0x00000FF0
+#define UFS_MOUNT_UFSTYPE		0x0000FFF0
 #define UFS_MOUNT_UFSTYPE_OLD		0x00000010
 #define UFS_MOUNT_UFSTYPE_44BSD		0x00000020
 #define UFS_MOUNT_UFSTYPE_SUN		0x00000040
@@ -141,6 +191,7 @@
 #define UFS_MOUNT_UFSTYPE_OPENSTEP	0x00000200
 #define UFS_MOUNT_UFSTYPE_SUNx86	0x00000400
 #define UFS_MOUNT_UFSTYPE_HP	        0x00000800
+#define UFS_MOUNT_UFSTYPE_UFS2		0x00001000
 
 #define ufs_clear_opt(o,opt)	o &= ~UFS_MOUNT_##opt
 #define ufs_set_opt(o,opt)	o |= UFS_MOUNT_##opt
@@ -173,7 +224,8 @@
  * They calc file system addresses of cylinder group data structures.
  */
 #define	ufs_cgbase(c)	(uspi->s_fpg * (c))
-#define ufs_cgstart(c)	(ufs_cgbase(c)  + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask))
+#define ufs_cgstart(c)	((uspi)->fs_magic == UFS2_MAGIC ?  ufs_cgbase(c) : \
+	(ufs_cgbase(c)  + uspi->s_cgoffset * ((c) & ~uspi->s_cgmask)))
 #define	ufs_cgsblock(c)	(ufs_cgstart(c) + uspi->s_sblkno)	/* super blk */
 #define	ufs_cgcmin(c)	(ufs_cgstart(c) + uspi->s_cblkno)	/* cg block */
 #define	ufs_cgimin(c)	(ufs_cgstart(c) + uspi->s_iblkno)	/* inode blk */
@@ -227,8 +279,14 @@
 
 #define	UFS_MAXNAMLEN 255
 #define UFS_MAXMNTLEN 512
+#define UFS2_MAXMNTLEN 468
+#define UFS2_MAXVOLLEN 32
 /* #define UFS_MAXCSBUFS 31 */
 #define UFS_LINK_MAX 32000
+/*
+#define	UFS2_NOCSPTRS	((128 / sizeof(void *)) - 4)
+*/
+#define	UFS2_NOCSPTRS	28
 
 /*
  * UFS_DIR_PAD defines the directory entries boundaries
@@ -262,6 +320,14 @@ struct ufs_csum {
 	__u32	cs_nifree;	/* number of free inodes */
 	__u32	cs_nffree;	/* number of free frags */
 };
+struct ufs2_csum_total {
+	__u64	cs_ndir;	/* number of directories */
+	__u64	cs_nbfree;	/* number of free blocks */
+	__u64	cs_nifree;	/* number of free inodes */
+	__u64	cs_nffree;	/* number of free frags */
+	__u64   cs_numclusters;	/* number of free clusters */
+	__u64   cs_spare[3];	/* future expansion */
+};
 
 /*
  * This is the actual superblock, as it is laid out on the disk.
@@ -333,7 +399,7 @@ struct ufs_super_block {
 	__u32	fs_ncyl;	/* cylinders in file system */
 /* these fields can be computed from the others */
 	__u32	fs_cpg;		/* cylinders per group */
-	__u32	fs_ipg;		/* inodes per group */
+	__u32	fs_ipg;		/* inodes per cylinder group */
 	__u32	fs_fpg;		/* blocks per group * fs_frag */
 /* this data must be re-computed after crashes */
 	struct ufs_csum fs_cstotal;	/* cylinder summary information */
@@ -342,13 +408,39 @@ struct ufs_super_block {
 	__s8	fs_clean;	/* file system is clean flag */
 	__s8	fs_ronly;	/* mounted read-only flag */
 	__s8	fs_flags;	/* currently unused flag */
-	__s8	fs_fsmnt[UFS_MAXMNTLEN];	/* name mounted on */
-/* these fields retain the current block allocation info */
-	__u32	fs_cgrotor;	/* last cg searched */
-	__u32	fs_csp[UFS_MAXCSBUFS];	/* list of fs_cs info buffers */
-	__u32	fs_maxcluster;
-	__u32	fs_cpc;		/* cyl per cycle in postbl */
-	__u16	fs_opostbl[16][8];	/* old rotation block list head */	
+	union {
+		struct {
+			__s8	fs_fsmnt[UFS_MAXMNTLEN];/* name mounted on */
+			__u32	fs_cgrotor;	/* last cg searched */
+			__u32	fs_csp[UFS_MAXCSBUFS];/*list of fs_cs info buffers */
+			__u32	fs_maxcluster;
+			__u32	fs_cpc;		/* cyl per cycle in postbl */
+			__u16	fs_opostbl[16][8]; /* old rotation block list head */
+		} fs_u1;
+		struct {
+			__s8  fs_fsmnt[UFS2_MAXMNTLEN];	/* name mounted on */
+			__u8   fs_volname[UFS2_MAXVOLLEN]; /* volume name */
+			__u64  fs_swuid;		/* system-wide uid */
+			__s32  fs_pad;	/* due to alignment of fs_swuid */
+			__u32   fs_cgrotor;     /* last cg searched */
+			__u32   fs_ocsp[UFS2_NOCSPTRS]; /*list of fs_cs info buffers */
+			__u32   fs_contigdirs;/*# of contiguously allocated dirs */
+			__u32   fs_csp;	/* cg summary info buffer for fs_cs */
+			__u32   fs_maxcluster;
+			__u32   fs_active;/* used by snapshots to track fs */
+			__s32   fs_old_cpc;	/* cyl per cycle in postbl */
+			__s32   fs_maxbsize;/*maximum blocking factor permitted */
+			__s64   fs_sparecon64[17];/*old rotation block list head */
+			__s64   fs_sblockloc; /* byte offset of standard superblock */
+			struct  ufs2_csum_total fs_cstotal;/*cylinder summary information*/
+			struct  ufs_timeval    fs_time;		/* last time written */
+			__s64    fs_size;		/* number of blocks in fs */
+			__s64    fs_dsize;	/* number of data blocks in fs */
+			__u64    fs_csaddr;	/* blk addr of cyl grp summary area */
+			__s64    fs_pendingblocks;/* blocks in process of being freed */
+			__s32    fs_pendinginodes;/*inodes in process of being freed */
+		} fs_u2;
+	}  fs_u11;
 	union {
 		struct {
 			__s32	fs_sparecon[53];/* reserved for future constants */
@@ -441,6 +533,16 @@ struct	ufs_cylinder_group {
 			__u32	cg_nclusterblks;	/* number of clusters this cg */
 			__u32	cg_sparecon[13];	/* reserved for future use */
 		} cg_44;
+		struct {
+			__u32	cg_clustersumoff;/* (u_int32) counts of avail clusters */
+			__u32	cg_clusteroff;	/* (u_int8) free cluster map */
+			__u32	cg_nclusterblks;/* number of clusters this cg */
+			__u32   cg_niblk; /* number of inode blocks this cg */
+			__u32   cg_initediblk;	/* last initialized inode */
+			__u32   cg_sparecon32[3];/* reserved for future use */
+			__u64   cg_time;	/* time last written */
+			__u64	cg_sparecon[3];	/* reserved for future use */
+		} cg_u2;
 		__u32	cg_sparecon[16];	/* reserved for future use */
 	} cg_u;
 	__u8	cg_space[1];		/* space for cylinder group maps */
@@ -497,6 +599,39 @@ struct ufs_inode {
 	} ui_u3;
 };
 
+#define UFS_NXADDR  2            /* External addresses in inode. */
+struct ufs2_inode {
+	__u16     ui_mode;        /*   0: IFMT, permissions; see below. */
+	__s16     ui_nlink;       /*   2: File link count. */
+	__u32     ui_uid;         /*   4: File owner. */
+	__u32     ui_gid;         /*   8: File group. */
+	__u32     ui_blksize;     /*  12: Inode blocksize. */
+	__u64     ui_size;        /*  16: File byte count. */
+	__u64     ui_blocks;      /*  24: Bytes actually held. */
+	struct ufs_timeval   ui_atime;       /*  32: Last access time. */
+	struct ufs_timeval   ui_mtime;       /*  40: Last modified time. */
+	struct ufs_timeval   ui_ctime;       /*  48: Last inode change time. */
+	struct ufs_timeval   ui_birthtime;   /*  56: Inode creation time. */
+	__s32     ui_mtimensec;   /*  64: Last modified time. */
+	__s32     ui_atimensec;   /*  68: Last access time. */
+	__s32     ui_ctimensec;   /*  72: Last inode change time. */
+	__s32     ui_birthnsec;   /*  76: Inode creation time. */
+	__s32     ui_gen;         /*  80: Generation number. */
+	__u32     ui_kernflags;   /*  84: Kernel flags. */
+	__u32     ui_flags;       /*  88: Status flags (chflags). */
+	__s32     ui_extsize;     /*  92: External attributes block. */
+	__s64     ui_extb[UFS_NXADDR];/*  96: External attributes block. */
+	union {
+		struct {
+			__s64     ui_db[UFS_NDADDR]; /* 112: Direct disk blocks. */
+			__s64     ui_ib[UFS_NINDIR];/* 208: Indirect disk blocks.*/
+		} ui_addr;
+	__u8	ui_symlink[2*4*(UFS_NDADDR+UFS_NINDIR)];/* 0x28 fast symlink */
+	} ui_u2;
+	__s64     ui_spare[3];    /* 232: Reserved; currently unused */
+};
+
+
 /* FreeBSD has these in sys/stat.h */
 /* ui_flags that can be set by a file owner */
 #define UFS_UF_SETTABLE   0x0000ffff
@@ -517,8 +652,8 @@ struct ufs_inode {
  * than the size of fragment.
  */
 struct ufs_buffer_head {
-	unsigned fragment;			/* first fragment */
-	unsigned count;				/* number of fragments */
+	__u64 fragment;			/* first fragment */
+	__u64 count;				/* number of fragments */
 	struct buffer_head * bh[UFS_MAXFRAG];	/* buffers */
 };
 
@@ -551,6 +686,8 @@ struct ufs_sb_private_info {
 	__u32	s_cgmask;	/* used to calc mod fs_ntrak */
 	__u32	s_size;		/* number of blocks (fragments) in fs */
 	__u32	s_dsize;	/* number of data blocks in fs */
+	__u64	s_u2_size;	/* ufs2: number of blocks (fragments) in fs */
+	__u64	s_u2_dsize;	/*ufs2:  number of data blocks in fs */
 	__u32	s_ncg;		/* number of cylinder groups */
 	__u32	s_bsize;	/* size of basic blocks */
 	__u32	s_fsize;	/* size of fragments */
@@ -577,7 +714,7 @@ struct ufs_sb_private_info {
 	__u32	s_ntrak;	/* tracks per cylinder */
 	__u32	s_nsect;	/* sectors per track */
 	__u32	s_spc;		/* sectors per cylinder */
-	__u32	s_ipg;		/* inodes per group */
+	__u32	s_ipg;		/* inodes per cylinder group */
 	__u32	s_fpg;		/* fragments per group */
 	__u32	s_cpc;		/* cyl per cycle in postbl */
 	__s32	s_contigsumsize;/* size of cluster summary array, 44bsd */
@@ -605,6 +742,7 @@ struct ufs_sb_private_info {
 	__u32	s_bpfmask;	/* bits per fragment mask */
 
 	__u32	s_maxsymlinklen;/* upper limit on fast symlinks' size */
+	__s32	fs_magic;       /* filesystem magic */
 };
 
 /*
@@ -758,7 +896,7 @@ extern void ufs_free_inode (struct inode
 extern struct inode * ufs_new_inode (struct inode *, int);
 
 /* inode.c */
-extern int ufs_frag_map (struct inode *, int);
+extern u64  ufs_frag_map (struct inode *, int);
 extern void ufs_read_inode (struct inode *);
 extern void ufs_put_inode (struct inode *);
 extern void ufs_write_inode (struct inode *, int);
diff -puN include/linux/ufs_fs_i.h~ufs2-01 include/linux/ufs_fs_i.h
--- 25/include/linux/ufs_fs_i.h~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/include/linux/ufs_fs_i.h	2004-02-23 00:32:57.000000000 -0800
@@ -17,6 +17,7 @@ struct ufs_inode_info {
 	union {
 		__u32	i_data[15];
 		__u8	i_symlink[4*15];
+		__u64	u2_i_data[15];
 	} i_u1;
 	__u32	i_flags;
 	__u32	i_gen;
diff -puN Documentation/filesystems/ufs.txt~ufs2-01 Documentation/filesystems/ufs.txt
--- 25/Documentation/filesystems/ufs.txt~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/Documentation/filesystems/ufs.txt	2004-02-23 00:32:57.000000000 -0800
@@ -20,6 +20,9 @@ ufstype=type_of_ufs
 	44bsd	used in FreeBSD, NetBSD, OpenBSD
 		supported os read-write
 
+       ufs2    used in FreeBSD 5.x
+               supported os read-only
+
 	sun	used in SunOS (Solaris)
 		supported as read-write
 
diff -puN fs/Kconfig~ufs2-01 fs/Kconfig
--- 25/fs/Kconfig~ufs2-01	2004-02-23 00:32:57.000000000 -0800
+++ 25-akpm/fs/Kconfig	2004-02-23 00:32:57.000000000 -0800
@@ -1251,6 +1251,9 @@ config UFS_FS
 	  experimental "UFS file system write support", below. Please read the
 	  file <file:Documentation/filesystems/ufs.txt> for more information.
 
+          The recently released UFS2 variant (used in FreeBSD 5.x) is
+          READ-ONLY supported.
+
 	  If you only intend to mount files from some other Unix over the
 	  network using NFS, you don't need the UFS file system support (but
 	  you need NFS file system support obviously).

_