freevxfs: handle big endian HP-UX file systems

To support VxFS filesystems from HP-UX on x86 systems we need to
implement byte swapping, and to keep support for Unixware filesystems
it needs to be the complicated dual-endian kind ala sysvfs.

To do this properly we have to split the on disk and in-core inode
so that we can keep the in-core one in native endianness.  All other
structures are byteswapped on demand.

Signed-off-by: Krzysztof Błaszkowski <kb@sysmikro.com.pl>
[hch: make spare happy]
Signed-off-by: Christoph Hellwig <hch@lst.de>
diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
index c8a9265..4b561de 100644
--- a/fs/freevxfs/vxfs.h
+++ b/fs/freevxfs/vxfs.h
@@ -38,13 +38,6 @@
  */
 #include <linux/types.h>
 
-
-/*
- * Data types for use with the VxFS ondisk format.
- */
-typedef	int32_t		vx_daddr_t;
-typedef int32_t		vx_ino_t;
-
 /*
  * Superblock magic number (vxfs_super->vs_magic).
  */
@@ -60,6 +53,14 @@
  */
 #define VXFS_NEFREE		32
 
+enum vxfs_byte_order {
+	VXFS_BO_LE,
+	VXFS_BO_BE,
+};
+
+typedef __u16 __bitwise __fs16;
+typedef __u32 __bitwise __fs32;
+typedef __u64 __bitwise __fs64;
 
 /*
  * VxFS superblock (disk).
@@ -71,83 +72,83 @@
 	 * Lots of this fields are no more used by version 2
 	 * and never filesystems.
 	 */
-	u_int32_t	vs_magic;		/* Magic number */
-	int32_t		vs_version;		/* VxFS version */
-	u_int32_t	vs_ctime;		/* create time - secs */
-	u_int32_t	vs_cutime;		/* create time - usecs */
-	int32_t		__unused1;		/* unused */
-	int32_t		__unused2;		/* unused */
-	vx_daddr_t	vs_old_logstart;	/* obsolete */
-	vx_daddr_t	vs_old_logend;		/* obsolete */
-	int32_t		vs_bsize;		/* block size */
-	int32_t		vs_size;		/* number of blocks */
-	int32_t		vs_dsize;		/* number of data blocks */
-	u_int32_t	vs_old_ninode;		/* obsolete */
-	int32_t		vs_old_nau;		/* obsolete */
-	int32_t		__unused3;		/* unused */
-	int32_t		vs_old_defiextsize;	/* obsolete */
-	int32_t		vs_old_ilbsize;		/* obsolete */
-	int32_t		vs_immedlen;		/* size of immediate data area */
-	int32_t		vs_ndaddr;		/* number of direct extentes */
-	vx_daddr_t	vs_firstau;		/* address of first AU */
-	vx_daddr_t	vs_emap;		/* offset of extent map in AU */
-	vx_daddr_t	vs_imap;		/* offset of inode map in AU */
-	vx_daddr_t	vs_iextop;		/* offset of ExtOp. map in AU */
-	vx_daddr_t	vs_istart;		/* offset of inode list in AU */
-	vx_daddr_t	vs_bstart;		/* offset of fdblock in AU */
-	vx_daddr_t	vs_femap;		/* aufirst + emap */
-	vx_daddr_t	vs_fimap;		/* aufirst + imap */
-	vx_daddr_t	vs_fiextop;		/* aufirst + iextop */
-	vx_daddr_t	vs_fistart;		/* aufirst + istart */
-	vx_daddr_t	vs_fbstart;		/* aufirst + bstart */
-	int32_t		vs_nindir;		/* number of entries in indir */
-	int32_t		vs_aulen;		/* length of AU in blocks */
-	int32_t		vs_auimlen;		/* length of imap in blocks */
-	int32_t		vs_auemlen;		/* length of emap in blocks */
-	int32_t		vs_auilen;		/* length of ilist in blocks */
-	int32_t		vs_aupad;		/* length of pad in blocks */
-	int32_t		vs_aublocks;		/* data blocks in AU */
-	int32_t		vs_maxtier;		/* log base 2 of aublocks */
-	int32_t		vs_inopb;		/* number of inodes per blk */
-	int32_t		vs_old_inopau;		/* obsolete */
-	int32_t		vs_old_inopilb;		/* obsolete */
-	int32_t		vs_old_ndiripau;	/* obsolete */
-	int32_t		vs_iaddrlen;		/* size of indirect addr ext. */
-	int32_t		vs_bshift;		/* log base 2 of bsize */
-	int32_t		vs_inoshift;		/* log base 2 of inobp */
-	int32_t		vs_bmask;		/* ~( bsize - 1 ) */
-	int32_t		vs_boffmask;		/* bsize - 1 */
-	int32_t		vs_old_inomask;		/* old_inopilb - 1 */
-	int32_t		vs_checksum;		/* checksum of V1 data */
+	__fs32		vs_magic;		/* Magic number */
+	__fs32		vs_version;		/* VxFS version */
+	__fs32		vs_ctime;		/* create time - secs */
+	__fs32		vs_cutime;		/* create time - usecs */
+	__fs32		__unused1;		/* unused */
+	__fs32		__unused2;		/* unused */
+	__fs32		vs_old_logstart;	/* obsolete */
+	__fs32		vs_old_logend;		/* obsolete */
+	__fs32		vs_bsize;		/* block size */
+	__fs32		vs_size;		/* number of blocks */
+	__fs32		vs_dsize;		/* number of data blocks */
+	__fs32		vs_old_ninode;		/* obsolete */
+	__fs32		vs_old_nau;		/* obsolete */
+	__fs32		__unused3;		/* unused */
+	__fs32		vs_old_defiextsize;	/* obsolete */
+	__fs32		vs_old_ilbsize;		/* obsolete */
+	__fs32		vs_immedlen;		/* size of immediate data area */
+	__fs32		vs_ndaddr;		/* number of direct extentes */
+	__fs32		vs_firstau;		/* address of first AU */
+	__fs32		vs_emap;		/* offset of extent map in AU */
+	__fs32		vs_imap;		/* offset of inode map in AU */
+	__fs32		vs_iextop;		/* offset of ExtOp. map in AU */
+	__fs32		vs_istart;		/* offset of inode list in AU */
+	__fs32		vs_bstart;		/* offset of fdblock in AU */
+	__fs32		vs_femap;		/* aufirst + emap */
+	__fs32		vs_fimap;		/* aufirst + imap */
+	__fs32		vs_fiextop;		/* aufirst + iextop */
+	__fs32		vs_fistart;		/* aufirst + istart */
+	__fs32		vs_fbstart;		/* aufirst + bstart */
+	__fs32		vs_nindir;		/* number of entries in indir */
+	__fs32		vs_aulen;		/* length of AU in blocks */
+	__fs32		vs_auimlen;		/* length of imap in blocks */
+	__fs32		vs_auemlen;		/* length of emap in blocks */
+	__fs32		vs_auilen;		/* length of ilist in blocks */
+	__fs32		vs_aupad;		/* length of pad in blocks */
+	__fs32		vs_aublocks;		/* data blocks in AU */
+	__fs32		vs_maxtier;		/* log base 2 of aublocks */
+	__fs32		vs_inopb;		/* number of inodes per blk */
+	__fs32		vs_old_inopau;		/* obsolete */
+	__fs32		vs_old_inopilb;		/* obsolete */
+	__fs32		vs_old_ndiripau;	/* obsolete */
+	__fs32		vs_iaddrlen;		/* size of indirect addr ext. */
+	__fs32		vs_bshift;		/* log base 2 of bsize */
+	__fs32		vs_inoshift;		/* log base 2 of inobp */
+	__fs32		vs_bmask;		/* ~( bsize - 1 ) */
+	__fs32		vs_boffmask;		/* bsize - 1 */
+	__fs32		vs_old_inomask;		/* old_inopilb - 1 */
+	__fs32		vs_checksum;		/* checksum of V1 data */
 	
 	/*
 	 * Version 1, writable
 	 */
-	int32_t		vs_free;		/* number of free blocks */
-	int32_t		vs_ifree;		/* number of free inodes */
-	int32_t		vs_efree[VXFS_NEFREE];	/* number of free extents by size */
-	int32_t		vs_flags;		/* flags ?!? */
-	u_int8_t	vs_mod;			/* filesystem has been changed */
-	u_int8_t	vs_clean;		/* clean FS */
-	u_int16_t	__unused4;		/* unused */
-	u_int32_t	vs_firstlogid;		/* mount time log ID */
-	u_int32_t	vs_wtime;		/* last time written - sec */
-	u_int32_t	vs_wutime;		/* last time written - usec */
-	u_int8_t	vs_fname[6];		/* FS name */
-	u_int8_t	vs_fpack[6];		/* FS pack name */
-	int32_t		vs_logversion;		/* log format version */
-	int32_t		__unused5;		/* unused */
+	__fs32		vs_free;		/* number of free blocks */
+	__fs32		vs_ifree;		/* number of free inodes */
+	__fs32		vs_efree[VXFS_NEFREE];	/* number of free extents by size */
+	__fs32		vs_flags;		/* flags ?!? */
+	__u8		vs_mod;			/* filesystem has been changed */
+	__u8		vs_clean;		/* clean FS */
+	__fs16		__unused4;		/* unused */
+	__fs32		vs_firstlogid;		/* mount time log ID */
+	__fs32		vs_wtime;		/* last time written - sec */
+	__fs32		vs_wutime;		/* last time written - usec */
+	__u8		vs_fname[6];		/* FS name */
+	__u8		vs_fpack[6];		/* FS pack name */
+	__fs32		vs_logversion;		/* log format version */
+	__u32		__unused5;		/* unused */
 	
 	/*
 	 * Version 2, Read-only
 	 */
-	vx_daddr_t	vs_oltext[2];		/* OLT extent and replica */
-	int32_t		vs_oltsize;		/* OLT extent size */
-	int32_t		vs_iauimlen;		/* size of inode map */
-	int32_t		vs_iausize;		/* size of IAU in blocks */
-	int32_t		vs_dinosize;		/* size of inode in bytes */
-	int32_t		vs_old_dniaddr;		/* indir levels per inode */
-	int32_t		vs_checksum2;		/* checksum of V2 RO */
+	__fs32		vs_oltext[2];		/* OLT extent and replica */
+	__fs32		vs_oltsize;		/* OLT extent size */
+	__fs32		vs_iauimlen;		/* size of inode map */
+	__fs32		vs_iausize;		/* size of IAU in blocks */
+	__fs32		vs_dinosize;		/* size of inode in bytes */
+	__fs32		vs_old_dniaddr;		/* indir levels per inode */
+	__fs32		vs_checksum2;		/* checksum of V2 RO */
 
 	/*
 	 * Actually much more...
@@ -168,8 +169,32 @@
 	ino_t			vsi_fshino;	/* fileset header inode */
 	daddr_t			vsi_oltext;	/* OLT extent */
 	daddr_t			vsi_oltsize;	/* OLT size */
+	enum vxfs_byte_order	byte_order;
 };
 
+static inline u16 fs16_to_cpu(struct vxfs_sb_info *sbi, __fs16 a)
+{
+	if (sbi->byte_order == VXFS_BO_BE)
+		return be16_to_cpu((__force __be16)a);
+	else
+		return le16_to_cpu((__force __le16)a);
+}
+
+static inline u32 fs32_to_cpu(struct vxfs_sb_info *sbi, __fs32 a)
+{
+	if (sbi->byte_order == VXFS_BO_BE)
+		return be32_to_cpu((__force __be32)a);
+	else
+		return le32_to_cpu((__force __le32)a);
+}
+
+static inline u64 fs64_to_cpu(struct vxfs_sb_info *sbi, __fs64 a)
+{
+	if (sbi->byte_order == VXFS_BO_BE)
+		return be64_to_cpu((__force __be64)a);
+	else
+		return le64_to_cpu((__force __le64)a);
+}
 
 /*
  * File modes.  File types above 0xf000 are vxfs internal only, they should