From: Niraj Kumar 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 #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 , August 1999 * + * UFS2 (of FreeBSD 5.x) support added by + * Niraj Kumar , 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 , August 1999 * + * UFS2 (of FreeBSD 5.x) support added by + * Niraj Kumar , 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 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). _