Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d83f7fc authored by Krzysztof Błaszkowski's avatar Krzysztof Błaszkowski Committed by Christoph Hellwig
Browse files

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: default avatarKrzysztof Błaszkowski <kb@sysmikro.com.pl>
[hch: make spare happy]
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 6b15d665
Loading
Loading
Loading
Loading
+101 −76
Original line number Diff line number Diff line
@@ -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 @@ typedef int32_t vx_ino_t;
 */
#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 @@ struct vxfs_sb {
	 * 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 @@ struct vxfs_sb_info {
	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
+42 −28
Original line number Diff line number Diff line
@@ -68,8 +68,9 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
{
	struct super_block *sb = ip->i_sb;
	struct vxfs_inode_info *vip = VXFS_INO(ip);
	struct vxfs_sb_info *sbi = VXFS_SBI(sb);
	unsigned long bsize = sb->s_blocksize;
	u32 indsize = vip->vii_ext4.ve4_indsize;
	u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize);
	int i;

	if (indsize > sb->s_blocksize)
@@ -77,22 +78,24 @@ vxfs_bmap_ext4(struct inode *ip, long bn)

	for (i = 0; i < VXFS_NDADDR; i++) {
		struct direct *d = vip->vii_ext4.ve4_direct + i;
		if (bn >= 0 && bn < d->size)
			return (bn + d->extent);
		bn -= d->size;
		if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size))
			return (bn + fs32_to_cpu(sbi, d->extent));
		bn -= fs32_to_cpu(sbi, d->size);
	}

	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
		struct buffer_head *buf;
		daddr_t	bno;
		u32 *indir;
		__fs32 *indir;

		buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]);
		buf = sb_bread(sb,
			fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0]));
		if (!buf || !buffer_mapped(buf))
			goto fail_buf;

		indir = (u32 *)buf->b_data;
		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
		indir = (__fs32 *)buf->b_data;
		bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) +
			(bn % indsize);

		brelse(buf);
		return bno;
@@ -127,6 +130,7 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
static daddr_t
vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
{
	struct vxfs_sb_info		*sbi = VXFS_SBI(ip->i_sb);
	struct buffer_head		*bp = NULL;
	daddr_t				pblock = 0;
	int				i;
@@ -142,24 +146,27 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)

		typ = ((struct vxfs_typed *)bp->b_data) +
			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
		off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;

		if (block < off) {
			brelse(bp);
			continue;
		}

		switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
		switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >>
				VXFS_TYPED_TYPESHIFT)) {
		case VXFS_TYPED_INDIRECT:
			pblock = vxfs_bmap_indir(ip, typ->vt_block,
					typ->vt_size, block - off);
			pblock = vxfs_bmap_indir(ip,
					fs32_to_cpu(sbi, typ->vt_block),
					fs32_to_cpu(sbi, typ->vt_size),
					block - off);
			if (pblock == -2)
				break;
			goto out;
		case VXFS_TYPED_DATA:
			if ((block - off) >= typ->vt_size)
			if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size))
				break;
			pblock = (typ->vt_block + block - off);
			pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off;
			goto out;
		case VXFS_TYPED_INDIRECT_DEV4:
		case VXFS_TYPED_DATA_DEV4: {
@@ -167,13 +174,15 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
				(struct vxfs_typed_dev4 *)typ;

			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
			       (unsigned long long) typ4->vd4_block,
			       (unsigned long long) typ4->vd4_size,
			       typ4->vd4_dev);
			printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
			       fs64_to_cpu(sbi, typ4->vd4_block),
			       fs64_to_cpu(sbi, typ4->vd4_size),
			       fs32_to_cpu(sbi, typ4->vd4_dev));
			goto fail;
		}
		default:
			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__,
				__LINE__, fs64_to_cpu(sbi, typ->vt_hdr));
			BUG();
		}
		brelse(bp);
@@ -201,28 +210,33 @@ static daddr_t
vxfs_bmap_typed(struct inode *ip, long iblock)
{
	struct vxfs_inode_info		*vip = VXFS_INO(ip);
	struct vxfs_sb_info		*sbi = VXFS_SBI(ip->i_sb);
	daddr_t				pblock = 0;
	int				i;

	for (i = 0; i < VXFS_NTYPED; i++) {
		struct vxfs_typed	*typ = vip->vii_org.typed + i;
		int64_t			off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
		u64			hdr = fs64_to_cpu(sbi, typ->vt_hdr);
		int64_t			off = (hdr & VXFS_TYPED_OFFSETMASK);

#ifdef DIAGNOSTIC
		vxfs_typdump(typ);
#endif
		if (iblock < off)
			continue;
		switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
		switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) {
		case VXFS_TYPED_INDIRECT:
			pblock = vxfs_bmap_indir(ip, typ->vt_block,
					typ->vt_size, iblock - off);
			pblock = vxfs_bmap_indir(ip,
					fs32_to_cpu(sbi, typ->vt_block),
					fs32_to_cpu(sbi, typ->vt_size),
					iblock - off);
			if (pblock == -2)
				break;
			return (pblock);
		case VXFS_TYPED_DATA:
			if ((iblock - off) < typ->vt_size)
				return (typ->vt_block + iblock - off);
			if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size))
				return (fs32_to_cpu(sbi, typ->vt_block) +
						iblock - off);
			break;
		case VXFS_TYPED_INDIRECT_DEV4:
		case VXFS_TYPED_DATA_DEV4: {
@@ -230,10 +244,10 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
				(struct vxfs_typed_dev4 *)typ;

			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
			       (unsigned long long) typ4->vd4_block,
			       (unsigned long long) typ4->vd4_size,
			       typ4->vd4_dev);
			printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
			       fs64_to_cpu(sbi, typ4->vd4_block),
			       fs64_to_cpu(sbi, typ4->vd4_size),
			       fs32_to_cpu(sbi, typ4->vd4_dev));
			return 0;
		}
		default:
+9 −8
Original line number Diff line number Diff line
@@ -48,9 +48,9 @@
 * Linux driver for now.
 */
struct vxfs_dirblk {
	u_int16_t	d_free;		/* free space in dirblock */
	u_int16_t	d_nhash;	/* no of hash chains */
	u_int16_t	d_hash[1];	/* hash chain */
	__fs16		d_free;		/* free space in dirblock */
	__fs16		d_nhash;	/* no of hash chains */
	__fs16		d_hash[1];	/* hash chain */
};

/*
@@ -63,10 +63,10 @@ struct vxfs_dirblk {
 * VxFS directory entry.
 */
struct vxfs_direct {
	vx_ino_t	d_ino;			/* inode number */
	u_int16_t	d_reclen;		/* record length */
	u_int16_t	d_namelen;		/* d_name length */
	u_int16_t	d_hashnext;		/* next hash entry */
	__fs32		d_ino;			/* inode number */
	__fs16		d_reclen;		/* record length */
	__fs16		d_namelen;		/* d_name length */
	__fs16		d_hashnext;		/* next hash entry */
	char		d_name[VXFS_NAMELEN];	/* name */
};

@@ -87,6 +87,7 @@ struct vxfs_direct {
/*
 * VXFS_DIRBLKOV is the overhead of a specific dirblock.
 */
#define VXFS_DIRBLKOV(dbp)	((sizeof(short) * dbp->d_nhash) + 4)
#define VXFS_DIRBLKOV(sbi, dbp)	\
	((sizeof(short) * fs16_to_cpu(sbi, dbp->d_nhash)) + 4)

#endif /* _VXFS_DIR_H_ */
+3 −2
Original line number Diff line number Diff line
@@ -153,7 +153,8 @@ vxfs_read_fshead(struct super_block *sbp)
	vxfs_dumpfsh(pfp);
#endif

	tip = vxfs_blkiget(sbp, infp->vsi_iext, sfp->fsh_ilistino[0]);
	tip = vxfs_blkiget(sbp, infp->vsi_iext,
			fs32_to_cpu(infp, sfp->fsh_ilistino[0]));
	if (!tip)
		goto out_free_pfp;

@@ -169,7 +170,7 @@ vxfs_read_fshead(struct super_block *sbp)
		goto out_iput_stilist;
	}

	tip = vxfs_stiget(sbp, pfp->fsh_ilistino[0]);
	tip = vxfs_stiget(sbp, fs32_to_cpu(infp, pfp->fsh_ilistino[0]));
	if (!tip)
		goto out_iput_stilist;
	infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
+14 −14
Original line number Diff line number Diff line
@@ -42,20 +42,20 @@
 * Fileset header 
 */
struct vxfs_fsh {
	u_int32_t	fsh_version;		/* fileset header version */
	u_int32_t	fsh_fsindex;		/* fileset index */
	u_int32_t	fsh_time;		/* modification time - sec */
	u_int32_t	fsh_utime;		/* modification time - usec */
	u_int32_t	fsh_extop;		/* extop flags */
	vx_ino_t	fsh_ninodes;		/* allocated inodes */
	u_int32_t	fsh_nau;		/* number of IAUs */
	u_int32_t	fsh_old_ilesize;	/* old size of ilist */
	u_int32_t	fsh_dflags;		/* flags */
	u_int32_t	fsh_quota;		/* quota limit */
	vx_ino_t	fsh_maxinode;		/* maximum inode number */
	vx_ino_t	fsh_iauino;		/* IAU inode */
	vx_ino_t	fsh_ilistino[2];	/* ilist inodes */
	vx_ino_t	fsh_lctino;		/* link count table inode */
	__fs32		fsh_version;		/* fileset header version */
	__fs32		fsh_fsindex;		/* fileset index */
	__fs32		fsh_time;		/* modification time - sec */
	__fs32		fsh_utime;		/* modification time - usec */
	__fs32		fsh_extop;		/* extop flags */
	__fs32		fsh_ninodes;		/* allocated inodes */
	__fs32		fsh_nau;		/* number of IAUs */
	__fs32		fsh_old_ilesize;	/* old size of ilist */
	__fs32		fsh_dflags;		/* flags */
	__fs32		fsh_quota;		/* quota limit */
	__fs32		fsh_maxinode;		/* maximum inode number */
	__fs32		fsh_iauino;		/* IAU inode */
	__fs32		fsh_ilistino[2];	/* ilist inodes */
	__fs32		fsh_lctino;		/* link count table inode */

	/*
	 * Slightly more fields follow, but they
Loading