From 252e211e90ce56bf005cb533ad5a297c18c19407 Mon Sep 17 00:00:00 2001 From: Mark Fortescue Date: Tue, 16 Oct 2007 23:26:31 -0700 Subject: [PATCH] Add in SunOS 4.1.x compatible mode for UFS Add in support for SunOS 4.1.x flavor of BSD 4.2 UFS filing system Macros have been put in to alow suport for the old static table Cylinder Groups but this implementation does not use them yet. This also fixes Solaris UFS filing system access by disabling fast symbolic links as Sun's version of UFS does not support on-disk fast symbolic links. Tested by: Ppartitioning a new disk using SunOS 4.1.1, creating a UFS filing system on one of the partitions and writing some files to the filing system. Using Linux-2.6.22 (patched) to read the files and then write a shed load of files to the UFS partition. Using SunOS 4.1.1 to verify the filing system is OK and to check the files. The test host is a sun4c SS1 Clone. [akpm@linux-foundation.org: coding style fixes] [adobriyan@gmail.com: fix oops] Signed-off-by: Mark Fortescue Cc: Evgeniy Dushistov Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ufs/super.c | 41 ++++++++++++++++++++++++++++++------- fs/ufs/util.h | 50 ++++++++++++++++++++++++++++++++++----------- include/linux/ufs_fs.h | 55 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 123 insertions(+), 23 deletions(-) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index c5bdea7..87f6b51 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -286,7 +286,7 @@ void ufs_warning (struct super_block * sb, const char * function, } enum { - Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_44bsd, + Opt_type_old, Opt_type_sunx86, Opt_type_sun, Opt_type_sunos, Opt_type_44bsd, 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 @@ -296,6 +296,7 @@ static match_table_t tokens = { {Opt_type_old, "ufstype=old"}, {Opt_type_sunx86, "ufstype=sunx86"}, {Opt_type_sun, "ufstype=sun"}, + {Opt_type_sunos, "ufstype=sunos"}, {Opt_type_44bsd, "ufstype=44bsd"}, {Opt_type_ufs2, "ufstype=ufs2"}, {Opt_type_ufs2, "ufstype=5xbsd"}, @@ -339,6 +340,10 @@ static int ufs_parse_options (char * options, unsigned * mount_options) ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_SUN); break; + case Opt_type_sunos: + ufs_clear_opt(*mount_options, UFSTYPE); + ufs_set_opt(*mount_options, UFSTYPE_SUNOS); + break; case Opt_type_44bsd: ufs_clear_opt (*mount_options, UFSTYPE); ufs_set_opt (*mount_options, UFSTYPE_44BSD); @@ -654,8 +659,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) ufs_set_opt (sbi->s_mount_opt, UFSTYPE_OLD); } - sbi->s_uspi = uspi = - kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); + uspi = kzalloc(sizeof(struct ufs_sb_private_info), GFP_KERNEL); + sbi->s_uspi = uspi; if (!uspi) goto failed; uspi->s_dirblksize = UFS_SECTOR_SIZE; @@ -692,10 +697,22 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; - uspi->s_maxsymlinklen = 56; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUN | UFS_CG_SUN; break; + case UFS_MOUNT_UFSTYPE_SUNOS: + UFSD(("ufstype=sunos\n")) + uspi->s_fsize = block_size = 1024; + uspi->s_fmask = ~(1024 - 1); + uspi->s_fshift = 10; + uspi->s_sbsize = 2048; + super_block_size = 2048; + uspi->s_sbbase = 0; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ + flags |= UFS_DE_OLD | UFS_UID_OLD | UFS_ST_SUNOS | UFS_CG_SUN; + break; + case UFS_MOUNT_UFSTYPE_SUNx86: UFSD("ufstype=sunx86\n"); uspi->s_fsize = block_size = 1024; @@ -703,7 +720,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; - uspi->s_maxsymlinklen = 56; + uspi->s_maxsymlinklen = 0; /* Not supported on disk */ flags |= UFS_DE_OLD | UFS_UID_EFT | UFS_ST_SUNx86 | UFS_CG_SUN; break; @@ -805,11 +822,18 @@ again: if (!ubh) goto failed; - usb1 = ubh_get_usb_first(uspi); usb2 = ubh_get_usb_second(uspi); usb3 = ubh_get_usb_third(uspi); + /* Sort out mod used on SunOS 4.1.3 for fs_state */ + uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); + if (((flags & UFS_ST_MASK) == UFS_ST_SUNOS) && + (uspi->s_postblformat != UFS_42POSTBLFMT)) { + flags &= ~UFS_ST_MASK; + flags |= UFS_ST_SUN; + } + /* * Check ufs magic number */ @@ -904,6 +928,7 @@ magic_found: if (((flags & UFS_ST_MASK) == UFS_ST_44BSD) || ((flags & UFS_ST_MASK) == UFS_ST_OLD) || (((flags & UFS_ST_MASK) == UFS_ST_SUN || + (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) && (ufs_get_fs_state(sb, usb1, usb3) == (UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time))))) { switch(usb1->fs_clean) { @@ -995,7 +1020,6 @@ magic_found: uspi->s_contigsumsize = fs32_to_cpu(sb, usb3->fs_un2.fs_44.fs_contigsumsize); uspi->s_qbmask = ufs_get_fs_qbmask(sb, usb3); uspi->s_qfmask = ufs_get_fs_qfmask(sb, usb3); - uspi->s_postblformat = fs32_to_cpu(sb, usb3->fs_postblformat); uspi->s_nrpos = fs32_to_cpu(sb, usb3->fs_nrpos); uspi->s_postbloff = fs32_to_cpu(sb, usb3->fs_postbloff); uspi->s_rotbloff = fs32_to_cpu(sb, usb3->fs_rotbloff); @@ -1077,6 +1101,7 @@ static void ufs_write_super(struct super_block *sb) if (!(sb->s_flags & MS_RDONLY)) { usb1->fs_time = cpu_to_fs32(sb, get_seconds()); if ((flags & UFS_ST_MASK) == UFS_ST_SUN + || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); @@ -1146,6 +1171,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) ufs_put_super_internal(sb); usb1->fs_time = cpu_to_fs32(sb, get_seconds()); if ((flags & UFS_ST_MASK) == UFS_ST_SUN + || (flags & UFS_ST_MASK) == UFS_ST_SUNOS || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) ufs_set_fs_state(sb, usb1, usb3, UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); @@ -1162,6 +1188,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) return -EINVAL; #else if (ufstype != UFS_MOUNT_UFSTYPE_SUN && + ufstype != UFS_MOUNT_UFSTYPE_SUNOS && ufstype != UFS_MOUNT_UFSTYPE_44BSD && ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && ufstype != UFS_MOUNT_UFSTYPE_UFS2) { diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 79a340a..b26fc4d 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -38,6 +38,10 @@ ufs_get_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1, struct ufs_super_block_third *usb3) { switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: + if (fs32_to_cpu(sb, usb3->fs_postblformat) == UFS_42POSTBLFMT) + return fs32_to_cpu(sb, usb1->fs_u0.fs_sun.fs_state); + /* Fall Through to UFS_ST_SUN */ case UFS_ST_SUN: return fs32_to_cpu(sb, usb3->fs_un2.fs_sun.fs_state); case UFS_ST_SUNx86: @@ -53,6 +57,12 @@ ufs_set_fs_state(struct super_block *sb, struct ufs_super_block_first *usb1, struct ufs_super_block_third *usb3, s32 value) { switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: + if (fs32_to_cpu(sb, usb3->fs_postblformat == UFS_42POSTBLFMT)) { + usb1->fs_u0.fs_sun.fs_state = cpu_to_fs32(sb, value); + break; + } + /* Fall Through to UFS_ST_SUN */ case UFS_ST_SUN: usb3->fs_un2.fs_sun.fs_state = cpu_to_fs32(sb, value); break; @@ -81,6 +91,7 @@ ufs_get_fs_qbmask(struct super_block *sb, struct ufs_super_block_third *usb3) __fs64 tmp; switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: case UFS_ST_SUN: ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qbmask[0]; ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qbmask[1]; @@ -104,6 +115,7 @@ ufs_get_fs_qfmask(struct super_block *sb, struct ufs_super_block_third *usb3) __fs64 tmp; switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) { + case UFS_ST_SUNOS: case UFS_ST_SUN: ((__fs32 *)&tmp)[0] = usb3->fs_un2.fs_sun.fs_qfmask[0]; ((__fs32 *)&tmp)[1] = usb3->fs_un2.fs_sun.fs_qfmask[1]; @@ -179,10 +191,12 @@ static inline u32 ufs_get_inode_uid(struct super_block *sb, struct ufs_inode *inode) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_uid); case UFS_UID_44BSD: return fs32_to_cpu(sb, inode->ui_u3.ui_44.ui_uid); + case UFS_UID_EFT: + if (inode->ui_u1.oldids.ui_suid == 0xFFFF) + return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_uid); + /* Fall through */ default: return fs16_to_cpu(sb, inode->ui_u1.oldids.ui_suid); } @@ -192,24 +206,31 @@ static inline void ufs_set_inode_uid(struct super_block *sb, struct ufs_inode *inode, u32 value) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - inode->ui_u3.ui_sun.ui_uid = cpu_to_fs32(sb, value); - break; case UFS_UID_44BSD: inode->ui_u3.ui_44.ui_uid = cpu_to_fs32(sb, value); + inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value); + break; + case UFS_UID_EFT: + inode->ui_u3.ui_sun.ui_uid = cpu_to_fs32(sb, value); + if (value > 0xFFFF) + value = 0xFFFF; + /* Fall through */ + default: + inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value); break; } - inode->ui_u1.oldids.ui_suid = cpu_to_fs16(sb, value); } static inline u32 ufs_get_inode_gid(struct super_block *sb, struct ufs_inode *inode) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid); case UFS_UID_44BSD: return fs32_to_cpu(sb, inode->ui_u3.ui_44.ui_gid); + case UFS_UID_EFT: + if (inode->ui_u1.oldids.ui_suid == 0xFFFF) + return fs32_to_cpu(sb, inode->ui_u3.ui_sun.ui_gid); + /* Fall through */ default: return fs16_to_cpu(sb, inode->ui_u1.oldids.ui_sgid); } @@ -219,14 +240,19 @@ static inline void ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value) { switch (UFS_SB(sb)->s_flags & UFS_UID_MASK) { - case UFS_UID_EFT: - inode->ui_u3.ui_sun.ui_gid = cpu_to_fs32(sb, value); - break; case UFS_UID_44BSD: inode->ui_u3.ui_44.ui_gid = cpu_to_fs32(sb, value); + inode->ui_u1.oldids.ui_sgid = cpu_to_fs16(sb, value); + break; + case UFS_UID_EFT: + inode->ui_u3.ui_sun.ui_gid = cpu_to_fs32(sb, value); + if (value > 0xFFFF) + value = 0xFFFF; + /* Fall through */ + default: + inode->ui_u1.oldids.ui_sgid = cpu_to_fs16(sb, value); break; } - inode->ui_u1.oldids.ui_sgid = cpu_to_fs16(sb, value); } extern dev_t ufs_get_inode_dev(struct super_block *, struct ufs_inode_info *); diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index daeba22..52730d2 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -170,8 +170,9 @@ typedef __u16 __bitwise __fs16; #define UFS_ST_MASK 0x00000700 /* mask for the following */ #define UFS_ST_OLD 0x00000000 #define UFS_ST_44BSD 0x00000100 -#define UFS_ST_SUN 0x00000200 -#define UFS_ST_SUNx86 0x00000400 +#define UFS_ST_SUN 0x00000200 /* Solaris */ +#define UFS_ST_SUNOS 0x00000300 +#define UFS_ST_SUNx86 0x00000400 /* Solaris x86 */ /*cylinder group encoding */ #define UFS_CG_MASK 0x00003000 /* mask for the following */ #define UFS_CG_OLD 0x00000000 @@ -204,6 +205,7 @@ typedef __u16 __bitwise __fs16; #define UFS_MOUNT_UFSTYPE_SUNx86 0x00000400 #define UFS_MOUNT_UFSTYPE_HP 0x00000800 #define UFS_MOUNT_UFSTYPE_UFS2 0x00001000 +#define UFS_MOUNT_UFSTYPE_SUNOS 0x00002000 #define ufs_clear_opt(o,opt) o &= ~UFS_MOUNT_##opt #define ufs_set_opt(o,opt) o |= UFS_MOUNT_##opt @@ -374,7 +376,14 @@ struct ufs_csum_core { * struct ufs_super_block_(first,second,third) instead. */ struct ufs_super_block { - __fs32 fs_link; /* UNUSED */ + union { + struct { + __fs32 fs_link; /* UNUSED */ + } fs_42; + struct { + __fs32 fs_state; /* file system state flag */ + } fs_sun; + } fs_u0; __fs32 fs_rlink; /* UNUSED */ __fs32 fs_sblkno; /* addr of super-block in filesys */ __fs32 fs_cblkno; /* offset of cyl-block in filesys */ @@ -545,6 +554,15 @@ struct ufs_super_block { #define CG_MAGIC 0x090255 #define ufs_cg_chkmagic(sb, ucg) \ (fs32_to_cpu((sb), (ucg)->cg_magic) == CG_MAGIC) +/* + * Macros for access to old cylinder group array structures + */ +#define ufs_ocg_blktot(sb, ucg) fs32_to_cpu((sb), ((struct ufs_old_cylinder_group *)(ucg))->cg_btot) +#define ufs_ocg_blks(sb, ucg, cylno) fs32_to_cpu((sb), ((struct ufs_old_cylinder_group *)(ucg))->cg_b[cylno]) +#define ufs_ocg_inosused(sb, ucg) fs32_to_cpu((sb), ((struct ufs_old_cylinder_group *)(ucg))->cg_iused) +#define ufs_ocg_blksfree(sb, ucg) fs32_to_cpu((sb), ((struct ufs_old_cylinder_group *)(ucg))->cg_free) +#define ufs_ocg_chkmagic(sb, ucg) \ + (fs32_to_cpu((sb), ((struct ufs_old_cylinder_group *)(ucg))->cg_magic) == CG_MAGIC) /* * size of this structure is 172 B @@ -590,6 +608,28 @@ struct ufs_cylinder_group { /* actually longer */ }; +/* Historic Cylinder group info */ +struct ufs_old_cylinder_group { + __fs32 cg_link; /* linked list of cyl groups */ + __fs32 cg_rlink; /* for incore cyl groups */ + __fs32 cg_time; /* time last written */ + __fs32 cg_cgx; /* we are the cgx'th cylinder group */ + __fs16 cg_ncyl; /* number of cyl's this cg */ + __fs16 cg_niblk; /* number of inode blocks this cg */ + __fs32 cg_ndblk; /* number of data blocks this cg */ + struct ufs_csum cg_cs; /* cylinder summary information */ + __fs32 cg_rotor; /* position of last used block */ + __fs32 cg_frotor; /* position of last used frag */ + __fs32 cg_irotor; /* position of last used inode */ + __fs32 cg_frsum[8]; /* counts of available frags */ + __fs32 cg_btot[32]; /* block totals per cylinder */ + __fs16 cg_b[32][8]; /* positions of free blocks */ + __u8 cg_iused[256]; /* used inode map */ + __fs32 cg_magic; /* magic number */ + __u8 cg_free[1]; /* free block map */ +/* actually longer */ +}; + /* * structure of an on-disk inode */ @@ -796,7 +836,14 @@ struct ufs_sb_private_info { * ufs_super_block_third 356 */ struct ufs_super_block_first { - __fs32 fs_link; + union { + struct { + __fs32 fs_link; /* UNUSED */ + } fs_42; + struct { + __fs32 fs_state; /* file system state flag */ + } fs_sun; + } fs_u0; __fs32 fs_rlink; __fs32 fs_sblkno; __fs32 fs_cblkno; -- 2.7.4