diff mbox

freevxfs

Message ID 1463929994.6136.9.camel@linux-q3cb.site (mailing list archive)
State New, archived
Headers show

Commit Message

Krzysztof Błaszkowski May 22, 2016, 3:13 p.m. UTC
Hello All,

I recently gave a try to vxfs (veritas fs) which is common to HP-UX and
it turned out that the module has been broken for very long time.

I fixed several issues with current freevxfs and also designed a
userspace tool which helps creating dm block devices from e.g. regular
file with raw image of hp-ux disk.
https://sourceforge.net/projects/linux-vxfs/


I send the patch because I believe that some people would appreciate
support for this vintage file system (e.g. me) and also it will be nice
to see my name in the kernel.

Regards,

Comments

Carlos Maiolino May 23, 2016, 8:23 a.m. UTC | #1
On Sun, May 22, 2016 at 05:13:14PM +0200, Krzysztof Błaszkowski wrote:
> Hello All,
> 
> I recently gave a try to vxfs (veritas fs) which is common to HP-UX and
> it turned out that the module has been broken for very long time.
> 
> I fixed several issues with current freevxfs and also designed a
> userspace tool which helps creating dm block devices from e.g. regular
> file with raw image of hp-ux disk.
> https://sourceforge.net/projects/linux-vxfs/
> 
> 
> I send the patch because I believe that some people would appreciate
> support for this vintage file system (e.g. me) and also it will be nice
> to see my name in the kernel.
> 

Hi,

- Can you please split this patch into individual patches fixing each specific
  problem? It's easier to review, instead of a big patch with several fixes into
  it.

- Also, as a quick view, there are a lot of trailing white spaces over the whole
  patch, which, should be removed.

  you can use the scripts/checkpatch.pl script to check your patches and see
  match at least the basics requirements for sending patches to kernel and, a
  read of Documentation/SubmittingPatches is interesting too.

> Regards,
> 
> -- 
> Krzysztof Blaszkowski

> diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
> index c8a9265..9890a84 100644
> --- a/fs/freevxfs/vxfs.h
> +++ b/fs/freevxfs/vxfs.h
> @@ -2,6 +2,39 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + *
> + * (c) 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests.
> + *
> + * These bugs and improvements were as follows:
> + *   - code not aware of cpu endianess and ondisk data is BE.
> + *   - misaligned structures read from block device
> + *   - wrong SB block number. default offset is 8kB
> + *   - kmem_cache_alloc() objectes released with kfree()
> + *   - inode.i_private released in evict_inode() callback.
> + *   - refactored vxfs_readdir() and vxfs_find_entry()
> + *
> + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> + * Example: */
> +// *  cksum mnt/usr/share/man/man3.Z/* 
> +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> +// *  cksum mnt/usr/local/doom/*
> +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> +// *  cksum mnt/usr/share/doc/*
> +// *  cksum mnt/usr/sprockets/lib/*
> +// *  cksum mnt/usr/sprockets/bin/*
> +/*

Don't use //

> + * Needles to say that checksums of files match these evaluated by
> + * HP-UX B.10.20 cksum. E.g.:
> + *  3457951056 4196020 /usr/local/doom/doom1.wad
> + *  2527157998 35344 /usr/local/doom/doomlaunch
> + *  2974998129 413696 /usr/local/doom/hpdoom
> + *
> + * The hpux_mdsetup tool project which is aimed at making possible
> + * accessing HP-UX logical volumes by device mapper is here:
> + *       https://sourceforge.net/projects/linux-vxfs/
> + *
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -38,6 +71,10 @@
>   */
>  #include <linux/types.h>
>  
> +//#define DIAGNOSTIC
> +#undef DIAGNOSTIC
> +#undef DIAGNOSTIC_V2
> +#undef DIAGNOSTIC_V3
>  
>  /*
>   * Data types for use with the VxFS ondisk format.
> @@ -152,7 +189,7 @@ struct vxfs_sb {
>  	/*
>  	 * Actually much more...
>  	 */
> -};
> +} __attribute__((packed));
>  
>  
>  /*
> @@ -260,4 +297,35 @@ enum {
>  #define VXFS_SBI(sbp) \
>  	((struct vxfs_sb_info *)(sbp)->s_fs_info)
>  
> +
> +#ifdef DIAGNOSTIC
> +#define F_ENTER(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#define F_EXIT(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +
> +#ifdef DIAGNOSTIC_V2
> +#define F_ENTER_V2(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#define F_EXIT_V2(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#else
> +#define F_ENTER_V2(a, b...) 
> +#define F_EXIT_V2(a, b...) 
> +#endif
> +
> +#ifdef DIAGNOSTIC_V3
> +#define F_ENTER_V3(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#define F_EXIT_V3(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#else
> +#define F_ENTER_V3(a, b...) 
> +#define F_EXIT_V3(a, b...) 
> +#endif
> +
> +#else // DIAGNOSTIC
> +#define F_ENTER(a, b...) 
> +#define F_EXIT(a, b...) 
> +#define F_ENTER_V2(a, b...) 
> +#define F_EXIT_V2(a, b...) 
> +#define F_ENTER_V3(a, b...) 
> +#define F_EXIT_V3(a, b...) 
> +#endif
> +

Lots of trailing white spaces here

> +
>  #endif /* _VXFS_SUPER_H_ */
> diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c
> index f86fd3c..58e6a17 100644
> --- a/fs/freevxfs/vxfs_bmap.c
> +++ b/fs/freevxfs/vxfs_bmap.c
> @@ -2,6 +2,10 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + *
> + * 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -39,17 +43,6 @@
>  #include "vxfs_extern.h"
>  
>  
> -#ifdef DIAGNOSTIC
> -static void
> -vxfs_typdump(struct vxfs_typed *typ)
> -{
> -	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
> -	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
> -	printk("block=%x ", typ->vt_block);
> -	printk("size=%x\n", typ->vt_size);
> -}
> -#endif
> -
>  /**
>   * vxfs_bmap_ext4 - do bmap for ext4 extents
>   * @ip:		pointer to the inode we do bmap for
> @@ -71,18 +64,23 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
>  	unsigned long bsize = sb->s_blocksize;
>  	u32 indsize = vip->vii_ext4.ve4_indsize;
>  	int i;
> +	daddr_t rc = 0;
> +
> +	F_ENTER_V2();
>  
>  	if (indsize > sb->s_blocksize)
>  		goto fail_size;
>  
>  	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);
> +		struct direct *d = vip->vii_ext4.ve4_direct + i; // cpu endian
> +		if (bn >= 0 && bn < d->size) {
> +			rc = bn + d->extent;
> +			break;
> +		}
>  		bn -= d->size;
>  	}
>  
> -	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
> +	if (!rc && ((bn / (indsize * indsize * bsize / 4)) == 0)) {
>  		struct buffer_head *buf;
>  		daddr_t	bno;
>  		u32 *indir;
> @@ -92,18 +90,21 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
>  			goto fail_buf;
>  
>  		indir = (u32 *)buf->b_data;
> -		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
> +		bno = be32_to_cpu(indir[(bn/indsize) % (indsize*bn)]) + (bn%indsize);
>  
>  		brelse(buf);
> -		return bno;
> -	} else
> -		printk(KERN_WARNING "no matching indir?");
> +		rc = bno;
> +	}
> +	if (!rc)
> +		printk(KERN_WARNING "%s:%d no matching indir?\n", __FUNCTION__, __LINE__);
>  
> -	return 0;
> +	F_EXIT_V2("pblk %d", rc);
> +	return rc;
>  
>  fail_size:
>  	printk("vxfs: indirect extent too big!\n");
>  fail_buf:
> +	F_EXIT();
>  	return 0;
>  }
>  
> @@ -129,51 +130,53 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
>  {
>  	struct buffer_head		*bp = NULL;
>  	daddr_t				pblock = 0;
> -	int				i;
> +	int i;
>  
> +	F_ENTER_V2();
>  	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
>  		struct vxfs_typed	*typ;
> -		int64_t			off;
> +		int64_t off;
>  
>  		bp = sb_bread(ip->i_sb,
>  				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
>  		if (!bp || !buffer_mapped(bp))
> -			return 0;
> +			break;
>  
>  		typ = ((struct vxfs_typed *)bp->b_data) +
>  			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
> -		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
> +		off = be64_to_cpu(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)(be64_to_cpu(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, be32_to_cpu(typ->vt_block),
> +					be32_to_cpu(typ->vt_size), block - off);
>  			if (pblock == -2)
>  				break;
>  			goto out;
>  		case VXFS_TYPED_DATA:
> -			if ((block - off) >= typ->vt_size)
> +			if ((block - off) >= be32_to_cpu(typ->vt_size))
>  				break;
> -			pblock = (typ->vt_block + block - off);
> +			pblock = be32_to_cpu(typ->vt_block) + block - off;
>  			goto out;
>  		case VXFS_TYPED_INDIRECT_DEV4:
>  		case VXFS_TYPED_DATA_DEV4: {
>  			struct vxfs_typed_dev4	*typ4 =
>  				(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_ERR "%s:%d TYPED_DEV4 detected!. block: %Lu\tsize: %Ld\tdev: %d\n",
> +				__FUNCTION__, __LINE__,
> +			       (unsigned long long) be64_to_cpu(typ4->vd4_block),
> +			       (unsigned long long) be64_to_cpu(typ4->vd4_size),
> +			       be32_to_cpu(typ4->vd4_dev));
>  			goto fail;
>  		}
>  		default:
> +			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __FUNCTION__, __LINE__, be64_to_cpu(typ->vt_hdr));
>  			BUG();
>  		}
>  		brelse(bp);
> @@ -182,7 +185,9 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
>  fail:
>  	pblock = 0;
>  out:
> -	brelse(bp);
> +	if (bp)
> +		brelse(bp);
> +	F_EXIT_V2();
>  	return (pblock);
>  }
>  
> @@ -200,16 +205,18 @@ out:
>  static daddr_t
>  vxfs_bmap_typed(struct inode *ip, long iblock)
>  {
> -	struct vxfs_inode_info		*vip = VXFS_INO(ip);
> -	daddr_t				pblock = 0;
> -	int				i;
> +	struct vxfs_inode_info *vip = VXFS_INO(ip);
> +	daddr_t pblock = 0;
> +	int i;
>  
> +	F_ENTER_V2();
>  	for (i = 0; i < VXFS_NTYPED; i++) {
> -		struct vxfs_typed	*typ = vip->vii_org.typed + i;
> +		struct vxfs_typed	*typ = vip->vii_org.typed + i; // cpu endian
>  		int64_t			off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
>  
> -#ifdef DIAGNOSTIC
> -		vxfs_typdump(typ);
> +#ifdef DIAGNOSTIC_V2
> +		printk(KERN_DEBUG "%s:%d type=%Lu, ofs=0x%Lx, blk=%d, size=%d\n", __FUNCTION__, __LINE__,
> +			typ->vt_hdr >> VXFS_TYPED_TYPESHIFT, off, typ->vt_block, typ->vt_size );
>  #endif
>  		if (iblock < off)
>  			continue;
> @@ -219,29 +226,36 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
>  					typ->vt_size, iblock - off);
>  			if (pblock == -2)
>  				break;
> -			return (pblock);
> +			goto out;
> +
>  		case VXFS_TYPED_DATA:
> -			if ((iblock - off) < typ->vt_size)
> -				return (typ->vt_block + iblock - off);
> +			if ((iblock - off) < typ->vt_size) {
> +				pblock = typ->vt_block + iblock - off;
> +				goto out;
> +			}
>  			break;
>  		case VXFS_TYPED_INDIRECT_DEV4:
>  		case VXFS_TYPED_DATA_DEV4: {
>  			struct vxfs_typed_dev4	*typ4 =
>  				(struct vxfs_typed_dev4 *)typ;
>  
> -			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
> -			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
> +			printk(KERN_ERR "%s:%d TYPED_DEV4 detected!. block: %Lu\tsize: %Ld\tdev: %d\n",
> +				__FUNCTION__, __LINE__,
>  			       (unsigned long long) typ4->vd4_block,
>  			       (unsigned long long) typ4->vd4_size,
>  			       typ4->vd4_dev);
> -			return 0;
> +			pblock = 0;
> +			goto out;
>  		}
>  		default:
> +			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __FUNCTION__, __LINE__, typ->vt_hdr);
>  			BUG();
>  		}
>  	}
>  
> -	return 0;
> +out:
> +	F_EXIT_V2("pblk %d", pblock);
> +	return pblock;
>  }
>  
>  /**
> @@ -270,12 +284,14 @@ vxfs_bmap1(struct inode *ip, long iblock)
>  	if (VXFS_ISIMMED(vip))
>  		goto unsupp;
>  
> -	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
> -			ip->i_ino, vip->vii_orgtype);
> +	printk(KERN_ERR "%s:%d inode %ld has no valid orgtype (%x)\n",
> +		__FUNCTION__, __LINE__,
> +		ip->i_ino, vip->vii_orgtype);
>  	BUG();
>  
>  unsupp:
> -	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
> -			ip->i_ino, vip->vii_orgtype);
> +	printk(KERN_WARNING "%s:%d inode %ld has an unsupported orgtype (%x)\n",
> +		__FUNCTION__, __LINE__,
> +		ip->i_ino, vip->vii_orgtype);
>  	return 0;
>  }
> diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h
> index aaf1fb0..d8b52e6 100644
> --- a/fs/freevxfs/vxfs_dir.h
> +++ b/fs/freevxfs/vxfs_dir.h
> @@ -84,9 +84,5 @@ struct vxfs_direct {
>  #define VXFS_DIRROUND(len)	((VXFS_DIRPAD + (len) - 1) & ~(VXFS_DIRPAD -1))
>  #define VXFS_DIRLEN(len)	(VXFS_DIRROUND(VXFS_NAMEMIN + (len)))
>  
> -/*
> - * VXFS_DIRBLKOV is the overhead of a specific dirblock.
> - */
> -#define VXFS_DIRBLKOV(dbp)	((sizeof(short) * dbp->d_nhash) + 4)
>  
>  #endif /* _VXFS_DIR_H_ */
> diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
> index 881aa3d..3d20421 100644
> --- a/fs/freevxfs/vxfs_extern.h
> +++ b/fs/freevxfs/vxfs_extern.h
> @@ -55,7 +55,7 @@ extern const struct inode_operations vxfs_immed_symlink_iops;
>  
>  /* vxfs_inode.c */
>  extern const struct address_space_operations vxfs_immed_aops;
> -extern struct kmem_cache	*vxfs_inode_cachep;
> +//extern struct kmem_cache	*vxfs_inode_cachep;
>  extern void			vxfs_dumpi(struct vxfs_inode_info *, ino_t);
>  extern struct inode *		vxfs_get_fake_inode(struct super_block *,
>  					struct vxfs_inode_info *);
> @@ -64,6 +64,10 @@ extern struct vxfs_inode_info *	vxfs_blkiget(struct super_block *, u_long, ino_t
>  extern struct vxfs_inode_info *	vxfs_stiget(struct super_block *, ino_t);
>  extern struct inode *		vxfs_iget(struct super_block *, ino_t);
>  extern void			vxfs_evict_inode(struct inode *);
> +extern void vxfs_destroy_inode(struct inode *ip);
> +extern void vxfs_inode_info_free(struct vxfs_inode_info *vip);
> +extern int vxfs_inode_info_cache(int setup);
> +
>  
>  /* vxfs_lookup.c */
>  extern const struct inode_operations	vxfs_dir_inode_ops;
> diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c
> index c9a6a94..69fcd7f 100644
> --- a/fs/freevxfs/vxfs_fshead.c
> +++ b/fs/freevxfs/vxfs_fshead.c
> @@ -2,6 +2,35 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + *
> + * (c) 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests.
> + *
> + * These bugs and improvements were as follows:
> + *   - code not aware of cpu endianess and ondisk data is BE.
> + *   - misaligned structures read from block device
> + *   - wrong SB block number. default offset is 8kB
> + *   - kmem_cache_alloc() objectes released with kfree()
> + *   - inode.i_private released in evict_inode() callback.
> + *   - refactored vxfs_readdir() and vxfs_find_entry()
> + *
> + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> + * Example: */
> +// *  cksum mnt/usr/share/man/man3.Z/* 
> +// *  cksum mnt/usr/share/doc/10.20RelNotes 

More white spaces and more //

> +// *  cksum mnt/usr/local/doom/*
> +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> +// *  cksum mnt/usr/share/doc/*
> +// *  cksum mnt/usr/sprockets/lib/*
> +// *  cksum mnt/usr/sprockets/bin/*
> +/*
> + * Needles to say that checksums of files match these evaluated by
> + * HP-UX B.10.20 cksum. E.g.:
> + *  3457951056 4196020 /usr/local/doom/doom1.wad
> + *  2527157998 35344 /usr/local/doom/doomlaunch
> + *  2974998129 413696 /usr/local/doom/hpdoom
> + *
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -60,6 +89,34 @@ vxfs_dumpfsh(struct vxfs_fsh *fhp)
>  }
>  #endif
>  
> +#define VXFS_BE32(field1, field2) fhp->field1 = be32_to_cpu(dbh->field2)
> +
> +
> +static void inline dbh2fhp(struct vxfs_fsh *fhp, void *_dbh)
> +{
> +#ifdef __LITTLE_ENDIAN
> +	struct vxfs_fsh *dbh = (struct vxfs_fsh *)_dbh;
> +
> +	VXFS_BE32(fsh_version, fsh_version);
> +	VXFS_BE32(fsh_fsindex, fsh_fsindex);
> +	VXFS_BE32(fsh_time, fsh_time);
> +	VXFS_BE32(fsh_utime, fsh_utime);
> +	VXFS_BE32(fsh_extop, fsh_extop);
> +	VXFS_BE32(fsh_ninodes, fsh_ninodes);
> +	VXFS_BE32(fsh_nau, fsh_nau);
> +	VXFS_BE32(fsh_old_ilesize, fsh_old_ilesize);
> +	VXFS_BE32(fsh_dflags, fsh_dflags);
> +	VXFS_BE32(fsh_quota, fsh_quota);
> +	VXFS_BE32(fsh_maxinode, fsh_maxinode);
> +	VXFS_BE32(fsh_iauino, fsh_iauino);
> +	VXFS_BE32(fsh_ilistino[0], fsh_ilistino[0]);
> +	VXFS_BE32(fsh_ilistino[1], fsh_ilistino[1]);
> +	VXFS_BE32(fsh_lctino, fsh_lctino);
> +#else
> +	memcpy(fhp, _dbh, sizeof(*fhp));
> +#endif
> +}
> +
>  /**
>   * vxfs_getfsh - read fileset header into memory
>   * @ip:		the (fake) fileset header inode
> @@ -83,7 +140,8 @@ vxfs_getfsh(struct inode *ip, int which)
>  
>  		if (!(fhp = kmalloc(sizeof(*fhp), GFP_KERNEL)))
>  			goto out;
> -		memcpy(fhp, bp->b_data, sizeof(*fhp));
> +
> +		dbh2fhp(fhp, bp->b_data);
>  
>  		put_bh(bp);
>  		return (fhp);
> @@ -110,9 +168,12 @@ vxfs_read_fshead(struct super_block *sbp)
>  	struct vxfs_fsh			*pfp, *sfp;
>  	struct vxfs_inode_info		*vip, *tip;
>  
> +	F_ENTER();
> +
>  	vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
>  	if (!vip) {
>  		printk(KERN_ERR "vxfs: unable to read fsh inode\n");
> +		F_EXIT();
>  		return -EINVAL;
>  	}
>  	if (!VXFS_ISFSH(vip)) {
> @@ -121,10 +182,8 @@ vxfs_read_fshead(struct super_block *sbp)
>  		goto out_free_fship;
>  	}
>  
> -
>  #ifdef DIAGNOSTIC
> -	printk("vxfs: fsh inode dump:\n");
> -	vxfs_dumpi(vip, infp->vsi_fshino);
> +	printk("%s:%d\n", __FUNCTION__, __LINE__);
>  #endif
>  
>  	infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
> @@ -160,7 +219,7 @@ vxfs_read_fshead(struct super_block *sbp)
>  	infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
>  	if (!infp->vsi_stilist) {
>  		printk(KERN_ERR "vxfs: unable to get structural list inode\n");
> -		kfree(tip);
> +		vxfs_inode_info_free(tip);
>  		goto out_free_pfp;
>  	}
>  	if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
> @@ -175,7 +234,7 @@ vxfs_read_fshead(struct super_block *sbp)
>  	infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
>  	if (!infp->vsi_ilist) {
>  		printk(KERN_ERR "vxfs: unable to get inode list inode\n");
> -		kfree(tip);
> +		vxfs_inode_info_free(tip);
>  		goto out_iput_stilist;
>  	}
>  	if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
> @@ -184,6 +243,7 @@ vxfs_read_fshead(struct super_block *sbp)
>  		goto out_iput_ilist;
>  	}
>  
> +	F_EXIT();
>  	return 0;
>  
>   out_iput_ilist:
> @@ -196,8 +256,10 @@ vxfs_read_fshead(struct super_block *sbp)
>   	kfree(sfp);
>   out_iput_fship:
>  	iput(infp->vsi_fship);
> +	F_EXIT();
>  	return -EINVAL;
>   out_free_fship:
> - 	kfree(vip);
> +	vxfs_inode_info_free(vip);
> +	F_EXIT();
>  	return -EINVAL;
>  }
> diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
> index 363e3ae..84dec28 100644
> --- a/fs/freevxfs/vxfs_inode.c
> +++ b/fs/freevxfs/vxfs_inode.c
> @@ -2,6 +2,34 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + *
> + * (c) 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests.
> + *
> + * These bugs and improvements were as follows:
> + *   - code not aware of cpu endianess and ondisk data is BE.
> + *   - misaligned structures read from block device
> + *   - wrong SB block number. default offset is 8kB
> + *   - kmem_cache_alloc() objectes released with kfree()
> + *   - inode.i_private released in evict_inode() callback.
> + *   - refactored vxfs_readdir() and vxfs_find_entry()
> + *
> + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> + * Example: */
> +// *  cksum mnt/usr/share/man/man3.Z/* 
> +// *  cksum mnt/usr/share/doc/10.20RelNotes 

More white spaces and more //

> +// *  cksum mnt/usr/local/doom/*
> +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> +// *  cksum mnt/usr/share/doc/*
> +// *  cksum mnt/usr/sprockets/lib/*
> +// *  cksum mnt/usr/sprockets/bin/*
> +/*
> + * Needles to say that checksums of files match these evaluated by
> + * HP-UX B.10.20 cksum. E.g.:
> + *  3457951056 4196020 /usr/local/doom/doom1.wad
> + *  2527157998 35344 /usr/local/doom/doomlaunch
> + *  2974998129 413696 /usr/local/doom/hpdoom
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -41,7 +69,7 @@
>  #include "vxfs_extern.h"
>  
>  
> -struct kmem_cache		*vxfs_inode_cachep;
> +static struct kmem_cache *vxfs_inode_cachep;
>  
>  
>  #ifdef DIAGNOSTIC
> @@ -51,23 +79,88 @@ struct kmem_cache		*vxfs_inode_cachep;
>  void
>  vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
>  {
> -	printk(KERN_DEBUG "\n\n");
> -	if (ino)
> -		printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino);
> +#ifdef DIAGNOSTIC_V2
> +	if (ino && vip)
> +		printk(KERN_DEBUG "\nvxfs inode %ld dump **** %p\n", ino, vip);
>  	else
> -		printk(KERN_DEBUG "dumping unknown vxfs inode\n");
> +		printk(KERN_DEBUG "\ndumping unknown vxfs inode %p\n", vip);
>  
> -	printk(KERN_DEBUG "---------------------------\n");
> -	printk(KERN_DEBUG "mode is %x\n", vip->vii_mode);
> -	printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n",
> -			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
> -	printk(KERN_DEBUG "size:%Lx, blocks:%u\n",
> +	if (vip) {
> +		printk(KERN_DEBUG " * mode: %x, type %d\n", vip->vii_mode, vip->vii_orgtype);
> +		printk(KERN_DEBUG " * size:%Lx, blocks:%u\n",
>  			vip->vii_size, vip->vii_blocks);
> -	printk(KERN_DEBUG "orgtype:%u\n", vip->vii_orgtype);
> +		printk(KERN_DEBUG " * nlink:%u, uid:%u, gid:%u\n",
> +			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
> +	}
> +#endif
>  }
>  #endif
>  
>  
> +#define VXFS_BE32(field1, field2) vip->field1 = be32_to_cpu(dip->field2)
> +#define VXFS_BE64(field1, field2) vip->field1 = be64_to_cpu(dip->field2)
> +#define VXFS_BE16(field1, field2) vip->field1 = be16_to_cpu(dip->field2)
> +
> +
> +static void inline dip2vip_cpy(struct vxfs_inode_info *vip, struct vxfs_dinode *dip)
> +{
> +#ifdef __LITTLE_ENDIAN
> +	int j;
> +
> +	VXFS_BE32(vdi_mode, vdi_mode);
> +	VXFS_BE32(vdi_nlink, vdi_nlink);
> +	VXFS_BE32(vdi_uid, vdi_uid);
> +	VXFS_BE32(vdi_gid, vdi_gid);
> +	VXFS_BE64(vdi_size, vdi_size);
> +	VXFS_BE32(vdi_atime, vdi_atime);
> +	VXFS_BE32(vdi_autime, vdi_autime);
> +	VXFS_BE32(vdi_mtime, vdi_mtime);
> +	VXFS_BE32(vdi_mutime, vdi_mutime);
> +	VXFS_BE32(vdi_ctime, vdi_ctime);
> +	VXFS_BE32(vdi_cutime, vdi_cutime);
> +	vip->vdi_aflags = dip->vdi_aflags;
> +	vip->vdi_orgtype = dip->vdi_orgtype;
> +	VXFS_BE16(vdi_eopflags, vdi_eopflags);
> +	VXFS_BE32(vdi_eopdata, vdi_eopdata);
> +
> +	VXFS_BE32(vdi_ftarea.i_regular.reserved, vdi_ftarea.i_regular.reserved);
> +	VXFS_BE32(vdi_ftarea.i_regular.fixextsize, vdi_ftarea.i_regular.fixextsize);
> +	VXFS_BE32(vdi_blocks, vdi_blocks);
> +	VXFS_BE32(vdi_gen, vdi_gen);
> +	VXFS_BE64(vdi_version, vdi_version);
> +
> +	switch (dip->vdi_orgtype) {
> +	case VXFS_ORG_EXT4:
> +		VXFS_BE32(vdi_org.ext4.ve4_spare, vdi_org.ext4.ve4_spare);
> +		VXFS_BE32(vdi_org.ext4.ve4_indsize, vdi_org.ext4.ve4_indsize);
> +		for (j = 0; j < VXFS_NIADDR; j++) {
> +			VXFS_BE32(vdi_org.ext4.ve4_indir[j], vdi_org.ext4.ve4_indir[j]);
> +		}
> +		for (j = 0; j < VXFS_NDADDR; j++) {
> +			VXFS_BE32(vdi_org.ext4.ve4_direct[j].extent, vdi_org.ext4.ve4_direct[j].extent);
> +			VXFS_BE32(vdi_org.ext4.ve4_direct[j].size, vdi_org.ext4.ve4_direct[j].size);
> +		}
> +		break;
> +	case VXFS_ORG_IMMED:
> +		memcpy(&vip->vdi_org.immed, &dip->vdi_org.immed, sizeof(vip->vdi_org.immed));
> +		break;
> +	case VXFS_ORG_TYPED:
> +		for (j = 0; j < VXFS_NTYPED; j++) {
> +			VXFS_BE64(vdi_org.typed[j].vt_hdr, vdi_org.typed[j].vt_hdr);
> +			VXFS_BE32(vdi_org.typed[j].vt_block, vdi_org.typed[j].vt_block);
> +			VXFS_BE32(vdi_org.typed[j].vt_size, vdi_org.typed[j].vt_size);
> +		}
> +		break;
> +	
> +	};
> +
> +	VXFS_BE32(vdi_iattrino, vdi_iattrino);
> +#else
> +	memcpy(vip, dip, sizeof(*vip));
> +#endif
> +}
> +
> +
>  /**
>   * vxfs_blkiget - find inode based on extent #
>   * @sbp:	superblock of the filesystem we search in
> @@ -84,6 +177,9 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
>   *  buffercache.  This function should not be used outside the
>   *  read_super() method, otherwise the data may be incoherent.
>   */
> +
> +
> +
>  struct vxfs_inode_info *
>  vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
>  {
> @@ -101,7 +197,7 @@ vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
>  		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
>  			goto fail;
>  		dip = (struct vxfs_dinode *)(bp->b_data + offset);
> -		memcpy(vip, dip, sizeof(*vip));
> +		dip2vip_cpy(vip, dip);
>  #ifdef DIAGNOSTIC
>  		vxfs_dumpi(vip, ino);
>  #endif
> @@ -143,7 +239,7 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
>  		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
>  			goto fail;
>  		dip = (struct vxfs_dinode *)(kaddr + offset);
> -		memcpy(vip, dip, sizeof(*vip));
> +		dip2vip_cpy(vip, dip);
>  #ifdef DIAGNOSTIC
>  		vxfs_dumpi(vip, ino);
>  #endif
> @@ -190,7 +286,7 @@ vxfs_stiget(struct super_block *sbp, ino_t ino)
>  static __inline__ umode_t
>  vxfs_transmod(struct vxfs_inode_info *vip)
>  {
> -	umode_t			ret = vip->vii_mode & ~VXFS_TYPE_MASK;
> +	umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK;
>  
>  	if (VXFS_ISFIFO(vip))
>  		ret |= S_IFIFO;
> @@ -340,21 +436,61 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
>  static void vxfs_i_callback(struct rcu_head *head)
>  {
>  	struct inode *inode = container_of(head, struct inode, i_rcu);
> -	kmem_cache_free(vxfs_inode_cachep, inode->i_private);
> +	void *priv = inode->i_private;
> +
> +	inode->i_private = NULL;
> +	// just in case the same inode was used elsewhere after releasing i_private.
> +	// if it was then dereferencing NULL is far better than using invalid
> +	// pointer to memory claimed by something.
> +	kmem_cache_free(vxfs_inode_cachep, priv);
> +}
> +
> +void vxfs_destroy_inode(struct inode *ip)
> +{
> +	call_rcu(&ip->i_rcu, vxfs_i_callback);
> +}
> +
> +void vxfs_inode_info_free(struct vxfs_inode_info *vip)
> +{
> +	kmem_cache_free(vxfs_inode_cachep, vip);
>  }
>  
> +
>  /**
>   * vxfs_evict_inode - remove inode from main memory
>   * @ip:		inode to discard.
>   *
>   * Description:
> - *  vxfs_evict_inode() is called on the final iput and frees the private
> - *  inode area.
> + *  vxfs_evict_inode() is called on the final iput 
>   */
>  void
>  vxfs_evict_inode(struct inode *ip)
>  {
>  	truncate_inode_pages_final(&ip->i_data);
> +	invalidate_inode_buffers(ip);
>  	clear_inode(ip);
> -	call_rcu(&ip->i_rcu, vxfs_i_callback);
>  }
> +
> +int vxfs_inode_info_cache(int setup)
> +{
> +	int rc = 0;
> +
> +	if (!setup) {
> +		vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
> +			sizeof(struct vxfs_inode_info), 0,
> +			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
> +
> +		if (!vxfs_inode_cachep)
> +			rc = -ENOMEM;
> +	} else {
> +	/*
> +	 * Make sure all delayed rcu free inodes are flushed before we
> +	 * destroy cache.
> +	 */
> +		rcu_barrier();
> +		kmem_cache_destroy(vxfs_inode_cachep);
> +	}
> +
> +	return rc;
> +}
> +
> diff --git a/fs/freevxfs/vxfs_inode.h b/fs/freevxfs/vxfs_inode.h
> index 240aeb1..9fc3533 100644
> --- a/fs/freevxfs/vxfs_inode.h
> +++ b/fs/freevxfs/vxfs_inode.h
> @@ -77,13 +77,13 @@ struct vxfs_ext4 {
>  		vx_daddr_t	extent;			/* Extent number */
>  		int32_t		size;			/* Size of extent */
>  	} ve4_direct[VXFS_NDADDR];
> -};
> +}  __attribute__((packed));
>  
>  struct vxfs_typed {
>  	u_int64_t	vt_hdr;		/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
>  	vx_daddr_t	vt_block;	/* Extent block */
>  	int32_t		vt_size;	/* Size in blocks */
> -};
> +}  __attribute__((packed));
>  
>  struct vxfs_typed_dev4 {
>  	u_int64_t	vd4_hdr;	/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
> @@ -91,7 +91,7 @@ struct vxfs_typed_dev4 {
>  	u_int64_t	vd4_size;	/* Size in blocks */
>  	int32_t		vd4_dev;	/* Device ID */
>  	u_int32_t	__pad1;
> -};
> +}  __attribute__((packed));
>  
>  /*
>   * The inode as contained on the physical device.
> @@ -134,7 +134,7 @@ struct vxfs_dinode {
>  		struct vxfs_typed	typed[VXFS_NTYPED];
>  	} vdi_org;
>  	u_int32_t	vdi_iattrino;
> -};
> +} __attribute__((packed));
>  
>  #define vdi_rdev	vdi_ftarea.rdev
>  #define vdi_dotdot	vdi_ftarea.dotdot
> diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
> index 99c7f0a..2e5365b 100644
> --- a/fs/freevxfs/vxfs_lookup.c
> +++ b/fs/freevxfs/vxfs_lookup.c
> @@ -2,6 +2,34 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + * (c) 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests.
> + *
> + * These bugs and improvements were as follows:
> + *   - code not aware of cpu endianess and ondisk data is BE.
> + *   - misaligned structures read from block device
> + *   - wrong SB block number. default offset is 8kB
> + *   - kmem_cache_alloc() objectes released with kfree()
> + *   - inode.i_private released in evict_inode() callback.
> + *   - refactored vxfs_readdir() and vxfs_find_entry()
> + *
> + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> + * Example: */
> +// *  cksum mnt/usr/share/man/man3.Z/* 
> +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> +// *  cksum mnt/usr/local/doom/*
> +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> +// *  cksum mnt/usr/share/doc/*
> +// *  cksum mnt/usr/sprockets/lib/*
> +// *  cksum mnt/usr/sprockets/bin/*
> +/*
> + * Needles to say that checksums of files match these evaluated by
> + * HP-UX B.10.20 cksum. E.g.:
> + *  3457951056 4196020 /usr/local/doom/doom1.wad
> + *  2527157998 35344 /usr/local/doom/doomlaunch
> + *  2974998129 413696 /usr/local/doom/hpdoom
> + *
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -76,6 +104,15 @@ dir_blocks(struct inode *ip)
>  }
>  
>  /*
> + * VXFS_dirblk_ovh is the overhead of a specific dirblock.
> + */
> +static inline u_long VXFS_dirblk_ovh(struct vxfs_dirblk *dbp)
> +{
> +	return (sizeof(short) * be16_to_cpu(dbp->d_nhash)) + 4;
> +}
> +
> +
> +/*
>   * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
>   *
>   * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
> @@ -83,19 +120,13 @@ dir_blocks(struct inode *ip)
>  static inline int
>  vxfs_match(int len, const char * const name, struct vxfs_direct *de)
>  {
> -	if (len != de->d_namelen)
> +	if (len != be16_to_cpu(de->d_namelen))
>  		return 0;
>  	if (!de->d_ino)
>  		return 0;
>  	return !memcmp(name, de->d_name, len);
>  }
>  
> -static inline struct vxfs_direct *
> -vxfs_next_entry(struct vxfs_direct *de)
> -{
> -	return ((struct vxfs_direct *)((char*)de + de->d_reclen));
> -}
> -
>  /**
>   * vxfs_find_entry - find a mathing directory entry for a dentry
>   * @ip:		directory inode
> @@ -113,50 +144,73 @@ vxfs_next_entry(struct vxfs_direct *de)
>  static struct vxfs_direct *
>  vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
>  {
> -	u_long				npages, page, nblocks, pblocks, block;
> -	u_long				bsize = ip->i_sb->s_blocksize;
> -	const char			*name = dp->d_name.name;
> -	int				namelen = dp->d_name.len;
> -
> -	npages = dir_pages(ip);
> -	nblocks = dir_blocks(ip);
> -	pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
> -	
> -	for (page = 0; page < npages; page++) {
> -		caddr_t			kaddr;
> -		struct page		*pp;
> -
> -		pp = vxfs_get_page(ip->i_mapping, page);
> -		if (IS_ERR(pp))
> -			continue;
> -		kaddr = (caddr_t)page_address(pp);
> -
> -		for (block = 0; block <= nblocks && block <= pblocks; block++) {
> -			caddr_t			baddr, limit;
> -			struct vxfs_dirblk	*dbp;
> -			struct vxfs_direct	*de;
> -
> -			baddr = kaddr + (block * bsize);
> -			limit = baddr + bsize - VXFS_DIRLEN(1);
> -			
> -			dbp = (struct vxfs_dirblk *)baddr;
> -			de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
> -
> -			for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
> -				if (!de->d_reclen)
> -					break;
> -				if (!de->d_ino)
> -					continue;
> -				if (vxfs_match(namelen, name, de)) {
> -					*ppp = pp;
> -					return (de);
> -				}
> +	u_long bsize = ip->i_sb->s_blocksize;
> +	const char *name = dp->d_name.name;
> +	int namelen = dp->d_name.len;
> +	loff_t limit = VXFS_DIRROUND(ip->i_size);
> +	struct vxfs_direct *de_exit = NULL;
> +	loff_t pos = 0;
> +
> +
> +	F_ENTER_V2("\"%s\" %d", name, namelen);
> +
> +	while (pos < limit) {
> +		struct page *pp;
> +		char *kaddr;
> +		int pg_ofs = pos & ~PAGE_CACHE_MASK;
> +
> +		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_CACHE_SHIFT);
> +		if (IS_ERR(pp)) {
> +			return NULL;
> +		}
> +		kaddr = (char *)page_address(pp);
> +
> +#ifdef DIAGNOSTIC_V2
> +		printk("%s:%d pos %ld, lim %ld, %p\n", __FUNCTION__, __LINE__, pos, limit, kaddr);
> +#endif
> +		while (pg_ofs < PAGE_SIZE && pos < limit) {
> +			struct vxfs_direct *de;
> +
> +			if ((pos & (bsize - 1)) < 4) {
> +				struct vxfs_dirblk *dbp = 

White space here too

> +				    (struct vxfs_dirblk *)(kaddr + (pos & ~PAGE_CACHE_MASK ));
> +				pos += VXFS_dirblk_ovh(dbp);
> +				pg_ofs += VXFS_dirblk_ovh(dbp);
> +			}
> +			de = (struct vxfs_direct *)(kaddr + pg_ofs);
> +
> +#ifdef DIAGNOSTIC_V2
> +			printk("%s:%d de=%p, pgo %d: \"%10s\", %d %d %d\n", __FUNCTION__, __LINE__,
> +				de, pg_ofs,
> +				de->d_name, be16_to_cpu(de->d_namelen),
> +				be16_to_cpu(de->d_reclen), be32_to_cpu(de->d_ino));
> +#endif
> +			if (!de->d_reclen) {
> +				pos += bsize - 1;
> +				pos &= ~(bsize - 1);
> +				break;
> +			}
> +
> +			pg_ofs += be16_to_cpu(de->d_reclen);
> +			pos += be16_to_cpu(de->d_reclen);
> +			if (!de->d_ino) {
> +				continue;
> +			}
> +
> +			if (vxfs_match(namelen, name, de)) {
> +				*ppp = pp;
> +				de_exit= de; //return (de);
> +				break;
>  			}
>  		}
> -		vxfs_put_page(pp);
> +		if (!de_exit)
> +			vxfs_put_page(pp);
> +		else
> +			break;
>  	}
>  
> -	return NULL;
> +	F_EXIT_V2("\"%s\": %p", name, de_exit);
> +	return de_exit;
>  }
>  
>  /**
> @@ -180,11 +234,10 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
>  
>  	de = vxfs_find_entry(dip, dp, &pp);
>  	if (de) {
> -		ino = de->d_ino;
> -		kunmap(pp);
> -		page_cache_release(pp);
> +		ino = be32_to_cpu(de->d_ino);
> +		vxfs_put_page(pp);
>  	}
> -	
> +
>  	return (ino);
>  }
>  
> @@ -207,17 +260,17 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
>  {
>  	struct inode		*ip = NULL;
>  	ino_t			ino;
> -			 
> +
>  	if (dp->d_name.len > VXFS_NAMELEN)
>  		return ERR_PTR(-ENAMETOOLONG);
> -				 
> +
>  	ino = vxfs_inode_by_name(dip, dp);
>  	if (ino) {
>  		ip = vxfs_iget(dip->i_sb, ino);
>  		if (IS_ERR(ip))
>  			return ERR_CAST(ip);
> +		d_add(dp, ip);
>  	}
> -	d_add(dp, ip);
>  	return NULL;
>  }
>  
> @@ -234,80 +287,95 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
>   * Returns:
>   *   Zero.
>   */
> +
>  static int
>  vxfs_readdir(struct file *fp, struct dir_context *ctx)
>  {
>  	struct inode		*ip = file_inode(fp);
>  	struct super_block	*sbp = ip->i_sb;
>  	u_long			bsize = sbp->s_blocksize;
> -	u_long			page, npages, block, pblocks, nblocks, offset;
> -	loff_t			pos;
> +	loff_t			pos, limit;
> +
> +	F_ENTER_V3("pos %ld, ino %ld, size %ld", (long)ctx->pos, ip->i_ino, (long)ip->i_size);
>  
>  	if (ctx->pos == 0) {
>  		if (!dir_emit_dot(fp, ctx))
> -			return 0;
> -		ctx->pos = 1;
> +			goto out;
> +		ctx->pos++;
>  	}
>  	if (ctx->pos == 1) {
>  		if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
> -			return 0;
> -		ctx->pos = 2;
> +			goto out;
> +		ctx->pos++;
>  	}
> -	pos = ctx->pos - 2;
> -	
> -	if (pos > VXFS_DIRROUND(ip->i_size))
> -		return 0;
>  
> -	npages = dir_pages(ip);
> -	nblocks = dir_blocks(ip);
> -	pblocks = VXFS_BLOCK_PER_PAGE(sbp);
> +	limit = VXFS_DIRROUND(ip->i_size);
> +	if (ctx->pos > limit) {
> +//		ctx->pos = 0;
> +		goto out;
> +	}
>  
> -	page = pos >> PAGE_CACHE_SHIFT;
> -	offset = pos & ~PAGE_CACHE_MASK;
> -	block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
> +	pos = ctx->pos & ~3L;
>  
> -	for (; page < npages; page++, block = 0) {
> -		char			*kaddr;
> -		struct page		*pp;
> +	while (pos < limit) {
> +		struct page *pp;
> +		char *kaddr;
> +		int pg_ofs = pos & ~PAGE_CACHE_MASK;
> +		int rc = 0;
>  
> -		pp = vxfs_get_page(ip->i_mapping, page);
> -		if (IS_ERR(pp))
> -			continue;
> +		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_CACHE_SHIFT);
> +		if (IS_ERR(pp)) {
> +			return -ENOMEM;
> +		}
>  		kaddr = (char *)page_address(pp);
>  
> -		for (; block <= nblocks && block <= pblocks; block++) {
> -			char			*baddr, *limit;
> -			struct vxfs_dirblk	*dbp;
> -			struct vxfs_direct	*de;
> -
> -			baddr = kaddr + (block * bsize);
> -			limit = baddr + bsize - VXFS_DIRLEN(1);
> -	
> -			dbp = (struct vxfs_dirblk *)baddr;
> -			de = (struct vxfs_direct *)
> -				(offset ?
> -				 (kaddr + offset) :
> -				 (baddr + VXFS_DIRBLKOV(dbp)));
> -
> -			for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
> -				if (!de->d_reclen)
> -					break;
> -				if (!de->d_ino)
> -					continue;
> -
> -				offset = (char *)de - kaddr;
> -				ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
> -				if (!dir_emit(ctx, de->d_name, de->d_namelen,
> -					de->d_ino, DT_UNKNOWN)) {
> -					vxfs_put_page(pp);
> -					return 0;
> -				}
> +#ifdef DIAGNOSTIC_V3
> +		printk("%s:%d pos %ld, lim %ld, %p\n", __FUNCTION__, __LINE__, pos, limit, kaddr);
> +#endif
> +		while (pg_ofs < PAGE_SIZE && pos < limit) {
> +			struct vxfs_direct *de;
> +
> +			if ((pos & (bsize - 1)) < 4) {
> +				struct vxfs_dirblk *dbp = 

White space

> +				    (struct vxfs_dirblk *)(kaddr + (pos & ~PAGE_CACHE_MASK ));
> +				pos += VXFS_dirblk_ovh(dbp);
> +				pg_ofs += VXFS_dirblk_ovh(dbp);
> +			}
> +			de = (struct vxfs_direct *)(kaddr + pg_ofs);
> +
> +#ifdef DIAGNOSTIC_V3
> +			printk("%s:%d de=%p, pgo %d: \"%10s\", %d %d %d\n", __FUNCTION__, __LINE__,
> +				de, pg_ofs,
> +				de->d_name, be16_to_cpu(de->d_namelen),
> +				be16_to_cpu(de->d_reclen), be32_to_cpu(de->d_ino));
> +#endif
> +			if (!de->d_reclen) {
> +				pos += bsize - 1;
> +				pos &= ~(bsize - 1);
> +				break;
> +			}
> +
> +			pg_ofs += be16_to_cpu(de->d_reclen);
> +			pos += be16_to_cpu(de->d_reclen);
> +			if (!de->d_ino) {
> +				continue;
> +			}
> +
> +			if (! (rc = dir_emit(ctx, de->d_name, be16_to_cpu(de->d_namelen),
> +				be32_to_cpu(de->d_ino), DT_UNKNOWN))) {
> +				// the dir entry was not submitted, so fix pos.
> +				pos -= be16_to_cpu(de->d_reclen); 
White space
> +				break;
>  			}
> -			offset = 0;
>  		}
>  		vxfs_put_page(pp);
> -		offset = 0;
> +		if (!rc)
> +			break;
>  	}
> -	ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
> +
> +	ctx->pos = pos | 2;
> +
> +out:
> +	F_EXIT_V3("pos %ld", (long)ctx->pos);
>  	return 0;
>  }
> diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c
> index 0495008..19a1cab 100644
> --- a/fs/freevxfs/vxfs_olt.c
> +++ b/fs/freevxfs/vxfs_olt.c
> @@ -2,6 +2,10 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + *
> + * 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -43,14 +47,14 @@ static inline void
>  vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
>  {
>  	BUG_ON(infp->vsi_fshino);
> -	infp->vsi_fshino = fshp->olt_fsino[0];
> +	infp->vsi_fshino = be32_to_cpu(fshp->olt_fsino[0]);
>  }
>  
>  static inline void
>  vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
>  {
>  	BUG_ON(infp->vsi_iext);
> -	infp->vsi_iext = ilistp->olt_iext[0]; 
> +	infp->vsi_iext = be32_to_cpu(ilistp->olt_iext[0]); 

	White space in these lines

>  }
>  
>  static inline u_long
> @@ -80,6 +84,7 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
>  	struct buffer_head	*bp;
>  	struct vxfs_olt		*op;
>  	char			*oaddr, *eaddr;
> +	u32 j;
>  
>  
>  	bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
> @@ -87,8 +92,8 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
>  		goto fail;
>  
>  	op = (struct vxfs_olt *)bp->b_data;
> -	if (op->olt_magic != VXFS_OLT_MAGIC) {
> -		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
> +	if ((j = be32_to_cpu(op->olt_magic)) != VXFS_OLT_MAGIC) {
> +		printk(KERN_NOTICE "vxfs: ivalid olt magic number %08x at +%d\n", j, infp->vsi_oltext);
>  		goto fail;
>  	}
>  
> @@ -97,19 +102,24 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
>  	 * I've not seen any such filesystem yet and I'm lazy..  --hch
>  	 */
>  	if (infp->vsi_oltsize > 1) {
> -		printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n");
> +		printk(KERN_NOTICE "vxfs: oltsize > 1 detected (%d).\n", infp->vsi_oltsize);
>  		printk(KERN_NOTICE "vxfs: please notify hch@infradead.org\n");
>  		goto fail;
>  	}
>  
> -	oaddr = bp->b_data + op->olt_size;
> +	oaddr = bp->b_data + be32_to_cpu(op->olt_size);
>  	eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
>  
>  	while (oaddr < eaddr) {
> -		struct vxfs_oltcommon	*ocp =
> +		struct vxfs_oltcommon *ocp =
>  			(struct vxfs_oltcommon *)oaddr;
> -		
> -		switch (ocp->olt_type) {
> +
> +#ifdef DIAGNOSTIC
> +		printk(KERN_DEBUG "oltc_type %d, sz %d at +%d\n", 

	White space
> +			be32_to_cpu(ocp->olt_type), be32_to_cpu(ocp->olt_size), (int)(oaddr - bp->b_data));
> +#endif
> +
> +		switch (be32_to_cpu(ocp->olt_type)) {
>  		case VXFS_OLT_FSHEAD:
>  			vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
>  			break;
> @@ -118,11 +128,16 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
>  			break;
>  		}
>  
> -		oaddr += ocp->olt_size;
> +		oaddr += be32_to_cpu(ocp->olt_size);
>  	}
>  
> +#ifdef DIAGNOSTIC
> +	printk(KERN_DEBUG "olt_size %d, vsi_fshino %d, vsi_iext %ld\n",
> +	    be32_to_cpu(op->olt_size), (u32)infp->vsi_fshino, infp->vsi_iext);
> +#endif
> +
>  	brelse(bp);
> -	return 0;
> +	return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
>  
>  fail:
>  	brelse(bp);
> diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
> index 7ca8c75..9fbf271 100644
> --- a/fs/freevxfs/vxfs_super.c
> +++ b/fs/freevxfs/vxfs_super.c
> @@ -2,6 +2,38 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + * (c) 2016 Krzysztof Blaszkowski.
> + *       Many bug fixes, improvements & tests.
> + *
> + * These bugs and improvements were as follows:
> + *   - code not aware of cpu endianess and ondisk data is BE.
> + *   - misaligned structures read from block device
> + *   - wrong SB block number. default offset is 8kB
> + *   - kmem_cache_alloc() objectes released with kfree()
> + *   - inode.i_private released in evict_inode() callback.
> + *   - refactored vxfs_readdir() and vxfs_find_entry()
> + *
> + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> + * Example: */
> +// *  cksum mnt/usr/share/man/man3.Z/* 
> +// *  cksum mnt/usr/share/doc/10.20RelNotes 

White space

> +// *  cksum mnt/usr/local/doom/*
> +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> +// *  cksum mnt/usr/share/doc/*
> +// *  cksum mnt/usr/sprockets/lib/*
> +// *  cksum mnt/usr/sprockets/bin/*
> +/*
> + * Needles to say that checksums of files match these evaluated by
> + * HP-UX B.10.20 cksum. E.g.:
> + *  3457951056 4196020 /usr/local/doom/doom1.wad
> + *  2527157998 35344 /usr/local/doom/doomlaunch
> + *  2974998129 413696 /usr/local/doom/hpdoom
> + *
> + * The hpux_mdsetup tool project which is aimed at making possible
> + * accessing HP-UX logical volumes by device mapper is here:
> + *       https://sourceforge.net/projects/linux-vxfs/
> + *
> + *
>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -41,6 +73,7 @@
>  #include <linux/stat.h>
>  #include <linux/vfs.h>
>  #include <linux/mount.h>
> +#include <linux/byteorder/generic.h>
>  
>  #include "vxfs.h"
>  #include "vxfs_extern.h"
> @@ -48,7 +81,7 @@
>  #include "vxfs_inode.h"
>  
>  
> -MODULE_AUTHOR("Christoph Hellwig");
> +MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski");
>  MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
>  MODULE_LICENSE("Dual BSD/GPL");
>  
> @@ -59,6 +92,7 @@ static int		vxfs_statfs(struct dentry *, struct kstatfs *);
>  static int		vxfs_remount(struct super_block *, int *, char *);
>  
>  static const struct super_operations vxfs_super_ops = {
> +	.destroy_inode = vxfs_destroy_inode,
>  	.evict_inode =		vxfs_evict_inode,
>  	.put_super =		vxfs_put_super,
>  	.statfs =		vxfs_statfs,
> @@ -153,6 +187,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
>  	u_long			bsize;
>  	struct inode *root;
>  	int ret = -EINVAL;
> +	int j;
>  
>  	sbp->s_flags |= MS_RDONLY;
>  
> @@ -168,7 +203,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
>  		goto out;
>  	}
>  
> -	bp = sb_bread(sbp, 1);
> +	bp = sb_bread(sbp, 8);
>  	if (!bp || !buffer_mapped(bp)) {
>  		if (!silent) {
>  			printk(KERN_WARNING
> @@ -178,32 +213,30 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
>  	}
>  
>  	rsbp = (struct vxfs_sb *)bp->b_data;
> -	if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
> +	if (be32_to_cpu(rsbp->vs_magic) != VXFS_SUPER_MAGIC) {
>  		if (!silent)
> -			printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
> +			printk(KERN_NOTICE "vxfs: WRONG superblock magic %08x\n", rsbp->vs_magic);
>  		goto out;
>  	}
>  
> -	if ((rsbp->vs_version < 2 || rsbp->vs_version > 4) && !silent) {
> -		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n",
> -		       rsbp->vs_version);
> +	j = be32_to_cpu(rsbp->vs_version);
> +	if ((j < 2 || j > 4) && !silent) {
> +		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j);
>  		goto out;
>  	}
>  
> -#ifdef DIAGNOSTIC
> -	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", rsbp->vs_version);
> -	printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize);
> -#endif
>  
> -	sbp->s_magic = rsbp->vs_magic;
> +	sbp->s_magic = be32_to_cpu(rsbp->vs_magic);
>  	sbp->s_fs_info = infp;
>  
>  	infp->vsi_raw = rsbp;
>  	infp->vsi_bp = bp;
> -	infp->vsi_oltext = rsbp->vs_oltext[0];
> -	infp->vsi_oltsize = rsbp->vs_oltsize;
> +	infp->vsi_oltext = be32_to_cpu(rsbp->vs_oltext[0]);
> +	infp->vsi_oltsize = be32_to_cpu(rsbp->vs_oltsize);
> +
> +	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", be32_to_cpu(rsbp->vs_version));
>  
> -	if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
> +	if (!sb_set_blocksize(sbp, be32_to_cpu(rsbp->vs_bsize))) {
>  		printk(KERN_WARNING "vxfs: unable to set final block size\n");
>  		goto out;
>  	}
> @@ -229,6 +262,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
>  		printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
>  		goto out_free_ilist;
>  	}
> +	printk(KERN_DEBUG "vxfs: blocksize: %d, oltext %d, oltsize %d\n", 

	White space

> +	    be32_to_cpu(rsbp->vs_bsize), infp->vsi_oltext, infp->vsi_oltsize);
>  
>  	return 0;
>  	
> @@ -237,6 +272,7 @@ out_free_ilist:
>  	vxfs_put_fake_inode(infp->vsi_ilist);
>  	vxfs_put_fake_inode(infp->vsi_stilist);
>  out:
> +	printk(KERN_ERR "vxfs: mount failed %d\n", ret);
>  	brelse(bp);
>  	kfree(infp);
>  	return ret;
> @@ -264,29 +300,22 @@ MODULE_ALIAS("vxfs");
>  static int __init
>  vxfs_init(void)
>  {
> -	int rv;
> +	int rc = vxfs_inode_info_cache(0);
>  
> -	vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
> -			sizeof(struct vxfs_inode_info), 0,
> -			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
> -	if (!vxfs_inode_cachep)
> -		return -ENOMEM;
> -	rv = register_filesystem(&vxfs_fs_type);
> -	if (rv < 0)
> -		kmem_cache_destroy(vxfs_inode_cachep);
> -	return rv;
> +	if (!rc) {
> +		rc = register_filesystem(&vxfs_fs_type);
> +		if (rc < 0)
> +			vxfs_inode_info_cache(1);
> +	}
> +	printk(KERN_DEBUG "%s: **** %s %s rc %d\n", __FUNCTION__, __DATE__, __TIME__, rc);
> +	return rc;
>  }
>  
>  static void __exit
>  vxfs_cleanup(void)
>  {
>  	unregister_filesystem(&vxfs_fs_type);
> -	/*
> -	 * Make sure all delayed rcu free inodes are flushed before we
> -	 * destroy cache.
> -	 */
> -	rcu_barrier();
> -	kmem_cache_destroy(vxfs_inode_cachep);
> +	vxfs_inode_info_cache(1);
>  }
>  
>  module_init(vxfs_init);
Christoph Hellwig May 23, 2016, 8:36 a.m. UTC | #2
Hi Krzysztof,

thanks for doing this work.  I did the vxfs work for SCO Unixware
file systems and never even looked at a HP-UX system.  Good to know that
it's useful for HP-UX as well with a few changes.

I'd love to merged it, but we should go through it a bit and make it
fit our normal kernel process and style.  I'm happy to help you on the
list or in personal mails with that.

Initial comments below:

> index c8a9265..9890a84 100644
> --- a/fs/freevxfs/vxfs.h
> +++ b/fs/freevxfs/vxfs.h
> @@ -2,6 +2,39 @@
>   * Copyright (c) 2000-2001 Christoph Hellwig.
>   * All rights reserved.
>   *
> + *
> + * (c) 2016 Krzysztof Blaszkowski.

Just add your copyrights on the top next to mine.

> + *       Many bug fixes, improvements & tests.
> + *
> + * These bugs and improvements were as follows:
> + *   - code not aware of cpu endianess and ondisk data is BE.
> + *   - misaligned structures read from block device
> + *   - wrong SB block number. default offset is 8kB
> + *   - kmem_cache_alloc() objectes released with kfree()
> + *   - inode.i_private released in evict_inode() callback.
> + *   - refactored vxfs_readdir() and vxfs_find_entry()
> + *
> + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> + * Example: */
> +// *  cksum mnt/usr/share/man/man3.Z/* 
> +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> +// *  cksum mnt/usr/local/doom/*
> +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> +// *  cksum mnt/usr/share/doc/*
> +// *  cksum mnt/usr/sprockets/lib/*
> +// *  cksum mnt/usr/sprockets/bin/*
> +/*
> + * Needles to say that checksums of files match these evaluated by
> + * HP-UX B.10.20 cksum. E.g.:
> + *  3457951056 4196020 /usr/local/doom/doom1.wad
> + *  2527157998 35344 /usr/local/doom/doomlaunch
> + *  2974998129 413696 /usr/local/doom/hpdoom

This just belongs into the git commit log and not into the file.


> + * The hpux_mdsetup tool project which is aimed at making possible
> + * accessing HP-UX logical volumes by device mapper is here:
> + *       https://sourceforge.net/projects/linux-vxfs/
> + *

I think this should just go into the Kconfig help text, or a
documentation text file if we want to add one.

>   * Redistribution and use in source and binary forms, with or without
>   * modification, are permitted provided that the following conditions
>   * are met:
> @@ -38,6 +71,10 @@
>   */
>  #include <linux/types.h>
>  
> +//#define DIAGNOSTIC
> +#undef DIAGNOSTIC
> +#undef DIAGNOSTIC_V2
> +#undef DIAGNOSTIC_V3
>  
>  /*
>   * Data types for use with the VxFS ondisk format.
> @@ -152,7 +189,7 @@ struct vxfs_sb {
>  	/*
>  	 * Actually much more...
>  	 */
> -};
> +} __attribute__((packed));

Can you explain why we need the packed annoation?  It should probably
be a patch on it's own and use __packed.

> +#ifdef DIAGNOSTIC
> +#define F_ENTER(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#define F_EXIT(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +
> +#ifdef DIAGNOSTIC_V2
> +#define F_ENTER_V2(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#define F_EXIT_V2(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#else
> +#define F_ENTER_V2(a, b...) 
> +#define F_EXIT_V2(a, b...) 
> +#endif
> +
> +#ifdef DIAGNOSTIC_V3
> +#define F_ENTER_V3(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#define F_EXIT_V3(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> +#else
> +#define F_ENTER_V3(a, b...) 
> +#define F_EXIT_V3(a, b...) 
> +#endif

Have you looked into ftrace for function tracing?  I'd prefer not to
add all these macros if we can avoid it.

>  	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);
> +		struct direct *d = vip->vii_ext4.ve4_direct + i; // cpu endian

no // comments for Linux kernel code please.  Also we should not need
comments about endianess.  Instead we should use sparse annotations
(see Documentation/sparse.txt for details).  We also have a few examples
for code that supports both little and big endian in a single driver
that way - take a look at the end of fs/sysv/sysv.h for an example.

> -		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
> +		bno = be32_to_cpu(indir[(bn/indsize) % (indsize*bn)]) + (bn%indsize);

This would break the existing Unixware support - we'll need helpers like
the one I just mentioned above instead.

> @@ -340,21 +436,61 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
>  static void vxfs_i_callback(struct rcu_head *head)
>  {
>  	struct inode *inode = container_of(head, struct inode, i_rcu);
> -	kmem_cache_free(vxfs_inode_cachep, inode->i_private);
> +	void *priv = inode->i_private;
> +
> +	inode->i_private = NULL;
> +	// just in case the same inode was used elsewhere after releasing i_private.
> +	// if it was then dereferencing NULL is far better than using invalid
> +	// pointer to memory claimed by something.
> +	kmem_cache_free(vxfs_inode_cachep, priv);
> +}
> +
> +void vxfs_destroy_inode(struct inode *ip)
> +{
> +	call_rcu(&ip->i_rcu, vxfs_i_callback);
> +}
> +
> +void vxfs_inode_info_free(struct vxfs_inode_info *vip)
> +{
> +	kmem_cache_free(vxfs_inode_cachep, vip);
>  }

Can you explain these changes?  Being able to explain each change in
the changelog is one of the reasons why we prefer multiple small
changes, one for each issue.

> +{
> +	int rc = 0;
> +
> +	if (!setup) {
> +		vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
> +			sizeof(struct vxfs_inode_info), 0,
> +			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
> +
> +		if (!vxfs_inode_cachep)
> +			rc = -ENOMEM;
> +	} else {
> +	/*
> +	 * Make sure all delayed rcu free inodes are flushed before we
> +	 * destroy cache.
> +	 */
> +		rcu_barrier();
> +		kmem_cache_destroy(vxfs_inode_cachep);
> +	}
> +
> +	return rc;
> +}

I don't think a function that does two different things depending on the
argument is a good idea.  I suspect you added it to keep
vxfs_inode_cachep static in this file?  I'm fine with that in general,
but please add two function for it then, and split it into a separate
patch.

>  #include <linux/stat.h>
>  #include <linux/vfs.h>
>  #include <linux/mount.h>
> +#include <linux/byteorder/generic.h>

Please use <asm/byteorder.h> instead.
--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Krzysztof Błaszkowski May 24, 2016, 8:48 a.m. UTC | #3
Hi Christoph,

Thank you for prompt response. Yes, please tell me what I should do to
complete this successfully. In the mean time I will look through the
rest of your reply.
I couldn't do this yesterday (drove 500km away from city I live in).

And my 1st thought of vxfs_fill_super() is that it should check sb magic
at two places +1k in case of SCO Unixware and +8k for HP-UX vxfs image
to preserve compatibility.
Also what is on-disk format of data written by SCO ? HP-UX 10.20 writes
everything big endian. (guess it's native to pa-risc 1.1)

The information can be utilized later to fine tune more corner case
issues with these two images of vxfs. e.g. for vxfs_bmap_ext4()

Best regards

On Mon, 2016-05-23 at 01:36 -0700, Christoph Hellwig wrote:
> Hi Krzysztof,
> 
> thanks for doing this work.  I did the vxfs work for SCO Unixware
> file systems and never even looked at a HP-UX system.  Good to know that
> it's useful for HP-UX as well with a few changes.
> 
> I'd love to merged it, but we should go through it a bit and make it
> fit our normal kernel process and style.  I'm happy to help you on the
> list or in personal mails with that.
> 
> Initial comments below:
> 
> > index c8a9265..9890a84 100644
> > --- a/fs/freevxfs/vxfs.h
> > +++ b/fs/freevxfs/vxfs.h
> > @@ -2,6 +2,39 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + *
> > + * (c) 2016 Krzysztof Blaszkowski.
> 
> Just add your copyrights on the top next to mine.
> 
> > + *       Many bug fixes, improvements & tests.
> > + *
> > + * These bugs and improvements were as follows:
> > + *   - code not aware of cpu endianess and ondisk data is BE.
> > + *   - misaligned structures read from block device
> > + *   - wrong SB block number. default offset is 8kB
> > + *   - kmem_cache_alloc() objectes released with kfree()
> > + *   - inode.i_private released in evict_inode() callback.
> > + *   - refactored vxfs_readdir() and vxfs_find_entry()
> > + *
> > + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> > + * Example: */
> > +// *  cksum mnt/usr/share/man/man3.Z/* 
> > +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> > +// *  cksum mnt/usr/local/doom/*
> > +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> > +// *  cksum mnt/usr/share/doc/*
> > +// *  cksum mnt/usr/sprockets/lib/*
> > +// *  cksum mnt/usr/sprockets/bin/*
> > +/*
> > + * Needles to say that checksums of files match these evaluated by
> > + * HP-UX B.10.20 cksum. E.g.:
> > + *  3457951056 4196020 /usr/local/doom/doom1.wad
> > + *  2527157998 35344 /usr/local/doom/doomlaunch
> > + *  2974998129 413696 /usr/local/doom/hpdoom
> 
> This just belongs into the git commit log and not into the file.
> 
> 
> > + * The hpux_mdsetup tool project which is aimed at making possible
> > + * accessing HP-UX logical volumes by device mapper is here:
> > + *       https://sourceforge.net/projects/linux-vxfs/
> > + *
> 
> I think this should just go into the Kconfig help text, or a
> documentation text file if we want to add one.
> 
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -38,6 +71,10 @@
> >   */
> >  #include <linux/types.h>
> >  
> > +//#define DIAGNOSTIC
> > +#undef DIAGNOSTIC
> > +#undef DIAGNOSTIC_V2
> > +#undef DIAGNOSTIC_V3
> >  
> >  /*
> >   * Data types for use with the VxFS ondisk format.
> > @@ -152,7 +189,7 @@ struct vxfs_sb {
> >  	/*
> >  	 * Actually much more...
> >  	 */
> > -};
> > +} __attribute__((packed));
> 
> Can you explain why we need the packed annoation?  It should probably
> be a patch on it's own and use __packed.
> 
> > +#ifdef DIAGNOSTIC
> > +#define F_ENTER(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#define F_EXIT(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +
> > +#ifdef DIAGNOSTIC_V2
> > +#define F_ENTER_V2(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#define F_EXIT_V2(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#else
> > +#define F_ENTER_V2(a, b...) 
> > +#define F_EXIT_V2(a, b...) 
> > +#endif
> > +
> > +#ifdef DIAGNOSTIC_V3
> > +#define F_ENTER_V3(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#define F_EXIT_V3(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#else
> > +#define F_ENTER_V3(a, b...) 
> > +#define F_EXIT_V3(a, b...) 
> > +#endif
> 
> Have you looked into ftrace for function tracing?  I'd prefer not to
> add all these macros if we can avoid it.
> 
> >  	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);
> > +		struct direct *d = vip->vii_ext4.ve4_direct + i; // cpu endian
> 
> no // comments for Linux kernel code please.  Also we should not need
> comments about endianess.  Instead we should use sparse annotations
> (see Documentation/sparse.txt for details).  We also have a few examples
> for code that supports both little and big endian in a single driver
> that way - take a look at the end of fs/sysv/sysv.h for an example.
> 
> > -		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
> > +		bno = be32_to_cpu(indir[(bn/indsize) % (indsize*bn)]) + (bn%indsize);
> 
> This would break the existing Unixware support - we'll need helpers like
> the one I just mentioned above instead.
> 
> > @@ -340,21 +436,61 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
> >  static void vxfs_i_callback(struct rcu_head *head)
> >  {
> >  	struct inode *inode = container_of(head, struct inode, i_rcu);
> > -	kmem_cache_free(vxfs_inode_cachep, inode->i_private);
> > +	void *priv = inode->i_private;
> > +
> > +	inode->i_private = NULL;
> > +	// just in case the same inode was used elsewhere after releasing i_private.
> > +	// if it was then dereferencing NULL is far better than using invalid
> > +	// pointer to memory claimed by something.
> > +	kmem_cache_free(vxfs_inode_cachep, priv);
> > +}
> > +
> > +void vxfs_destroy_inode(struct inode *ip)
> > +{
> > +	call_rcu(&ip->i_rcu, vxfs_i_callback);
> > +}
> > +
> > +void vxfs_inode_info_free(struct vxfs_inode_info *vip)
> > +{
> > +	kmem_cache_free(vxfs_inode_cachep, vip);
> >  }
> 
> Can you explain these changes?  Being able to explain each change in
> the changelog is one of the reasons why we prefer multiple small
> changes, one for each issue.
> 
> > +{
> > +	int rc = 0;
> > +
> > +	if (!setup) {
> > +		vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
> > +			sizeof(struct vxfs_inode_info), 0,
> > +			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
> > +
> > +		if (!vxfs_inode_cachep)
> > +			rc = -ENOMEM;
> > +	} else {
> > +	/*
> > +	 * Make sure all delayed rcu free inodes are flushed before we
> > +	 * destroy cache.
> > +	 */
> > +		rcu_barrier();
> > +		kmem_cache_destroy(vxfs_inode_cachep);
> > +	}
> > +
> > +	return rc;
> > +}
> 
> I don't think a function that does two different things depending on the
> argument is a good idea.  I suspect you added it to keep
> vxfs_inode_cachep static in this file?  I'm fine with that in general,
> but please add two function for it then, and split it into a separate
> patch.
> 
> >  #include <linux/stat.h>
> >  #include <linux/vfs.h>
> >  #include <linux/mount.h>
> > +#include <linux/byteorder/generic.h>
> 
> Please use <asm/byteorder.h> instead.
Krzysztof Błaszkowski May 24, 2016, 11:50 a.m. UTC | #4
Hi,

Yes, I think I can do this.
Sure, will use the script.

I reckon that this process will take more time than I expect because of
preserving functionality of SCO.

On Mon, 2016-05-23 at 10:23 +0200, Carlos Maiolino wrote:
> On Sun, May 22, 2016 at 05:13:14PM +0200, Krzysztof Błaszkowski wrote:
> > Hello All,
> > 
> > I recently gave a try to vxfs (veritas fs) which is common to HP-UX and
> > it turned out that the module has been broken for very long time.
> > 
> > I fixed several issues with current freevxfs and also designed a
> > userspace tool which helps creating dm block devices from e.g. regular
> > file with raw image of hp-ux disk.
> > https://sourceforge.net/projects/linux-vxfs/
> > 
> > 
> > I send the patch because I believe that some people would appreciate
> > support for this vintage file system (e.g. me) and also it will be nice
> > to see my name in the kernel.
> > 
> 
> Hi,
> 
> - Can you please split this patch into individual patches fixing each specific
>   problem? It's easier to review, instead of a big patch with several fixes into
>   it.
> 
> - Also, as a quick view, there are a lot of trailing white spaces over the whole
>   patch, which, should be removed.
> 
>   you can use the scripts/checkpatch.pl script to check your patches and see
>   match at least the basics requirements for sending patches to kernel and, a
>   read of Documentation/SubmittingPatches is interesting too.
> 
> > Regards,
> > 
> > -- 
> > Krzysztof Blaszkowski
> 
> > diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
> > index c8a9265..9890a84 100644
> > --- a/fs/freevxfs/vxfs.h
> > +++ b/fs/freevxfs/vxfs.h
> > @@ -2,6 +2,39 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + *
> > + * (c) 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests.
> > + *
> > + * These bugs and improvements were as follows:
> > + *   - code not aware of cpu endianess and ondisk data is BE.
> > + *   - misaligned structures read from block device
> > + *   - wrong SB block number. default offset is 8kB
> > + *   - kmem_cache_alloc() objectes released with kfree()
> > + *   - inode.i_private released in evict_inode() callback.
> > + *   - refactored vxfs_readdir() and vxfs_find_entry()
> > + *
> > + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> > + * Example: */
> > +// *  cksum mnt/usr/share/man/man3.Z/* 
> > +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> > +// *  cksum mnt/usr/local/doom/*
> > +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> > +// *  cksum mnt/usr/share/doc/*
> > +// *  cksum mnt/usr/sprockets/lib/*
> > +// *  cksum mnt/usr/sprockets/bin/*
> > +/*
> 
> Don't use //
> 
> > + * Needles to say that checksums of files match these evaluated by
> > + * HP-UX B.10.20 cksum. E.g.:
> > + *  3457951056 4196020 /usr/local/doom/doom1.wad
> > + *  2527157998 35344 /usr/local/doom/doomlaunch
> > + *  2974998129 413696 /usr/local/doom/hpdoom
> > + *
> > + * The hpux_mdsetup tool project which is aimed at making possible
> > + * accessing HP-UX logical volumes by device mapper is here:
> > + *       https://sourceforge.net/projects/linux-vxfs/
> > + *
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -38,6 +71,10 @@
> >   */
> >  #include <linux/types.h>
> >  
> > +//#define DIAGNOSTIC
> > +#undef DIAGNOSTIC
> > +#undef DIAGNOSTIC_V2
> > +#undef DIAGNOSTIC_V3
> >  
> >  /*
> >   * Data types for use with the VxFS ondisk format.
> > @@ -152,7 +189,7 @@ struct vxfs_sb {
> >  	/*
> >  	 * Actually much more...
> >  	 */
> > -};
> > +} __attribute__((packed));
> >  
> >  
> >  /*
> > @@ -260,4 +297,35 @@ enum {
> >  #define VXFS_SBI(sbp) \
> >  	((struct vxfs_sb_info *)(sbp)->s_fs_info)
> >  
> > +
> > +#ifdef DIAGNOSTIC
> > +#define F_ENTER(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#define F_EXIT(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +
> > +#ifdef DIAGNOSTIC_V2
> > +#define F_ENTER_V2(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#define F_EXIT_V2(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#else
> > +#define F_ENTER_V2(a, b...) 
> > +#define F_EXIT_V2(a, b...) 
> > +#endif
> > +
> > +#ifdef DIAGNOSTIC_V3
> > +#define F_ENTER_V3(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#define F_EXIT_V3(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
> > +#else
> > +#define F_ENTER_V3(a, b...) 
> > +#define F_EXIT_V3(a, b...) 
> > +#endif
> > +
> > +#else // DIAGNOSTIC
> > +#define F_ENTER(a, b...) 
> > +#define F_EXIT(a, b...) 
> > +#define F_ENTER_V2(a, b...) 
> > +#define F_EXIT_V2(a, b...) 
> > +#define F_ENTER_V3(a, b...) 
> > +#define F_EXIT_V3(a, b...) 
> > +#endif
> > +
> 
> Lots of trailing white spaces here
> 
> > +
> >  #endif /* _VXFS_SUPER_H_ */
> > diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c
> > index f86fd3c..58e6a17 100644
> > --- a/fs/freevxfs/vxfs_bmap.c
> > +++ b/fs/freevxfs/vxfs_bmap.c
> > @@ -2,6 +2,10 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + *
> > + * 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -39,17 +43,6 @@
> >  #include "vxfs_extern.h"
> >  
> >  
> > -#ifdef DIAGNOSTIC
> > -static void
> > -vxfs_typdump(struct vxfs_typed *typ)
> > -{
> > -	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
> > -	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
> > -	printk("block=%x ", typ->vt_block);
> > -	printk("size=%x\n", typ->vt_size);
> > -}
> > -#endif
> > -
> >  /**
> >   * vxfs_bmap_ext4 - do bmap for ext4 extents
> >   * @ip:		pointer to the inode we do bmap for
> > @@ -71,18 +64,23 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
> >  	unsigned long bsize = sb->s_blocksize;
> >  	u32 indsize = vip->vii_ext4.ve4_indsize;
> >  	int i;
> > +	daddr_t rc = 0;
> > +
> > +	F_ENTER_V2();
> >  
> >  	if (indsize > sb->s_blocksize)
> >  		goto fail_size;
> >  
> >  	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);
> > +		struct direct *d = vip->vii_ext4.ve4_direct + i; // cpu endian
> > +		if (bn >= 0 && bn < d->size) {
> > +			rc = bn + d->extent;
> > +			break;
> > +		}
> >  		bn -= d->size;
> >  	}
> >  
> > -	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
> > +	if (!rc && ((bn / (indsize * indsize * bsize / 4)) == 0)) {
> >  		struct buffer_head *buf;
> >  		daddr_t	bno;
> >  		u32 *indir;
> > @@ -92,18 +90,21 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
> >  			goto fail_buf;
> >  
> >  		indir = (u32 *)buf->b_data;
> > -		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
> > +		bno = be32_to_cpu(indir[(bn/indsize) % (indsize*bn)]) + (bn%indsize);
> >  
> >  		brelse(buf);
> > -		return bno;
> > -	} else
> > -		printk(KERN_WARNING "no matching indir?");
> > +		rc = bno;
> > +	}
> > +	if (!rc)
> > +		printk(KERN_WARNING "%s:%d no matching indir?\n", __FUNCTION__, __LINE__);
> >  
> > -	return 0;
> > +	F_EXIT_V2("pblk %d", rc);
> > +	return rc;
> >  
> >  fail_size:
> >  	printk("vxfs: indirect extent too big!\n");
> >  fail_buf:
> > +	F_EXIT();
> >  	return 0;
> >  }
> >  
> > @@ -129,51 +130,53 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
> >  {
> >  	struct buffer_head		*bp = NULL;
> >  	daddr_t				pblock = 0;
> > -	int				i;
> > +	int i;
> >  
> > +	F_ENTER_V2();
> >  	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
> >  		struct vxfs_typed	*typ;
> > -		int64_t			off;
> > +		int64_t off;
> >  
> >  		bp = sb_bread(ip->i_sb,
> >  				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
> >  		if (!bp || !buffer_mapped(bp))
> > -			return 0;
> > +			break;
> >  
> >  		typ = ((struct vxfs_typed *)bp->b_data) +
> >  			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
> > -		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
> > +		off = be64_to_cpu(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)(be64_to_cpu(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, be32_to_cpu(typ->vt_block),
> > +					be32_to_cpu(typ->vt_size), block - off);
> >  			if (pblock == -2)
> >  				break;
> >  			goto out;
> >  		case VXFS_TYPED_DATA:
> > -			if ((block - off) >= typ->vt_size)
> > +			if ((block - off) >= be32_to_cpu(typ->vt_size))
> >  				break;
> > -			pblock = (typ->vt_block + block - off);
> > +			pblock = be32_to_cpu(typ->vt_block) + block - off;
> >  			goto out;
> >  		case VXFS_TYPED_INDIRECT_DEV4:
> >  		case VXFS_TYPED_DATA_DEV4: {
> >  			struct vxfs_typed_dev4	*typ4 =
> >  				(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_ERR "%s:%d TYPED_DEV4 detected!. block: %Lu\tsize: %Ld\tdev: %d\n",
> > +				__FUNCTION__, __LINE__,
> > +			       (unsigned long long) be64_to_cpu(typ4->vd4_block),
> > +			       (unsigned long long) be64_to_cpu(typ4->vd4_size),
> > +			       be32_to_cpu(typ4->vd4_dev));
> >  			goto fail;
> >  		}
> >  		default:
> > +			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __FUNCTION__, __LINE__, be64_to_cpu(typ->vt_hdr));
> >  			BUG();
> >  		}
> >  		brelse(bp);
> > @@ -182,7 +185,9 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
> >  fail:
> >  	pblock = 0;
> >  out:
> > -	brelse(bp);
> > +	if (bp)
> > +		brelse(bp);
> > +	F_EXIT_V2();
> >  	return (pblock);
> >  }
> >  
> > @@ -200,16 +205,18 @@ out:
> >  static daddr_t
> >  vxfs_bmap_typed(struct inode *ip, long iblock)
> >  {
> > -	struct vxfs_inode_info		*vip = VXFS_INO(ip);
> > -	daddr_t				pblock = 0;
> > -	int				i;
> > +	struct vxfs_inode_info *vip = VXFS_INO(ip);
> > +	daddr_t pblock = 0;
> > +	int i;
> >  
> > +	F_ENTER_V2();
> >  	for (i = 0; i < VXFS_NTYPED; i++) {
> > -		struct vxfs_typed	*typ = vip->vii_org.typed + i;
> > +		struct vxfs_typed	*typ = vip->vii_org.typed + i; // cpu endian
> >  		int64_t			off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
> >  
> > -#ifdef DIAGNOSTIC
> > -		vxfs_typdump(typ);
> > +#ifdef DIAGNOSTIC_V2
> > +		printk(KERN_DEBUG "%s:%d type=%Lu, ofs=0x%Lx, blk=%d, size=%d\n", __FUNCTION__, __LINE__,
> > +			typ->vt_hdr >> VXFS_TYPED_TYPESHIFT, off, typ->vt_block, typ->vt_size );
> >  #endif
> >  		if (iblock < off)
> >  			continue;
> > @@ -219,29 +226,36 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
> >  					typ->vt_size, iblock - off);
> >  			if (pblock == -2)
> >  				break;
> > -			return (pblock);
> > +			goto out;
> > +
> >  		case VXFS_TYPED_DATA:
> > -			if ((iblock - off) < typ->vt_size)
> > -				return (typ->vt_block + iblock - off);
> > +			if ((iblock - off) < typ->vt_size) {
> > +				pblock = typ->vt_block + iblock - off;
> > +				goto out;
> > +			}
> >  			break;
> >  		case VXFS_TYPED_INDIRECT_DEV4:
> >  		case VXFS_TYPED_DATA_DEV4: {
> >  			struct vxfs_typed_dev4	*typ4 =
> >  				(struct vxfs_typed_dev4 *)typ;
> >  
> > -			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
> > -			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
> > +			printk(KERN_ERR "%s:%d TYPED_DEV4 detected!. block: %Lu\tsize: %Ld\tdev: %d\n",
> > +				__FUNCTION__, __LINE__,
> >  			       (unsigned long long) typ4->vd4_block,
> >  			       (unsigned long long) typ4->vd4_size,
> >  			       typ4->vd4_dev);
> > -			return 0;
> > +			pblock = 0;
> > +			goto out;
> >  		}
> >  		default:
> > +			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __FUNCTION__, __LINE__, typ->vt_hdr);
> >  			BUG();
> >  		}
> >  	}
> >  
> > -	return 0;
> > +out:
> > +	F_EXIT_V2("pblk %d", pblock);
> > +	return pblock;
> >  }
> >  
> >  /**
> > @@ -270,12 +284,14 @@ vxfs_bmap1(struct inode *ip, long iblock)
> >  	if (VXFS_ISIMMED(vip))
> >  		goto unsupp;
> >  
> > -	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
> > -			ip->i_ino, vip->vii_orgtype);
> > +	printk(KERN_ERR "%s:%d inode %ld has no valid orgtype (%x)\n",
> > +		__FUNCTION__, __LINE__,
> > +		ip->i_ino, vip->vii_orgtype);
> >  	BUG();
> >  
> >  unsupp:
> > -	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
> > -			ip->i_ino, vip->vii_orgtype);
> > +	printk(KERN_WARNING "%s:%d inode %ld has an unsupported orgtype (%x)\n",
> > +		__FUNCTION__, __LINE__,
> > +		ip->i_ino, vip->vii_orgtype);
> >  	return 0;
> >  }
> > diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h
> > index aaf1fb0..d8b52e6 100644
> > --- a/fs/freevxfs/vxfs_dir.h
> > +++ b/fs/freevxfs/vxfs_dir.h
> > @@ -84,9 +84,5 @@ struct vxfs_direct {
> >  #define VXFS_DIRROUND(len)	((VXFS_DIRPAD + (len) - 1) & ~(VXFS_DIRPAD -1))
> >  #define VXFS_DIRLEN(len)	(VXFS_DIRROUND(VXFS_NAMEMIN + (len)))
> >  
> > -/*
> > - * VXFS_DIRBLKOV is the overhead of a specific dirblock.
> > - */
> > -#define VXFS_DIRBLKOV(dbp)	((sizeof(short) * dbp->d_nhash) + 4)
> >  
> >  #endif /* _VXFS_DIR_H_ */
> > diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
> > index 881aa3d..3d20421 100644
> > --- a/fs/freevxfs/vxfs_extern.h
> > +++ b/fs/freevxfs/vxfs_extern.h
> > @@ -55,7 +55,7 @@ extern const struct inode_operations vxfs_immed_symlink_iops;
> >  
> >  /* vxfs_inode.c */
> >  extern const struct address_space_operations vxfs_immed_aops;
> > -extern struct kmem_cache	*vxfs_inode_cachep;
> > +//extern struct kmem_cache	*vxfs_inode_cachep;
> >  extern void			vxfs_dumpi(struct vxfs_inode_info *, ino_t);
> >  extern struct inode *		vxfs_get_fake_inode(struct super_block *,
> >  					struct vxfs_inode_info *);
> > @@ -64,6 +64,10 @@ extern struct vxfs_inode_info *	vxfs_blkiget(struct super_block *, u_long, ino_t
> >  extern struct vxfs_inode_info *	vxfs_stiget(struct super_block *, ino_t);
> >  extern struct inode *		vxfs_iget(struct super_block *, ino_t);
> >  extern void			vxfs_evict_inode(struct inode *);
> > +extern void vxfs_destroy_inode(struct inode *ip);
> > +extern void vxfs_inode_info_free(struct vxfs_inode_info *vip);
> > +extern int vxfs_inode_info_cache(int setup);
> > +
> >  
> >  /* vxfs_lookup.c */
> >  extern const struct inode_operations	vxfs_dir_inode_ops;
> > diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c
> > index c9a6a94..69fcd7f 100644
> > --- a/fs/freevxfs/vxfs_fshead.c
> > +++ b/fs/freevxfs/vxfs_fshead.c
> > @@ -2,6 +2,35 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + *
> > + * (c) 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests.
> > + *
> > + * These bugs and improvements were as follows:
> > + *   - code not aware of cpu endianess and ondisk data is BE.
> > + *   - misaligned structures read from block device
> > + *   - wrong SB block number. default offset is 8kB
> > + *   - kmem_cache_alloc() objectes released with kfree()
> > + *   - inode.i_private released in evict_inode() callback.
> > + *   - refactored vxfs_readdir() and vxfs_find_entry()
> > + *
> > + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> > + * Example: */
> > +// *  cksum mnt/usr/share/man/man3.Z/* 
> > +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> 
> More white spaces and more //
> 
> > +// *  cksum mnt/usr/local/doom/*
> > +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> > +// *  cksum mnt/usr/share/doc/*
> > +// *  cksum mnt/usr/sprockets/lib/*
> > +// *  cksum mnt/usr/sprockets/bin/*
> > +/*
> > + * Needles to say that checksums of files match these evaluated by
> > + * HP-UX B.10.20 cksum. E.g.:
> > + *  3457951056 4196020 /usr/local/doom/doom1.wad
> > + *  2527157998 35344 /usr/local/doom/doomlaunch
> > + *  2974998129 413696 /usr/local/doom/hpdoom
> > + *
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -60,6 +89,34 @@ vxfs_dumpfsh(struct vxfs_fsh *fhp)
> >  }
> >  #endif
> >  
> > +#define VXFS_BE32(field1, field2) fhp->field1 = be32_to_cpu(dbh->field2)
> > +
> > +
> > +static void inline dbh2fhp(struct vxfs_fsh *fhp, void *_dbh)
> > +{
> > +#ifdef __LITTLE_ENDIAN
> > +	struct vxfs_fsh *dbh = (struct vxfs_fsh *)_dbh;
> > +
> > +	VXFS_BE32(fsh_version, fsh_version);
> > +	VXFS_BE32(fsh_fsindex, fsh_fsindex);
> > +	VXFS_BE32(fsh_time, fsh_time);
> > +	VXFS_BE32(fsh_utime, fsh_utime);
> > +	VXFS_BE32(fsh_extop, fsh_extop);
> > +	VXFS_BE32(fsh_ninodes, fsh_ninodes);
> > +	VXFS_BE32(fsh_nau, fsh_nau);
> > +	VXFS_BE32(fsh_old_ilesize, fsh_old_ilesize);
> > +	VXFS_BE32(fsh_dflags, fsh_dflags);
> > +	VXFS_BE32(fsh_quota, fsh_quota);
> > +	VXFS_BE32(fsh_maxinode, fsh_maxinode);
> > +	VXFS_BE32(fsh_iauino, fsh_iauino);
> > +	VXFS_BE32(fsh_ilistino[0], fsh_ilistino[0]);
> > +	VXFS_BE32(fsh_ilistino[1], fsh_ilistino[1]);
> > +	VXFS_BE32(fsh_lctino, fsh_lctino);
> > +#else
> > +	memcpy(fhp, _dbh, sizeof(*fhp));
> > +#endif
> > +}
> > +
> >  /**
> >   * vxfs_getfsh - read fileset header into memory
> >   * @ip:		the (fake) fileset header inode
> > @@ -83,7 +140,8 @@ vxfs_getfsh(struct inode *ip, int which)
> >  
> >  		if (!(fhp = kmalloc(sizeof(*fhp), GFP_KERNEL)))
> >  			goto out;
> > -		memcpy(fhp, bp->b_data, sizeof(*fhp));
> > +
> > +		dbh2fhp(fhp, bp->b_data);
> >  
> >  		put_bh(bp);
> >  		return (fhp);
> > @@ -110,9 +168,12 @@ vxfs_read_fshead(struct super_block *sbp)
> >  	struct vxfs_fsh			*pfp, *sfp;
> >  	struct vxfs_inode_info		*vip, *tip;
> >  
> > +	F_ENTER();
> > +
> >  	vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
> >  	if (!vip) {
> >  		printk(KERN_ERR "vxfs: unable to read fsh inode\n");
> > +		F_EXIT();
> >  		return -EINVAL;
> >  	}
> >  	if (!VXFS_ISFSH(vip)) {
> > @@ -121,10 +182,8 @@ vxfs_read_fshead(struct super_block *sbp)
> >  		goto out_free_fship;
> >  	}
> >  
> > -
> >  #ifdef DIAGNOSTIC
> > -	printk("vxfs: fsh inode dump:\n");
> > -	vxfs_dumpi(vip, infp->vsi_fshino);
> > +	printk("%s:%d\n", __FUNCTION__, __LINE__);
> >  #endif
> >  
> >  	infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
> > @@ -160,7 +219,7 @@ vxfs_read_fshead(struct super_block *sbp)
> >  	infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
> >  	if (!infp->vsi_stilist) {
> >  		printk(KERN_ERR "vxfs: unable to get structural list inode\n");
> > -		kfree(tip);
> > +		vxfs_inode_info_free(tip);
> >  		goto out_free_pfp;
> >  	}
> >  	if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
> > @@ -175,7 +234,7 @@ vxfs_read_fshead(struct super_block *sbp)
> >  	infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
> >  	if (!infp->vsi_ilist) {
> >  		printk(KERN_ERR "vxfs: unable to get inode list inode\n");
> > -		kfree(tip);
> > +		vxfs_inode_info_free(tip);
> >  		goto out_iput_stilist;
> >  	}
> >  	if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
> > @@ -184,6 +243,7 @@ vxfs_read_fshead(struct super_block *sbp)
> >  		goto out_iput_ilist;
> >  	}
> >  
> > +	F_EXIT();
> >  	return 0;
> >  
> >   out_iput_ilist:
> > @@ -196,8 +256,10 @@ vxfs_read_fshead(struct super_block *sbp)
> >   	kfree(sfp);
> >   out_iput_fship:
> >  	iput(infp->vsi_fship);
> > +	F_EXIT();
> >  	return -EINVAL;
> >   out_free_fship:
> > - 	kfree(vip);
> > +	vxfs_inode_info_free(vip);
> > +	F_EXIT();
> >  	return -EINVAL;
> >  }
> > diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
> > index 363e3ae..84dec28 100644
> > --- a/fs/freevxfs/vxfs_inode.c
> > +++ b/fs/freevxfs/vxfs_inode.c
> > @@ -2,6 +2,34 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + *
> > + * (c) 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests.
> > + *
> > + * These bugs and improvements were as follows:
> > + *   - code not aware of cpu endianess and ondisk data is BE.
> > + *   - misaligned structures read from block device
> > + *   - wrong SB block number. default offset is 8kB
> > + *   - kmem_cache_alloc() objectes released with kfree()
> > + *   - inode.i_private released in evict_inode() callback.
> > + *   - refactored vxfs_readdir() and vxfs_find_entry()
> > + *
> > + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> > + * Example: */
> > +// *  cksum mnt/usr/share/man/man3.Z/* 
> > +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> 
> More white spaces and more //
> 
> > +// *  cksum mnt/usr/local/doom/*
> > +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> > +// *  cksum mnt/usr/share/doc/*
> > +// *  cksum mnt/usr/sprockets/lib/*
> > +// *  cksum mnt/usr/sprockets/bin/*
> > +/*
> > + * Needles to say that checksums of files match these evaluated by
> > + * HP-UX B.10.20 cksum. E.g.:
> > + *  3457951056 4196020 /usr/local/doom/doom1.wad
> > + *  2527157998 35344 /usr/local/doom/doomlaunch
> > + *  2974998129 413696 /usr/local/doom/hpdoom
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -41,7 +69,7 @@
> >  #include "vxfs_extern.h"
> >  
> >  
> > -struct kmem_cache		*vxfs_inode_cachep;
> > +static struct kmem_cache *vxfs_inode_cachep;
> >  
> >  
> >  #ifdef DIAGNOSTIC
> > @@ -51,23 +79,88 @@ struct kmem_cache		*vxfs_inode_cachep;
> >  void
> >  vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
> >  {
> > -	printk(KERN_DEBUG "\n\n");
> > -	if (ino)
> > -		printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino);
> > +#ifdef DIAGNOSTIC_V2
> > +	if (ino && vip)
> > +		printk(KERN_DEBUG "\nvxfs inode %ld dump **** %p\n", ino, vip);
> >  	else
> > -		printk(KERN_DEBUG "dumping unknown vxfs inode\n");
> > +		printk(KERN_DEBUG "\ndumping unknown vxfs inode %p\n", vip);
> >  
> > -	printk(KERN_DEBUG "---------------------------\n");
> > -	printk(KERN_DEBUG "mode is %x\n", vip->vii_mode);
> > -	printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n",
> > -			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
> > -	printk(KERN_DEBUG "size:%Lx, blocks:%u\n",
> > +	if (vip) {
> > +		printk(KERN_DEBUG " * mode: %x, type %d\n", vip->vii_mode, vip->vii_orgtype);
> > +		printk(KERN_DEBUG " * size:%Lx, blocks:%u\n",
> >  			vip->vii_size, vip->vii_blocks);
> > -	printk(KERN_DEBUG "orgtype:%u\n", vip->vii_orgtype);
> > +		printk(KERN_DEBUG " * nlink:%u, uid:%u, gid:%u\n",
> > +			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
> > +	}
> > +#endif
> >  }
> >  #endif
> >  
> >  
> > +#define VXFS_BE32(field1, field2) vip->field1 = be32_to_cpu(dip->field2)
> > +#define VXFS_BE64(field1, field2) vip->field1 = be64_to_cpu(dip->field2)
> > +#define VXFS_BE16(field1, field2) vip->field1 = be16_to_cpu(dip->field2)
> > +
> > +
> > +static void inline dip2vip_cpy(struct vxfs_inode_info *vip, struct vxfs_dinode *dip)
> > +{
> > +#ifdef __LITTLE_ENDIAN
> > +	int j;
> > +
> > +	VXFS_BE32(vdi_mode, vdi_mode);
> > +	VXFS_BE32(vdi_nlink, vdi_nlink);
> > +	VXFS_BE32(vdi_uid, vdi_uid);
> > +	VXFS_BE32(vdi_gid, vdi_gid);
> > +	VXFS_BE64(vdi_size, vdi_size);
> > +	VXFS_BE32(vdi_atime, vdi_atime);
> > +	VXFS_BE32(vdi_autime, vdi_autime);
> > +	VXFS_BE32(vdi_mtime, vdi_mtime);
> > +	VXFS_BE32(vdi_mutime, vdi_mutime);
> > +	VXFS_BE32(vdi_ctime, vdi_ctime);
> > +	VXFS_BE32(vdi_cutime, vdi_cutime);
> > +	vip->vdi_aflags = dip->vdi_aflags;
> > +	vip->vdi_orgtype = dip->vdi_orgtype;
> > +	VXFS_BE16(vdi_eopflags, vdi_eopflags);
> > +	VXFS_BE32(vdi_eopdata, vdi_eopdata);
> > +
> > +	VXFS_BE32(vdi_ftarea.i_regular.reserved, vdi_ftarea.i_regular.reserved);
> > +	VXFS_BE32(vdi_ftarea.i_regular.fixextsize, vdi_ftarea.i_regular.fixextsize);
> > +	VXFS_BE32(vdi_blocks, vdi_blocks);
> > +	VXFS_BE32(vdi_gen, vdi_gen);
> > +	VXFS_BE64(vdi_version, vdi_version);
> > +
> > +	switch (dip->vdi_orgtype) {
> > +	case VXFS_ORG_EXT4:
> > +		VXFS_BE32(vdi_org.ext4.ve4_spare, vdi_org.ext4.ve4_spare);
> > +		VXFS_BE32(vdi_org.ext4.ve4_indsize, vdi_org.ext4.ve4_indsize);
> > +		for (j = 0; j < VXFS_NIADDR; j++) {
> > +			VXFS_BE32(vdi_org.ext4.ve4_indir[j], vdi_org.ext4.ve4_indir[j]);
> > +		}
> > +		for (j = 0; j < VXFS_NDADDR; j++) {
> > +			VXFS_BE32(vdi_org.ext4.ve4_direct[j].extent, vdi_org.ext4.ve4_direct[j].extent);
> > +			VXFS_BE32(vdi_org.ext4.ve4_direct[j].size, vdi_org.ext4.ve4_direct[j].size);
> > +		}
> > +		break;
> > +	case VXFS_ORG_IMMED:
> > +		memcpy(&vip->vdi_org.immed, &dip->vdi_org.immed, sizeof(vip->vdi_org.immed));
> > +		break;
> > +	case VXFS_ORG_TYPED:
> > +		for (j = 0; j < VXFS_NTYPED; j++) {
> > +			VXFS_BE64(vdi_org.typed[j].vt_hdr, vdi_org.typed[j].vt_hdr);
> > +			VXFS_BE32(vdi_org.typed[j].vt_block, vdi_org.typed[j].vt_block);
> > +			VXFS_BE32(vdi_org.typed[j].vt_size, vdi_org.typed[j].vt_size);
> > +		}
> > +		break;
> > +	
> > +	};
> > +
> > +	VXFS_BE32(vdi_iattrino, vdi_iattrino);
> > +#else
> > +	memcpy(vip, dip, sizeof(*vip));
> > +#endif
> > +}
> > +
> > +
> >  /**
> >   * vxfs_blkiget - find inode based on extent #
> >   * @sbp:	superblock of the filesystem we search in
> > @@ -84,6 +177,9 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
> >   *  buffercache.  This function should not be used outside the
> >   *  read_super() method, otherwise the data may be incoherent.
> >   */
> > +
> > +
> > +
> >  struct vxfs_inode_info *
> >  vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
> >  {
> > @@ -101,7 +197,7 @@ vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
> >  		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
> >  			goto fail;
> >  		dip = (struct vxfs_dinode *)(bp->b_data + offset);
> > -		memcpy(vip, dip, sizeof(*vip));
> > +		dip2vip_cpy(vip, dip);
> >  #ifdef DIAGNOSTIC
> >  		vxfs_dumpi(vip, ino);
> >  #endif
> > @@ -143,7 +239,7 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
> >  		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
> >  			goto fail;
> >  		dip = (struct vxfs_dinode *)(kaddr + offset);
> > -		memcpy(vip, dip, sizeof(*vip));
> > +		dip2vip_cpy(vip, dip);
> >  #ifdef DIAGNOSTIC
> >  		vxfs_dumpi(vip, ino);
> >  #endif
> > @@ -190,7 +286,7 @@ vxfs_stiget(struct super_block *sbp, ino_t ino)
> >  static __inline__ umode_t
> >  vxfs_transmod(struct vxfs_inode_info *vip)
> >  {
> > -	umode_t			ret = vip->vii_mode & ~VXFS_TYPE_MASK;
> > +	umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK;
> >  
> >  	if (VXFS_ISFIFO(vip))
> >  		ret |= S_IFIFO;
> > @@ -340,21 +436,61 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
> >  static void vxfs_i_callback(struct rcu_head *head)
> >  {
> >  	struct inode *inode = container_of(head, struct inode, i_rcu);
> > -	kmem_cache_free(vxfs_inode_cachep, inode->i_private);
> > +	void *priv = inode->i_private;
> > +
> > +	inode->i_private = NULL;
> > +	// just in case the same inode was used elsewhere after releasing i_private.
> > +	// if it was then dereferencing NULL is far better than using invalid
> > +	// pointer to memory claimed by something.
> > +	kmem_cache_free(vxfs_inode_cachep, priv);
> > +}
> > +
> > +void vxfs_destroy_inode(struct inode *ip)
> > +{
> > +	call_rcu(&ip->i_rcu, vxfs_i_callback);
> > +}
> > +
> > +void vxfs_inode_info_free(struct vxfs_inode_info *vip)
> > +{
> > +	kmem_cache_free(vxfs_inode_cachep, vip);
> >  }
> >  
> > +
> >  /**
> >   * vxfs_evict_inode - remove inode from main memory
> >   * @ip:		inode to discard.
> >   *
> >   * Description:
> > - *  vxfs_evict_inode() is called on the final iput and frees the private
> > - *  inode area.
> > + *  vxfs_evict_inode() is called on the final iput 
> >   */
> >  void
> >  vxfs_evict_inode(struct inode *ip)
> >  {
> >  	truncate_inode_pages_final(&ip->i_data);
> > +	invalidate_inode_buffers(ip);
> >  	clear_inode(ip);
> > -	call_rcu(&ip->i_rcu, vxfs_i_callback);
> >  }
> > +
> > +int vxfs_inode_info_cache(int setup)
> > +{
> > +	int rc = 0;
> > +
> > +	if (!setup) {
> > +		vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
> > +			sizeof(struct vxfs_inode_info), 0,
> > +			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
> > +
> > +		if (!vxfs_inode_cachep)
> > +			rc = -ENOMEM;
> > +	} else {
> > +	/*
> > +	 * Make sure all delayed rcu free inodes are flushed before we
> > +	 * destroy cache.
> > +	 */
> > +		rcu_barrier();
> > +		kmem_cache_destroy(vxfs_inode_cachep);
> > +	}
> > +
> > +	return rc;
> > +}
> > +
> > diff --git a/fs/freevxfs/vxfs_inode.h b/fs/freevxfs/vxfs_inode.h
> > index 240aeb1..9fc3533 100644
> > --- a/fs/freevxfs/vxfs_inode.h
> > +++ b/fs/freevxfs/vxfs_inode.h
> > @@ -77,13 +77,13 @@ struct vxfs_ext4 {
> >  		vx_daddr_t	extent;			/* Extent number */
> >  		int32_t		size;			/* Size of extent */
> >  	} ve4_direct[VXFS_NDADDR];
> > -};
> > +}  __attribute__((packed));
> >  
> >  struct vxfs_typed {
> >  	u_int64_t	vt_hdr;		/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
> >  	vx_daddr_t	vt_block;	/* Extent block */
> >  	int32_t		vt_size;	/* Size in blocks */
> > -};
> > +}  __attribute__((packed));
> >  
> >  struct vxfs_typed_dev4 {
> >  	u_int64_t	vd4_hdr;	/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
> > @@ -91,7 +91,7 @@ struct vxfs_typed_dev4 {
> >  	u_int64_t	vd4_size;	/* Size in blocks */
> >  	int32_t		vd4_dev;	/* Device ID */
> >  	u_int32_t	__pad1;
> > -};
> > +}  __attribute__((packed));
> >  
> >  /*
> >   * The inode as contained on the physical device.
> > @@ -134,7 +134,7 @@ struct vxfs_dinode {
> >  		struct vxfs_typed	typed[VXFS_NTYPED];
> >  	} vdi_org;
> >  	u_int32_t	vdi_iattrino;
> > -};
> > +} __attribute__((packed));
> >  
> >  #define vdi_rdev	vdi_ftarea.rdev
> >  #define vdi_dotdot	vdi_ftarea.dotdot
> > diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
> > index 99c7f0a..2e5365b 100644
> > --- a/fs/freevxfs/vxfs_lookup.c
> > +++ b/fs/freevxfs/vxfs_lookup.c
> > @@ -2,6 +2,34 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + * (c) 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests.
> > + *
> > + * These bugs and improvements were as follows:
> > + *   - code not aware of cpu endianess and ondisk data is BE.
> > + *   - misaligned structures read from block device
> > + *   - wrong SB block number. default offset is 8kB
> > + *   - kmem_cache_alloc() objectes released with kfree()
> > + *   - inode.i_private released in evict_inode() callback.
> > + *   - refactored vxfs_readdir() and vxfs_find_entry()
> > + *
> > + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> > + * Example: */
> > +// *  cksum mnt/usr/share/man/man3.Z/* 
> > +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> > +// *  cksum mnt/usr/local/doom/*
> > +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> > +// *  cksum mnt/usr/share/doc/*
> > +// *  cksum mnt/usr/sprockets/lib/*
> > +// *  cksum mnt/usr/sprockets/bin/*
> > +/*
> > + * Needles to say that checksums of files match these evaluated by
> > + * HP-UX B.10.20 cksum. E.g.:
> > + *  3457951056 4196020 /usr/local/doom/doom1.wad
> > + *  2527157998 35344 /usr/local/doom/doomlaunch
> > + *  2974998129 413696 /usr/local/doom/hpdoom
> > + *
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -76,6 +104,15 @@ dir_blocks(struct inode *ip)
> >  }
> >  
> >  /*
> > + * VXFS_dirblk_ovh is the overhead of a specific dirblock.
> > + */
> > +static inline u_long VXFS_dirblk_ovh(struct vxfs_dirblk *dbp)
> > +{
> > +	return (sizeof(short) * be16_to_cpu(dbp->d_nhash)) + 4;
> > +}
> > +
> > +
> > +/*
> >   * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
> >   *
> >   * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
> > @@ -83,19 +120,13 @@ dir_blocks(struct inode *ip)
> >  static inline int
> >  vxfs_match(int len, const char * const name, struct vxfs_direct *de)
> >  {
> > -	if (len != de->d_namelen)
> > +	if (len != be16_to_cpu(de->d_namelen))
> >  		return 0;
> >  	if (!de->d_ino)
> >  		return 0;
> >  	return !memcmp(name, de->d_name, len);
> >  }
> >  
> > -static inline struct vxfs_direct *
> > -vxfs_next_entry(struct vxfs_direct *de)
> > -{
> > -	return ((struct vxfs_direct *)((char*)de + de->d_reclen));
> > -}
> > -
> >  /**
> >   * vxfs_find_entry - find a mathing directory entry for a dentry
> >   * @ip:		directory inode
> > @@ -113,50 +144,73 @@ vxfs_next_entry(struct vxfs_direct *de)
> >  static struct vxfs_direct *
> >  vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
> >  {
> > -	u_long				npages, page, nblocks, pblocks, block;
> > -	u_long				bsize = ip->i_sb->s_blocksize;
> > -	const char			*name = dp->d_name.name;
> > -	int				namelen = dp->d_name.len;
> > -
> > -	npages = dir_pages(ip);
> > -	nblocks = dir_blocks(ip);
> > -	pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
> > -	
> > -	for (page = 0; page < npages; page++) {
> > -		caddr_t			kaddr;
> > -		struct page		*pp;
> > -
> > -		pp = vxfs_get_page(ip->i_mapping, page);
> > -		if (IS_ERR(pp))
> > -			continue;
> > -		kaddr = (caddr_t)page_address(pp);
> > -
> > -		for (block = 0; block <= nblocks && block <= pblocks; block++) {
> > -			caddr_t			baddr, limit;
> > -			struct vxfs_dirblk	*dbp;
> > -			struct vxfs_direct	*de;
> > -
> > -			baddr = kaddr + (block * bsize);
> > -			limit = baddr + bsize - VXFS_DIRLEN(1);
> > -			
> > -			dbp = (struct vxfs_dirblk *)baddr;
> > -			de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
> > -
> > -			for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
> > -				if (!de->d_reclen)
> > -					break;
> > -				if (!de->d_ino)
> > -					continue;
> > -				if (vxfs_match(namelen, name, de)) {
> > -					*ppp = pp;
> > -					return (de);
> > -				}
> > +	u_long bsize = ip->i_sb->s_blocksize;
> > +	const char *name = dp->d_name.name;
> > +	int namelen = dp->d_name.len;
> > +	loff_t limit = VXFS_DIRROUND(ip->i_size);
> > +	struct vxfs_direct *de_exit = NULL;
> > +	loff_t pos = 0;
> > +
> > +
> > +	F_ENTER_V2("\"%s\" %d", name, namelen);
> > +
> > +	while (pos < limit) {
> > +		struct page *pp;
> > +		char *kaddr;
> > +		int pg_ofs = pos & ~PAGE_CACHE_MASK;
> > +
> > +		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_CACHE_SHIFT);
> > +		if (IS_ERR(pp)) {
> > +			return NULL;
> > +		}
> > +		kaddr = (char *)page_address(pp);
> > +
> > +#ifdef DIAGNOSTIC_V2
> > +		printk("%s:%d pos %ld, lim %ld, %p\n", __FUNCTION__, __LINE__, pos, limit, kaddr);
> > +#endif
> > +		while (pg_ofs < PAGE_SIZE && pos < limit) {
> > +			struct vxfs_direct *de;
> > +
> > +			if ((pos & (bsize - 1)) < 4) {
> > +				struct vxfs_dirblk *dbp = 
> 
> White space here too
> 
> > +				    (struct vxfs_dirblk *)(kaddr + (pos & ~PAGE_CACHE_MASK ));
> > +				pos += VXFS_dirblk_ovh(dbp);
> > +				pg_ofs += VXFS_dirblk_ovh(dbp);
> > +			}
> > +			de = (struct vxfs_direct *)(kaddr + pg_ofs);
> > +
> > +#ifdef DIAGNOSTIC_V2
> > +			printk("%s:%d de=%p, pgo %d: \"%10s\", %d %d %d\n", __FUNCTION__, __LINE__,
> > +				de, pg_ofs,
> > +				de->d_name, be16_to_cpu(de->d_namelen),
> > +				be16_to_cpu(de->d_reclen), be32_to_cpu(de->d_ino));
> > +#endif
> > +			if (!de->d_reclen) {
> > +				pos += bsize - 1;
> > +				pos &= ~(bsize - 1);
> > +				break;
> > +			}
> > +
> > +			pg_ofs += be16_to_cpu(de->d_reclen);
> > +			pos += be16_to_cpu(de->d_reclen);
> > +			if (!de->d_ino) {
> > +				continue;
> > +			}
> > +
> > +			if (vxfs_match(namelen, name, de)) {
> > +				*ppp = pp;
> > +				de_exit= de; //return (de);
> > +				break;
> >  			}
> >  		}
> > -		vxfs_put_page(pp);
> > +		if (!de_exit)
> > +			vxfs_put_page(pp);
> > +		else
> > +			break;
> >  	}
> >  
> > -	return NULL;
> > +	F_EXIT_V2("\"%s\": %p", name, de_exit);
> > +	return de_exit;
> >  }
> >  
> >  /**
> > @@ -180,11 +234,10 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
> >  
> >  	de = vxfs_find_entry(dip, dp, &pp);
> >  	if (de) {
> > -		ino = de->d_ino;
> > -		kunmap(pp);
> > -		page_cache_release(pp);
> > +		ino = be32_to_cpu(de->d_ino);
> > +		vxfs_put_page(pp);
> >  	}
> > -	
> > +
> >  	return (ino);
> >  }
> >  
> > @@ -207,17 +260,17 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
> >  {
> >  	struct inode		*ip = NULL;
> >  	ino_t			ino;
> > -			 
> > +
> >  	if (dp->d_name.len > VXFS_NAMELEN)
> >  		return ERR_PTR(-ENAMETOOLONG);
> > -				 
> > +
> >  	ino = vxfs_inode_by_name(dip, dp);
> >  	if (ino) {
> >  		ip = vxfs_iget(dip->i_sb, ino);
> >  		if (IS_ERR(ip))
> >  			return ERR_CAST(ip);
> > +		d_add(dp, ip);
> >  	}
> > -	d_add(dp, ip);
> >  	return NULL;
> >  }
> >  
> > @@ -234,80 +287,95 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
> >   * Returns:
> >   *   Zero.
> >   */
> > +
> >  static int
> >  vxfs_readdir(struct file *fp, struct dir_context *ctx)
> >  {
> >  	struct inode		*ip = file_inode(fp);
> >  	struct super_block	*sbp = ip->i_sb;
> >  	u_long			bsize = sbp->s_blocksize;
> > -	u_long			page, npages, block, pblocks, nblocks, offset;
> > -	loff_t			pos;
> > +	loff_t			pos, limit;
> > +
> > +	F_ENTER_V3("pos %ld, ino %ld, size %ld", (long)ctx->pos, ip->i_ino, (long)ip->i_size);
> >  
> >  	if (ctx->pos == 0) {
> >  		if (!dir_emit_dot(fp, ctx))
> > -			return 0;
> > -		ctx->pos = 1;
> > +			goto out;
> > +		ctx->pos++;
> >  	}
> >  	if (ctx->pos == 1) {
> >  		if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
> > -			return 0;
> > -		ctx->pos = 2;
> > +			goto out;
> > +		ctx->pos++;
> >  	}
> > -	pos = ctx->pos - 2;
> > -	
> > -	if (pos > VXFS_DIRROUND(ip->i_size))
> > -		return 0;
> >  
> > -	npages = dir_pages(ip);
> > -	nblocks = dir_blocks(ip);
> > -	pblocks = VXFS_BLOCK_PER_PAGE(sbp);
> > +	limit = VXFS_DIRROUND(ip->i_size);
> > +	if (ctx->pos > limit) {
> > +//		ctx->pos = 0;
> > +		goto out;
> > +	}
> >  
> > -	page = pos >> PAGE_CACHE_SHIFT;
> > -	offset = pos & ~PAGE_CACHE_MASK;
> > -	block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
> > +	pos = ctx->pos & ~3L;
> >  
> > -	for (; page < npages; page++, block = 0) {
> > -		char			*kaddr;
> > -		struct page		*pp;
> > +	while (pos < limit) {
> > +		struct page *pp;
> > +		char *kaddr;
> > +		int pg_ofs = pos & ~PAGE_CACHE_MASK;
> > +		int rc = 0;
> >  
> > -		pp = vxfs_get_page(ip->i_mapping, page);
> > -		if (IS_ERR(pp))
> > -			continue;
> > +		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_CACHE_SHIFT);
> > +		if (IS_ERR(pp)) {
> > +			return -ENOMEM;
> > +		}
> >  		kaddr = (char *)page_address(pp);
> >  
> > -		for (; block <= nblocks && block <= pblocks; block++) {
> > -			char			*baddr, *limit;
> > -			struct vxfs_dirblk	*dbp;
> > -			struct vxfs_direct	*de;
> > -
> > -			baddr = kaddr + (block * bsize);
> > -			limit = baddr + bsize - VXFS_DIRLEN(1);
> > -	
> > -			dbp = (struct vxfs_dirblk *)baddr;
> > -			de = (struct vxfs_direct *)
> > -				(offset ?
> > -				 (kaddr + offset) :
> > -				 (baddr + VXFS_DIRBLKOV(dbp)));
> > -
> > -			for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
> > -				if (!de->d_reclen)
> > -					break;
> > -				if (!de->d_ino)
> > -					continue;
> > -
> > -				offset = (char *)de - kaddr;
> > -				ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
> > -				if (!dir_emit(ctx, de->d_name, de->d_namelen,
> > -					de->d_ino, DT_UNKNOWN)) {
> > -					vxfs_put_page(pp);
> > -					return 0;
> > -				}
> > +#ifdef DIAGNOSTIC_V3
> > +		printk("%s:%d pos %ld, lim %ld, %p\n", __FUNCTION__, __LINE__, pos, limit, kaddr);
> > +#endif
> > +		while (pg_ofs < PAGE_SIZE && pos < limit) {
> > +			struct vxfs_direct *de;
> > +
> > +			if ((pos & (bsize - 1)) < 4) {
> > +				struct vxfs_dirblk *dbp = 
> 
> White space
> 
> > +				    (struct vxfs_dirblk *)(kaddr + (pos & ~PAGE_CACHE_MASK ));
> > +				pos += VXFS_dirblk_ovh(dbp);
> > +				pg_ofs += VXFS_dirblk_ovh(dbp);
> > +			}
> > +			de = (struct vxfs_direct *)(kaddr + pg_ofs);
> > +
> > +#ifdef DIAGNOSTIC_V3
> > +			printk("%s:%d de=%p, pgo %d: \"%10s\", %d %d %d\n", __FUNCTION__, __LINE__,
> > +				de, pg_ofs,
> > +				de->d_name, be16_to_cpu(de->d_namelen),
> > +				be16_to_cpu(de->d_reclen), be32_to_cpu(de->d_ino));
> > +#endif
> > +			if (!de->d_reclen) {
> > +				pos += bsize - 1;
> > +				pos &= ~(bsize - 1);
> > +				break;
> > +			}
> > +
> > +			pg_ofs += be16_to_cpu(de->d_reclen);
> > +			pos += be16_to_cpu(de->d_reclen);
> > +			if (!de->d_ino) {
> > +				continue;
> > +			}
> > +
> > +			if (! (rc = dir_emit(ctx, de->d_name, be16_to_cpu(de->d_namelen),
> > +				be32_to_cpu(de->d_ino), DT_UNKNOWN))) {
> > +				// the dir entry was not submitted, so fix pos.
> > +				pos -= be16_to_cpu(de->d_reclen); 
> White space
> > +				break;
> >  			}
> > -			offset = 0;
> >  		}
> >  		vxfs_put_page(pp);
> > -		offset = 0;
> > +		if (!rc)
> > +			break;
> >  	}
> > -	ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
> > +
> > +	ctx->pos = pos | 2;
> > +
> > +out:
> > +	F_EXIT_V3("pos %ld", (long)ctx->pos);
> >  	return 0;
> >  }
> > diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c
> > index 0495008..19a1cab 100644
> > --- a/fs/freevxfs/vxfs_olt.c
> > +++ b/fs/freevxfs/vxfs_olt.c
> > @@ -2,6 +2,10 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + *
> > + * 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -43,14 +47,14 @@ static inline void
> >  vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
> >  {
> >  	BUG_ON(infp->vsi_fshino);
> > -	infp->vsi_fshino = fshp->olt_fsino[0];
> > +	infp->vsi_fshino = be32_to_cpu(fshp->olt_fsino[0]);
> >  }
> >  
> >  static inline void
> >  vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
> >  {
> >  	BUG_ON(infp->vsi_iext);
> > -	infp->vsi_iext = ilistp->olt_iext[0]; 
> > +	infp->vsi_iext = be32_to_cpu(ilistp->olt_iext[0]); 
> 
> 	White space in these lines
> 
> >  }
> >  
> >  static inline u_long
> > @@ -80,6 +84,7 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
> >  	struct buffer_head	*bp;
> >  	struct vxfs_olt		*op;
> >  	char			*oaddr, *eaddr;
> > +	u32 j;
> >  
> >  
> >  	bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
> > @@ -87,8 +92,8 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
> >  		goto fail;
> >  
> >  	op = (struct vxfs_olt *)bp->b_data;
> > -	if (op->olt_magic != VXFS_OLT_MAGIC) {
> > -		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
> > +	if ((j = be32_to_cpu(op->olt_magic)) != VXFS_OLT_MAGIC) {
> > +		printk(KERN_NOTICE "vxfs: ivalid olt magic number %08x at +%d\n", j, infp->vsi_oltext);
> >  		goto fail;
> >  	}
> >  
> > @@ -97,19 +102,24 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
> >  	 * I've not seen any such filesystem yet and I'm lazy..  --hch
> >  	 */
> >  	if (infp->vsi_oltsize > 1) {
> > -		printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n");
> > +		printk(KERN_NOTICE "vxfs: oltsize > 1 detected (%d).\n", infp->vsi_oltsize);
> >  		printk(KERN_NOTICE "vxfs: please notify hch@infradead.org\n");
> >  		goto fail;
> >  	}
> >  
> > -	oaddr = bp->b_data + op->olt_size;
> > +	oaddr = bp->b_data + be32_to_cpu(op->olt_size);
> >  	eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
> >  
> >  	while (oaddr < eaddr) {
> > -		struct vxfs_oltcommon	*ocp =
> > +		struct vxfs_oltcommon *ocp =
> >  			(struct vxfs_oltcommon *)oaddr;
> > -		
> > -		switch (ocp->olt_type) {
> > +
> > +#ifdef DIAGNOSTIC
> > +		printk(KERN_DEBUG "oltc_type %d, sz %d at +%d\n", 
> 
> 	White space
> > +			be32_to_cpu(ocp->olt_type), be32_to_cpu(ocp->olt_size), (int)(oaddr - bp->b_data));
> > +#endif
> > +
> > +		switch (be32_to_cpu(ocp->olt_type)) {
> >  		case VXFS_OLT_FSHEAD:
> >  			vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
> >  			break;
> > @@ -118,11 +128,16 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
> >  			break;
> >  		}
> >  
> > -		oaddr += ocp->olt_size;
> > +		oaddr += be32_to_cpu(ocp->olt_size);
> >  	}
> >  
> > +#ifdef DIAGNOSTIC
> > +	printk(KERN_DEBUG "olt_size %d, vsi_fshino %d, vsi_iext %ld\n",
> > +	    be32_to_cpu(op->olt_size), (u32)infp->vsi_fshino, infp->vsi_iext);
> > +#endif
> > +
> >  	brelse(bp);
> > -	return 0;
> > +	return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
> >  
> >  fail:
> >  	brelse(bp);
> > diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
> > index 7ca8c75..9fbf271 100644
> > --- a/fs/freevxfs/vxfs_super.c
> > +++ b/fs/freevxfs/vxfs_super.c
> > @@ -2,6 +2,38 @@
> >   * Copyright (c) 2000-2001 Christoph Hellwig.
> >   * All rights reserved.
> >   *
> > + * (c) 2016 Krzysztof Blaszkowski.
> > + *       Many bug fixes, improvements & tests.
> > + *
> > + * These bugs and improvements were as follows:
> > + *   - code not aware of cpu endianess and ondisk data is BE.
> > + *   - misaligned structures read from block device
> > + *   - wrong SB block number. default offset is 8kB
> > + *   - kmem_cache_alloc() objectes released with kfree()
> > + *   - inode.i_private released in evict_inode() callback.
> > + *   - refactored vxfs_readdir() and vxfs_find_entry()
> > + *
> > + * Tests were performed with image of HP 9000/779 disk (/ lvol)
> > + * Example: */
> > +// *  cksum mnt/usr/share/man/man3.Z/* 
> > +// *  cksum mnt/usr/share/doc/10.20RelNotes 
> 
> White space
> 
> > +// *  cksum mnt/usr/local/doom/*
> > +// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
> > +// *  cksum mnt/usr/share/doc/*
> > +// *  cksum mnt/usr/sprockets/lib/*
> > +// *  cksum mnt/usr/sprockets/bin/*
> > +/*
> > + * Needles to say that checksums of files match these evaluated by
> > + * HP-UX B.10.20 cksum. E.g.:
> > + *  3457951056 4196020 /usr/local/doom/doom1.wad
> > + *  2527157998 35344 /usr/local/doom/doomlaunch
> > + *  2974998129 413696 /usr/local/doom/hpdoom
> > + *
> > + * The hpux_mdsetup tool project which is aimed at making possible
> > + * accessing HP-UX logical volumes by device mapper is here:
> > + *       https://sourceforge.net/projects/linux-vxfs/
> > + *
> > + *
> >   * Redistribution and use in source and binary forms, with or without
> >   * modification, are permitted provided that the following conditions
> >   * are met:
> > @@ -41,6 +73,7 @@
> >  #include <linux/stat.h>
> >  #include <linux/vfs.h>
> >  #include <linux/mount.h>
> > +#include <linux/byteorder/generic.h>
> >  
> >  #include "vxfs.h"
> >  #include "vxfs_extern.h"
> > @@ -48,7 +81,7 @@
> >  #include "vxfs_inode.h"
> >  
> >  
> > -MODULE_AUTHOR("Christoph Hellwig");
> > +MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski");
> >  MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
> >  MODULE_LICENSE("Dual BSD/GPL");
> >  
> > @@ -59,6 +92,7 @@ static int		vxfs_statfs(struct dentry *, struct kstatfs *);
> >  static int		vxfs_remount(struct super_block *, int *, char *);
> >  
> >  static const struct super_operations vxfs_super_ops = {
> > +	.destroy_inode = vxfs_destroy_inode,
> >  	.evict_inode =		vxfs_evict_inode,
> >  	.put_super =		vxfs_put_super,
> >  	.statfs =		vxfs_statfs,
> > @@ -153,6 +187,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
> >  	u_long			bsize;
> >  	struct inode *root;
> >  	int ret = -EINVAL;
> > +	int j;
> >  
> >  	sbp->s_flags |= MS_RDONLY;
> >  
> > @@ -168,7 +203,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
> >  		goto out;
> >  	}
> >  
> > -	bp = sb_bread(sbp, 1);
> > +	bp = sb_bread(sbp, 8);
> >  	if (!bp || !buffer_mapped(bp)) {
> >  		if (!silent) {
> >  			printk(KERN_WARNING
> > @@ -178,32 +213,30 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
> >  	}
> >  
> >  	rsbp = (struct vxfs_sb *)bp->b_data;
> > -	if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
> > +	if (be32_to_cpu(rsbp->vs_magic) != VXFS_SUPER_MAGIC) {
> >  		if (!silent)
> > -			printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
> > +			printk(KERN_NOTICE "vxfs: WRONG superblock magic %08x\n", rsbp->vs_magic);
> >  		goto out;
> >  	}
> >  
> > -	if ((rsbp->vs_version < 2 || rsbp->vs_version > 4) && !silent) {
> > -		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n",
> > -		       rsbp->vs_version);
> > +	j = be32_to_cpu(rsbp->vs_version);
> > +	if ((j < 2 || j > 4) && !silent) {
> > +		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j);
> >  		goto out;
> >  	}
> >  
> > -#ifdef DIAGNOSTIC
> > -	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", rsbp->vs_version);
> > -	printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize);
> > -#endif
> >  
> > -	sbp->s_magic = rsbp->vs_magic;
> > +	sbp->s_magic = be32_to_cpu(rsbp->vs_magic);
> >  	sbp->s_fs_info = infp;
> >  
> >  	infp->vsi_raw = rsbp;
> >  	infp->vsi_bp = bp;
> > -	infp->vsi_oltext = rsbp->vs_oltext[0];
> > -	infp->vsi_oltsize = rsbp->vs_oltsize;
> > +	infp->vsi_oltext = be32_to_cpu(rsbp->vs_oltext[0]);
> > +	infp->vsi_oltsize = be32_to_cpu(rsbp->vs_oltsize);
> > +
> > +	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", be32_to_cpu(rsbp->vs_version));
> >  
> > -	if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
> > +	if (!sb_set_blocksize(sbp, be32_to_cpu(rsbp->vs_bsize))) {
> >  		printk(KERN_WARNING "vxfs: unable to set final block size\n");
> >  		goto out;
> >  	}
> > @@ -229,6 +262,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
> >  		printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
> >  		goto out_free_ilist;
> >  	}
> > +	printk(KERN_DEBUG "vxfs: blocksize: %d, oltext %d, oltsize %d\n", 
> 
> 	White space
> 
> > +	    be32_to_cpu(rsbp->vs_bsize), infp->vsi_oltext, infp->vsi_oltsize);
> >  
> >  	return 0;
> >  	
> > @@ -237,6 +272,7 @@ out_free_ilist:
> >  	vxfs_put_fake_inode(infp->vsi_ilist);
> >  	vxfs_put_fake_inode(infp->vsi_stilist);
> >  out:
> > +	printk(KERN_ERR "vxfs: mount failed %d\n", ret);
> >  	brelse(bp);
> >  	kfree(infp);
> >  	return ret;
> > @@ -264,29 +300,22 @@ MODULE_ALIAS("vxfs");
> >  static int __init
> >  vxfs_init(void)
> >  {
> > -	int rv;
> > +	int rc = vxfs_inode_info_cache(0);
> >  
> > -	vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
> > -			sizeof(struct vxfs_inode_info), 0,
> > -			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
> > -	if (!vxfs_inode_cachep)
> > -		return -ENOMEM;
> > -	rv = register_filesystem(&vxfs_fs_type);
> > -	if (rv < 0)
> > -		kmem_cache_destroy(vxfs_inode_cachep);
> > -	return rv;
> > +	if (!rc) {
> > +		rc = register_filesystem(&vxfs_fs_type);
> > +		if (rc < 0)
> > +			vxfs_inode_info_cache(1);
> > +	}
> > +	printk(KERN_DEBUG "%s: **** %s %s rc %d\n", __FUNCTION__, __DATE__, __TIME__, rc);
> > +	return rc;
> >  }
> >  
> >  static void __exit
> >  vxfs_cleanup(void)
> >  {
> >  	unregister_filesystem(&vxfs_fs_type);
> > -	/*
> > -	 * Make sure all delayed rcu free inodes are flushed before we
> > -	 * destroy cache.
> > -	 */
> > -	rcu_barrier();
> > -	kmem_cache_destroy(vxfs_inode_cachep);
> > +	vxfs_inode_info_cache(1);
> >  }
> >  
> >  module_init(vxfs_init);
> 
>
diff mbox

Patch

diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
index c8a9265..9890a84 100644
--- a/fs/freevxfs/vxfs.h
+++ b/fs/freevxfs/vxfs.h
@@ -2,6 +2,39 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ *
+ * (c) 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests.
+ *
+ * These bugs and improvements were as follows:
+ *   - code not aware of cpu endianess and ondisk data is BE.
+ *   - misaligned structures read from block device
+ *   - wrong SB block number. default offset is 8kB
+ *   - kmem_cache_alloc() objectes released with kfree()
+ *   - inode.i_private released in evict_inode() callback.
+ *   - refactored vxfs_readdir() and vxfs_find_entry()
+ *
+ * Tests were performed with image of HP 9000/779 disk (/ lvol)
+ * Example: */
+// *  cksum mnt/usr/share/man/man3.Z/* 
+// *  cksum mnt/usr/share/doc/10.20RelNotes 
+// *  cksum mnt/usr/local/doom/*
+// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
+// *  cksum mnt/usr/share/doc/*
+// *  cksum mnt/usr/sprockets/lib/*
+// *  cksum mnt/usr/sprockets/bin/*
+/*
+ * Needles to say that checksums of files match these evaluated by
+ * HP-UX B.10.20 cksum. E.g.:
+ *  3457951056 4196020 /usr/local/doom/doom1.wad
+ *  2527157998 35344 /usr/local/doom/doomlaunch
+ *  2974998129 413696 /usr/local/doom/hpdoom
+ *
+ * The hpux_mdsetup tool project which is aimed at making possible
+ * accessing HP-UX logical volumes by device mapper is here:
+ *       https://sourceforge.net/projects/linux-vxfs/
+ *
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -38,6 +71,10 @@ 
  */
 #include <linux/types.h>
 
+//#define DIAGNOSTIC
+#undef DIAGNOSTIC
+#undef DIAGNOSTIC_V2
+#undef DIAGNOSTIC_V3
 
 /*
  * Data types for use with the VxFS ondisk format.
@@ -152,7 +189,7 @@  struct vxfs_sb {
 	/*
 	 * Actually much more...
 	 */
-};
+} __attribute__((packed));
 
 
 /*
@@ -260,4 +297,35 @@  enum {
 #define VXFS_SBI(sbp) \
 	((struct vxfs_sb_info *)(sbp)->s_fs_info)
 
+
+#ifdef DIAGNOSTIC
+#define F_ENTER(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
+#define F_EXIT(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
+
+#ifdef DIAGNOSTIC_V2
+#define F_ENTER_V2(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
+#define F_EXIT_V2(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
+#else
+#define F_ENTER_V2(a, b...) 
+#define F_EXIT_V2(a, b...) 
+#endif
+
+#ifdef DIAGNOSTIC_V3
+#define F_ENTER_V3(fmt, arg...) printk("%s:%d ENTER. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
+#define F_EXIT_V3(fmt, arg...) printk("%s:%d EXIT. " fmt "\n", __FUNCTION__, __LINE__, ##arg)
+#else
+#define F_ENTER_V3(a, b...) 
+#define F_EXIT_V3(a, b...) 
+#endif
+
+#else // DIAGNOSTIC
+#define F_ENTER(a, b...) 
+#define F_EXIT(a, b...) 
+#define F_ENTER_V2(a, b...) 
+#define F_EXIT_V2(a, b...) 
+#define F_ENTER_V3(a, b...) 
+#define F_EXIT_V3(a, b...) 
+#endif
+
+
 #endif /* _VXFS_SUPER_H_ */
diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c
index f86fd3c..58e6a17 100644
--- a/fs/freevxfs/vxfs_bmap.c
+++ b/fs/freevxfs/vxfs_bmap.c
@@ -2,6 +2,10 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ *
+ * 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -39,17 +43,6 @@ 
 #include "vxfs_extern.h"
 
 
-#ifdef DIAGNOSTIC
-static void
-vxfs_typdump(struct vxfs_typed *typ)
-{
-	printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT);
-	printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
-	printk("block=%x ", typ->vt_block);
-	printk("size=%x\n", typ->vt_size);
-}
-#endif
-
 /**
  * vxfs_bmap_ext4 - do bmap for ext4 extents
  * @ip:		pointer to the inode we do bmap for
@@ -71,18 +64,23 @@  vxfs_bmap_ext4(struct inode *ip, long bn)
 	unsigned long bsize = sb->s_blocksize;
 	u32 indsize = vip->vii_ext4.ve4_indsize;
 	int i;
+	daddr_t rc = 0;
+
+	F_ENTER_V2();
 
 	if (indsize > sb->s_blocksize)
 		goto fail_size;
 
 	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);
+		struct direct *d = vip->vii_ext4.ve4_direct + i; // cpu endian
+		if (bn >= 0 && bn < d->size) {
+			rc = bn + d->extent;
+			break;
+		}
 		bn -= d->size;
 	}
 
-	if ((bn / (indsize * indsize * bsize / 4)) == 0) {
+	if (!rc && ((bn / (indsize * indsize * bsize / 4)) == 0)) {
 		struct buffer_head *buf;
 		daddr_t	bno;
 		u32 *indir;
@@ -92,18 +90,21 @@  vxfs_bmap_ext4(struct inode *ip, long bn)
 			goto fail_buf;
 
 		indir = (u32 *)buf->b_data;
-		bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
+		bno = be32_to_cpu(indir[(bn/indsize) % (indsize*bn)]) + (bn%indsize);
 
 		brelse(buf);
-		return bno;
-	} else
-		printk(KERN_WARNING "no matching indir?");
+		rc = bno;
+	}
+	if (!rc)
+		printk(KERN_WARNING "%s:%d no matching indir?\n", __FUNCTION__, __LINE__);
 
-	return 0;
+	F_EXIT_V2("pblk %d", rc);
+	return rc;
 
 fail_size:
 	printk("vxfs: indirect extent too big!\n");
 fail_buf:
+	F_EXIT();
 	return 0;
 }
 
@@ -129,51 +130,53 @@  vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
 {
 	struct buffer_head		*bp = NULL;
 	daddr_t				pblock = 0;
-	int				i;
+	int i;
 
+	F_ENTER_V2();
 	for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
 		struct vxfs_typed	*typ;
-		int64_t			off;
+		int64_t off;
 
 		bp = sb_bread(ip->i_sb,
 				indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb)));
 		if (!bp || !buffer_mapped(bp))
-			return 0;
+			break;
 
 		typ = ((struct vxfs_typed *)bp->b_data) +
 			(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
-		off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+		off = be64_to_cpu(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)(be64_to_cpu(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, be32_to_cpu(typ->vt_block),
+					be32_to_cpu(typ->vt_size), block - off);
 			if (pblock == -2)
 				break;
 			goto out;
 		case VXFS_TYPED_DATA:
-			if ((block - off) >= typ->vt_size)
+			if ((block - off) >= be32_to_cpu(typ->vt_size))
 				break;
-			pblock = (typ->vt_block + block - off);
+			pblock = be32_to_cpu(typ->vt_block) + block - off;
 			goto out;
 		case VXFS_TYPED_INDIRECT_DEV4:
 		case VXFS_TYPED_DATA_DEV4: {
 			struct vxfs_typed_dev4	*typ4 =
 				(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_ERR "%s:%d TYPED_DEV4 detected!. block: %Lu\tsize: %Ld\tdev: %d\n",
+				__FUNCTION__, __LINE__,
+			       (unsigned long long) be64_to_cpu(typ4->vd4_block),
+			       (unsigned long long) be64_to_cpu(typ4->vd4_size),
+			       be32_to_cpu(typ4->vd4_dev));
 			goto fail;
 		}
 		default:
+			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __FUNCTION__, __LINE__, be64_to_cpu(typ->vt_hdr));
 			BUG();
 		}
 		brelse(bp);
@@ -182,7 +185,9 @@  vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
 fail:
 	pblock = 0;
 out:
-	brelse(bp);
+	if (bp)
+		brelse(bp);
+	F_EXIT_V2();
 	return (pblock);
 }
 
@@ -200,16 +205,18 @@  out:
 static daddr_t
 vxfs_bmap_typed(struct inode *ip, long iblock)
 {
-	struct vxfs_inode_info		*vip = VXFS_INO(ip);
-	daddr_t				pblock = 0;
-	int				i;
+	struct vxfs_inode_info *vip = VXFS_INO(ip);
+	daddr_t pblock = 0;
+	int i;
 
+	F_ENTER_V2();
 	for (i = 0; i < VXFS_NTYPED; i++) {
-		struct vxfs_typed	*typ = vip->vii_org.typed + i;
+		struct vxfs_typed	*typ = vip->vii_org.typed + i; // cpu endian
 		int64_t			off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
 
-#ifdef DIAGNOSTIC
-		vxfs_typdump(typ);
+#ifdef DIAGNOSTIC_V2
+		printk(KERN_DEBUG "%s:%d type=%Lu, ofs=0x%Lx, blk=%d, size=%d\n", __FUNCTION__, __LINE__,
+			typ->vt_hdr >> VXFS_TYPED_TYPESHIFT, off, typ->vt_block, typ->vt_size );
 #endif
 		if (iblock < off)
 			continue;
@@ -219,29 +226,36 @@  vxfs_bmap_typed(struct inode *ip, long iblock)
 					typ->vt_size, iblock - off);
 			if (pblock == -2)
 				break;
-			return (pblock);
+			goto out;
+
 		case VXFS_TYPED_DATA:
-			if ((iblock - off) < typ->vt_size)
-				return (typ->vt_block + iblock - off);
+			if ((iblock - off) < typ->vt_size) {
+				pblock = typ->vt_block + iblock - off;
+				goto out;
+			}
 			break;
 		case VXFS_TYPED_INDIRECT_DEV4:
 		case VXFS_TYPED_DATA_DEV4: {
 			struct vxfs_typed_dev4	*typ4 =
 				(struct vxfs_typed_dev4 *)typ;
 
-			printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
-			printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
+			printk(KERN_ERR "%s:%d TYPED_DEV4 detected!. block: %Lu\tsize: %Ld\tdev: %d\n",
+				__FUNCTION__, __LINE__,
 			       (unsigned long long) typ4->vd4_block,
 			       (unsigned long long) typ4->vd4_size,
 			       typ4->vd4_dev);
-			return 0;
+			pblock = 0;
+			goto out;
 		}
 		default:
+			printk(KERN_ERR "%s:%d vt_hdr %llu\n", __FUNCTION__, __LINE__, typ->vt_hdr);
 			BUG();
 		}
 	}
 
-	return 0;
+out:
+	F_EXIT_V2("pblk %d", pblock);
+	return pblock;
 }
 
 /**
@@ -270,12 +284,14 @@  vxfs_bmap1(struct inode *ip, long iblock)
 	if (VXFS_ISIMMED(vip))
 		goto unsupp;
 
-	printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n",
-			ip->i_ino, vip->vii_orgtype);
+	printk(KERN_ERR "%s:%d inode %ld has no valid orgtype (%x)\n",
+		__FUNCTION__, __LINE__,
+		ip->i_ino, vip->vii_orgtype);
 	BUG();
 
 unsupp:
-	printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n",
-			ip->i_ino, vip->vii_orgtype);
+	printk(KERN_WARNING "%s:%d inode %ld has an unsupported orgtype (%x)\n",
+		__FUNCTION__, __LINE__,
+		ip->i_ino, vip->vii_orgtype);
 	return 0;
 }
diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h
index aaf1fb0..d8b52e6 100644
--- a/fs/freevxfs/vxfs_dir.h
+++ b/fs/freevxfs/vxfs_dir.h
@@ -84,9 +84,5 @@  struct vxfs_direct {
 #define VXFS_DIRROUND(len)	((VXFS_DIRPAD + (len) - 1) & ~(VXFS_DIRPAD -1))
 #define VXFS_DIRLEN(len)	(VXFS_DIRROUND(VXFS_NAMEMIN + (len)))
 
-/*
- * VXFS_DIRBLKOV is the overhead of a specific dirblock.
- */
-#define VXFS_DIRBLKOV(dbp)	((sizeof(short) * dbp->d_nhash) + 4)
 
 #endif /* _VXFS_DIR_H_ */
diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
index 881aa3d..3d20421 100644
--- a/fs/freevxfs/vxfs_extern.h
+++ b/fs/freevxfs/vxfs_extern.h
@@ -55,7 +55,7 @@  extern const struct inode_operations vxfs_immed_symlink_iops;
 
 /* vxfs_inode.c */
 extern const struct address_space_operations vxfs_immed_aops;
-extern struct kmem_cache	*vxfs_inode_cachep;
+//extern struct kmem_cache	*vxfs_inode_cachep;
 extern void			vxfs_dumpi(struct vxfs_inode_info *, ino_t);
 extern struct inode *		vxfs_get_fake_inode(struct super_block *,
 					struct vxfs_inode_info *);
@@ -64,6 +64,10 @@  extern struct vxfs_inode_info *	vxfs_blkiget(struct super_block *, u_long, ino_t
 extern struct vxfs_inode_info *	vxfs_stiget(struct super_block *, ino_t);
 extern struct inode *		vxfs_iget(struct super_block *, ino_t);
 extern void			vxfs_evict_inode(struct inode *);
+extern void vxfs_destroy_inode(struct inode *ip);
+extern void vxfs_inode_info_free(struct vxfs_inode_info *vip);
+extern int vxfs_inode_info_cache(int setup);
+
 
 /* vxfs_lookup.c */
 extern const struct inode_operations	vxfs_dir_inode_ops;
diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c
index c9a6a94..69fcd7f 100644
--- a/fs/freevxfs/vxfs_fshead.c
+++ b/fs/freevxfs/vxfs_fshead.c
@@ -2,6 +2,35 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ *
+ * (c) 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests.
+ *
+ * These bugs and improvements were as follows:
+ *   - code not aware of cpu endianess and ondisk data is BE.
+ *   - misaligned structures read from block device
+ *   - wrong SB block number. default offset is 8kB
+ *   - kmem_cache_alloc() objectes released with kfree()
+ *   - inode.i_private released in evict_inode() callback.
+ *   - refactored vxfs_readdir() and vxfs_find_entry()
+ *
+ * Tests were performed with image of HP 9000/779 disk (/ lvol)
+ * Example: */
+// *  cksum mnt/usr/share/man/man3.Z/* 
+// *  cksum mnt/usr/share/doc/10.20RelNotes 
+// *  cksum mnt/usr/local/doom/*
+// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
+// *  cksum mnt/usr/share/doc/*
+// *  cksum mnt/usr/sprockets/lib/*
+// *  cksum mnt/usr/sprockets/bin/*
+/*
+ * Needles to say that checksums of files match these evaluated by
+ * HP-UX B.10.20 cksum. E.g.:
+ *  3457951056 4196020 /usr/local/doom/doom1.wad
+ *  2527157998 35344 /usr/local/doom/doomlaunch
+ *  2974998129 413696 /usr/local/doom/hpdoom
+ *
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -60,6 +89,34 @@  vxfs_dumpfsh(struct vxfs_fsh *fhp)
 }
 #endif
 
+#define VXFS_BE32(field1, field2) fhp->field1 = be32_to_cpu(dbh->field2)
+
+
+static void inline dbh2fhp(struct vxfs_fsh *fhp, void *_dbh)
+{
+#ifdef __LITTLE_ENDIAN
+	struct vxfs_fsh *dbh = (struct vxfs_fsh *)_dbh;
+
+	VXFS_BE32(fsh_version, fsh_version);
+	VXFS_BE32(fsh_fsindex, fsh_fsindex);
+	VXFS_BE32(fsh_time, fsh_time);
+	VXFS_BE32(fsh_utime, fsh_utime);
+	VXFS_BE32(fsh_extop, fsh_extop);
+	VXFS_BE32(fsh_ninodes, fsh_ninodes);
+	VXFS_BE32(fsh_nau, fsh_nau);
+	VXFS_BE32(fsh_old_ilesize, fsh_old_ilesize);
+	VXFS_BE32(fsh_dflags, fsh_dflags);
+	VXFS_BE32(fsh_quota, fsh_quota);
+	VXFS_BE32(fsh_maxinode, fsh_maxinode);
+	VXFS_BE32(fsh_iauino, fsh_iauino);
+	VXFS_BE32(fsh_ilistino[0], fsh_ilistino[0]);
+	VXFS_BE32(fsh_ilistino[1], fsh_ilistino[1]);
+	VXFS_BE32(fsh_lctino, fsh_lctino);
+#else
+	memcpy(fhp, _dbh, sizeof(*fhp));
+#endif
+}
+
 /**
  * vxfs_getfsh - read fileset header into memory
  * @ip:		the (fake) fileset header inode
@@ -83,7 +140,8 @@  vxfs_getfsh(struct inode *ip, int which)
 
 		if (!(fhp = kmalloc(sizeof(*fhp), GFP_KERNEL)))
 			goto out;
-		memcpy(fhp, bp->b_data, sizeof(*fhp));
+
+		dbh2fhp(fhp, bp->b_data);
 
 		put_bh(bp);
 		return (fhp);
@@ -110,9 +168,12 @@  vxfs_read_fshead(struct super_block *sbp)
 	struct vxfs_fsh			*pfp, *sfp;
 	struct vxfs_inode_info		*vip, *tip;
 
+	F_ENTER();
+
 	vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
 	if (!vip) {
 		printk(KERN_ERR "vxfs: unable to read fsh inode\n");
+		F_EXIT();
 		return -EINVAL;
 	}
 	if (!VXFS_ISFSH(vip)) {
@@ -121,10 +182,8 @@  vxfs_read_fshead(struct super_block *sbp)
 		goto out_free_fship;
 	}
 
-
 #ifdef DIAGNOSTIC
-	printk("vxfs: fsh inode dump:\n");
-	vxfs_dumpi(vip, infp->vsi_fshino);
+	printk("%s:%d\n", __FUNCTION__, __LINE__);
 #endif
 
 	infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
@@ -160,7 +219,7 @@  vxfs_read_fshead(struct super_block *sbp)
 	infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
 	if (!infp->vsi_stilist) {
 		printk(KERN_ERR "vxfs: unable to get structural list inode\n");
-		kfree(tip);
+		vxfs_inode_info_free(tip);
 		goto out_free_pfp;
 	}
 	if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
@@ -175,7 +234,7 @@  vxfs_read_fshead(struct super_block *sbp)
 	infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
 	if (!infp->vsi_ilist) {
 		printk(KERN_ERR "vxfs: unable to get inode list inode\n");
-		kfree(tip);
+		vxfs_inode_info_free(tip);
 		goto out_iput_stilist;
 	}
 	if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
@@ -184,6 +243,7 @@  vxfs_read_fshead(struct super_block *sbp)
 		goto out_iput_ilist;
 	}
 
+	F_EXIT();
 	return 0;
 
  out_iput_ilist:
@@ -196,8 +256,10 @@  vxfs_read_fshead(struct super_block *sbp)
  	kfree(sfp);
  out_iput_fship:
 	iput(infp->vsi_fship);
+	F_EXIT();
 	return -EINVAL;
  out_free_fship:
- 	kfree(vip);
+	vxfs_inode_info_free(vip);
+	F_EXIT();
 	return -EINVAL;
 }
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index 363e3ae..84dec28 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -2,6 +2,34 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ *
+ * (c) 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests.
+ *
+ * These bugs and improvements were as follows:
+ *   - code not aware of cpu endianess and ondisk data is BE.
+ *   - misaligned structures read from block device
+ *   - wrong SB block number. default offset is 8kB
+ *   - kmem_cache_alloc() objectes released with kfree()
+ *   - inode.i_private released in evict_inode() callback.
+ *   - refactored vxfs_readdir() and vxfs_find_entry()
+ *
+ * Tests were performed with image of HP 9000/779 disk (/ lvol)
+ * Example: */
+// *  cksum mnt/usr/share/man/man3.Z/* 
+// *  cksum mnt/usr/share/doc/10.20RelNotes 
+// *  cksum mnt/usr/local/doom/*
+// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
+// *  cksum mnt/usr/share/doc/*
+// *  cksum mnt/usr/sprockets/lib/*
+// *  cksum mnt/usr/sprockets/bin/*
+/*
+ * Needles to say that checksums of files match these evaluated by
+ * HP-UX B.10.20 cksum. E.g.:
+ *  3457951056 4196020 /usr/local/doom/doom1.wad
+ *  2527157998 35344 /usr/local/doom/doomlaunch
+ *  2974998129 413696 /usr/local/doom/hpdoom
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -41,7 +69,7 @@ 
 #include "vxfs_extern.h"
 
 
-struct kmem_cache		*vxfs_inode_cachep;
+static struct kmem_cache *vxfs_inode_cachep;
 
 
 #ifdef DIAGNOSTIC
@@ -51,23 +79,88 @@  struct kmem_cache		*vxfs_inode_cachep;
 void
 vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
 {
-	printk(KERN_DEBUG "\n\n");
-	if (ino)
-		printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino);
+#ifdef DIAGNOSTIC_V2
+	if (ino && vip)
+		printk(KERN_DEBUG "\nvxfs inode %ld dump **** %p\n", ino, vip);
 	else
-		printk(KERN_DEBUG "dumping unknown vxfs inode\n");
+		printk(KERN_DEBUG "\ndumping unknown vxfs inode %p\n", vip);
 
-	printk(KERN_DEBUG "---------------------------\n");
-	printk(KERN_DEBUG "mode is %x\n", vip->vii_mode);
-	printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n",
-			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
-	printk(KERN_DEBUG "size:%Lx, blocks:%u\n",
+	if (vip) {
+		printk(KERN_DEBUG " * mode: %x, type %d\n", vip->vii_mode, vip->vii_orgtype);
+		printk(KERN_DEBUG " * size:%Lx, blocks:%u\n",
 			vip->vii_size, vip->vii_blocks);
-	printk(KERN_DEBUG "orgtype:%u\n", vip->vii_orgtype);
+		printk(KERN_DEBUG " * nlink:%u, uid:%u, gid:%u\n",
+			vip->vii_nlink, vip->vii_uid, vip->vii_gid);
+	}
+#endif
 }
 #endif
 
 
+#define VXFS_BE32(field1, field2) vip->field1 = be32_to_cpu(dip->field2)
+#define VXFS_BE64(field1, field2) vip->field1 = be64_to_cpu(dip->field2)
+#define VXFS_BE16(field1, field2) vip->field1 = be16_to_cpu(dip->field2)
+
+
+static void inline dip2vip_cpy(struct vxfs_inode_info *vip, struct vxfs_dinode *dip)
+{
+#ifdef __LITTLE_ENDIAN
+	int j;
+
+	VXFS_BE32(vdi_mode, vdi_mode);
+	VXFS_BE32(vdi_nlink, vdi_nlink);
+	VXFS_BE32(vdi_uid, vdi_uid);
+	VXFS_BE32(vdi_gid, vdi_gid);
+	VXFS_BE64(vdi_size, vdi_size);
+	VXFS_BE32(vdi_atime, vdi_atime);
+	VXFS_BE32(vdi_autime, vdi_autime);
+	VXFS_BE32(vdi_mtime, vdi_mtime);
+	VXFS_BE32(vdi_mutime, vdi_mutime);
+	VXFS_BE32(vdi_ctime, vdi_ctime);
+	VXFS_BE32(vdi_cutime, vdi_cutime);
+	vip->vdi_aflags = dip->vdi_aflags;
+	vip->vdi_orgtype = dip->vdi_orgtype;
+	VXFS_BE16(vdi_eopflags, vdi_eopflags);
+	VXFS_BE32(vdi_eopdata, vdi_eopdata);
+
+	VXFS_BE32(vdi_ftarea.i_regular.reserved, vdi_ftarea.i_regular.reserved);
+	VXFS_BE32(vdi_ftarea.i_regular.fixextsize, vdi_ftarea.i_regular.fixextsize);
+	VXFS_BE32(vdi_blocks, vdi_blocks);
+	VXFS_BE32(vdi_gen, vdi_gen);
+	VXFS_BE64(vdi_version, vdi_version);
+
+	switch (dip->vdi_orgtype) {
+	case VXFS_ORG_EXT4:
+		VXFS_BE32(vdi_org.ext4.ve4_spare, vdi_org.ext4.ve4_spare);
+		VXFS_BE32(vdi_org.ext4.ve4_indsize, vdi_org.ext4.ve4_indsize);
+		for (j = 0; j < VXFS_NIADDR; j++) {
+			VXFS_BE32(vdi_org.ext4.ve4_indir[j], vdi_org.ext4.ve4_indir[j]);
+		}
+		for (j = 0; j < VXFS_NDADDR; j++) {
+			VXFS_BE32(vdi_org.ext4.ve4_direct[j].extent, vdi_org.ext4.ve4_direct[j].extent);
+			VXFS_BE32(vdi_org.ext4.ve4_direct[j].size, vdi_org.ext4.ve4_direct[j].size);
+		}
+		break;
+	case VXFS_ORG_IMMED:
+		memcpy(&vip->vdi_org.immed, &dip->vdi_org.immed, sizeof(vip->vdi_org.immed));
+		break;
+	case VXFS_ORG_TYPED:
+		for (j = 0; j < VXFS_NTYPED; j++) {
+			VXFS_BE64(vdi_org.typed[j].vt_hdr, vdi_org.typed[j].vt_hdr);
+			VXFS_BE32(vdi_org.typed[j].vt_block, vdi_org.typed[j].vt_block);
+			VXFS_BE32(vdi_org.typed[j].vt_size, vdi_org.typed[j].vt_size);
+		}
+		break;
+	
+	};
+
+	VXFS_BE32(vdi_iattrino, vdi_iattrino);
+#else
+	memcpy(vip, dip, sizeof(*vip));
+#endif
+}
+
+
 /**
  * vxfs_blkiget - find inode based on extent #
  * @sbp:	superblock of the filesystem we search in
@@ -84,6 +177,9 @@  vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
  *  buffercache.  This function should not be used outside the
  *  read_super() method, otherwise the data may be incoherent.
  */
+
+
+
 struct vxfs_inode_info *
 vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
 {
@@ -101,7 +197,7 @@  vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
 		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
 			goto fail;
 		dip = (struct vxfs_dinode *)(bp->b_data + offset);
-		memcpy(vip, dip, sizeof(*vip));
+		dip2vip_cpy(vip, dip);
 #ifdef DIAGNOSTIC
 		vxfs_dumpi(vip, ino);
 #endif
@@ -143,7 +239,7 @@  __vxfs_iget(ino_t ino, struct inode *ilistp)
 		if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL)))
 			goto fail;
 		dip = (struct vxfs_dinode *)(kaddr + offset);
-		memcpy(vip, dip, sizeof(*vip));
+		dip2vip_cpy(vip, dip);
 #ifdef DIAGNOSTIC
 		vxfs_dumpi(vip, ino);
 #endif
@@ -190,7 +286,7 @@  vxfs_stiget(struct super_block *sbp, ino_t ino)
 static __inline__ umode_t
 vxfs_transmod(struct vxfs_inode_info *vip)
 {
-	umode_t			ret = vip->vii_mode & ~VXFS_TYPE_MASK;
+	umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK;
 
 	if (VXFS_ISFIFO(vip))
 		ret |= S_IFIFO;
@@ -340,21 +436,61 @@  vxfs_iget(struct super_block *sbp, ino_t ino)
 static void vxfs_i_callback(struct rcu_head *head)
 {
 	struct inode *inode = container_of(head, struct inode, i_rcu);
-	kmem_cache_free(vxfs_inode_cachep, inode->i_private);
+	void *priv = inode->i_private;
+
+	inode->i_private = NULL;
+	// just in case the same inode was used elsewhere after releasing i_private.
+	// if it was then dereferencing NULL is far better than using invalid
+	// pointer to memory claimed by something.
+	kmem_cache_free(vxfs_inode_cachep, priv);
+}
+
+void vxfs_destroy_inode(struct inode *ip)
+{
+	call_rcu(&ip->i_rcu, vxfs_i_callback);
+}
+
+void vxfs_inode_info_free(struct vxfs_inode_info *vip)
+{
+	kmem_cache_free(vxfs_inode_cachep, vip);
 }
 
+
 /**
  * vxfs_evict_inode - remove inode from main memory
  * @ip:		inode to discard.
  *
  * Description:
- *  vxfs_evict_inode() is called on the final iput and frees the private
- *  inode area.
+ *  vxfs_evict_inode() is called on the final iput 
  */
 void
 vxfs_evict_inode(struct inode *ip)
 {
 	truncate_inode_pages_final(&ip->i_data);
+	invalidate_inode_buffers(ip);
 	clear_inode(ip);
-	call_rcu(&ip->i_rcu, vxfs_i_callback);
 }
+
+int vxfs_inode_info_cache(int setup)
+{
+	int rc = 0;
+
+	if (!setup) {
+		vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
+			sizeof(struct vxfs_inode_info), 0,
+			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
+
+		if (!vxfs_inode_cachep)
+			rc = -ENOMEM;
+	} else {
+	/*
+	 * Make sure all delayed rcu free inodes are flushed before we
+	 * destroy cache.
+	 */
+		rcu_barrier();
+		kmem_cache_destroy(vxfs_inode_cachep);
+	}
+
+	return rc;
+}
+
diff --git a/fs/freevxfs/vxfs_inode.h b/fs/freevxfs/vxfs_inode.h
index 240aeb1..9fc3533 100644
--- a/fs/freevxfs/vxfs_inode.h
+++ b/fs/freevxfs/vxfs_inode.h
@@ -77,13 +77,13 @@  struct vxfs_ext4 {
 		vx_daddr_t	extent;			/* Extent number */
 		int32_t		size;			/* Size of extent */
 	} ve4_direct[VXFS_NDADDR];
-};
+}  __attribute__((packed));
 
 struct vxfs_typed {
 	u_int64_t	vt_hdr;		/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
 	vx_daddr_t	vt_block;	/* Extent block */
 	int32_t		vt_size;	/* Size in blocks */
-};
+}  __attribute__((packed));
 
 struct vxfs_typed_dev4 {
 	u_int64_t	vd4_hdr;	/* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
@@ -91,7 +91,7 @@  struct vxfs_typed_dev4 {
 	u_int64_t	vd4_size;	/* Size in blocks */
 	int32_t		vd4_dev;	/* Device ID */
 	u_int32_t	__pad1;
-};
+}  __attribute__((packed));
 
 /*
  * The inode as contained on the physical device.
@@ -134,7 +134,7 @@  struct vxfs_dinode {
 		struct vxfs_typed	typed[VXFS_NTYPED];
 	} vdi_org;
 	u_int32_t	vdi_iattrino;
-};
+} __attribute__((packed));
 
 #define vdi_rdev	vdi_ftarea.rdev
 #define vdi_dotdot	vdi_ftarea.dotdot
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index 99c7f0a..2e5365b 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -2,6 +2,34 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ * (c) 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests.
+ *
+ * These bugs and improvements were as follows:
+ *   - code not aware of cpu endianess and ondisk data is BE.
+ *   - misaligned structures read from block device
+ *   - wrong SB block number. default offset is 8kB
+ *   - kmem_cache_alloc() objectes released with kfree()
+ *   - inode.i_private released in evict_inode() callback.
+ *   - refactored vxfs_readdir() and vxfs_find_entry()
+ *
+ * Tests were performed with image of HP 9000/779 disk (/ lvol)
+ * Example: */
+// *  cksum mnt/usr/share/man/man3.Z/* 
+// *  cksum mnt/usr/share/doc/10.20RelNotes 
+// *  cksum mnt/usr/local/doom/*
+// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
+// *  cksum mnt/usr/share/doc/*
+// *  cksum mnt/usr/sprockets/lib/*
+// *  cksum mnt/usr/sprockets/bin/*
+/*
+ * Needles to say that checksums of files match these evaluated by
+ * HP-UX B.10.20 cksum. E.g.:
+ *  3457951056 4196020 /usr/local/doom/doom1.wad
+ *  2527157998 35344 /usr/local/doom/doomlaunch
+ *  2974998129 413696 /usr/local/doom/hpdoom
+ *
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -76,6 +104,15 @@  dir_blocks(struct inode *ip)
 }
 
 /*
+ * VXFS_dirblk_ovh is the overhead of a specific dirblock.
+ */
+static inline u_long VXFS_dirblk_ovh(struct vxfs_dirblk *dbp)
+{
+	return (sizeof(short) * be16_to_cpu(dbp->d_nhash)) + 4;
+}
+
+
+/*
  * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
  *
  * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
@@ -83,19 +120,13 @@  dir_blocks(struct inode *ip)
 static inline int
 vxfs_match(int len, const char * const name, struct vxfs_direct *de)
 {
-	if (len != de->d_namelen)
+	if (len != be16_to_cpu(de->d_namelen))
 		return 0;
 	if (!de->d_ino)
 		return 0;
 	return !memcmp(name, de->d_name, len);
 }
 
-static inline struct vxfs_direct *
-vxfs_next_entry(struct vxfs_direct *de)
-{
-	return ((struct vxfs_direct *)((char*)de + de->d_reclen));
-}
-
 /**
  * vxfs_find_entry - find a mathing directory entry for a dentry
  * @ip:		directory inode
@@ -113,50 +144,73 @@  vxfs_next_entry(struct vxfs_direct *de)
 static struct vxfs_direct *
 vxfs_find_entry(struct inode *ip, struct dentry *dp, struct page **ppp)
 {
-	u_long				npages, page, nblocks, pblocks, block;
-	u_long				bsize = ip->i_sb->s_blocksize;
-	const char			*name = dp->d_name.name;
-	int				namelen = dp->d_name.len;
-
-	npages = dir_pages(ip);
-	nblocks = dir_blocks(ip);
-	pblocks = VXFS_BLOCK_PER_PAGE(ip->i_sb);
-	
-	for (page = 0; page < npages; page++) {
-		caddr_t			kaddr;
-		struct page		*pp;
-
-		pp = vxfs_get_page(ip->i_mapping, page);
-		if (IS_ERR(pp))
-			continue;
-		kaddr = (caddr_t)page_address(pp);
-
-		for (block = 0; block <= nblocks && block <= pblocks; block++) {
-			caddr_t			baddr, limit;
-			struct vxfs_dirblk	*dbp;
-			struct vxfs_direct	*de;
-
-			baddr = kaddr + (block * bsize);
-			limit = baddr + bsize - VXFS_DIRLEN(1);
-			
-			dbp = (struct vxfs_dirblk *)baddr;
-			de = (struct vxfs_direct *)(baddr + VXFS_DIRBLKOV(dbp));
-
-			for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) {
-				if (!de->d_reclen)
-					break;
-				if (!de->d_ino)
-					continue;
-				if (vxfs_match(namelen, name, de)) {
-					*ppp = pp;
-					return (de);
-				}
+	u_long bsize = ip->i_sb->s_blocksize;
+	const char *name = dp->d_name.name;
+	int namelen = dp->d_name.len;
+	loff_t limit = VXFS_DIRROUND(ip->i_size);
+	struct vxfs_direct *de_exit = NULL;
+	loff_t pos = 0;
+
+
+	F_ENTER_V2("\"%s\" %d", name, namelen);
+
+	while (pos < limit) {
+		struct page *pp;
+		char *kaddr;
+		int pg_ofs = pos & ~PAGE_CACHE_MASK;
+
+		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_CACHE_SHIFT);
+		if (IS_ERR(pp)) {
+			return NULL;
+		}
+		kaddr = (char *)page_address(pp);
+
+#ifdef DIAGNOSTIC_V2
+		printk("%s:%d pos %ld, lim %ld, %p\n", __FUNCTION__, __LINE__, pos, limit, kaddr);
+#endif
+		while (pg_ofs < PAGE_SIZE && pos < limit) {
+			struct vxfs_direct *de;
+
+			if ((pos & (bsize - 1)) < 4) {
+				struct vxfs_dirblk *dbp = 
+				    (struct vxfs_dirblk *)(kaddr + (pos & ~PAGE_CACHE_MASK ));
+				pos += VXFS_dirblk_ovh(dbp);
+				pg_ofs += VXFS_dirblk_ovh(dbp);
+			}
+			de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+#ifdef DIAGNOSTIC_V2
+			printk("%s:%d de=%p, pgo %d: \"%10s\", %d %d %d\n", __FUNCTION__, __LINE__,
+				de, pg_ofs,
+				de->d_name, be16_to_cpu(de->d_namelen),
+				be16_to_cpu(de->d_reclen), be32_to_cpu(de->d_ino));
+#endif
+			if (!de->d_reclen) {
+				pos += bsize - 1;
+				pos &= ~(bsize - 1);
+				break;
+			}
+
+			pg_ofs += be16_to_cpu(de->d_reclen);
+			pos += be16_to_cpu(de->d_reclen);
+			if (!de->d_ino) {
+				continue;
+			}
+
+			if (vxfs_match(namelen, name, de)) {
+				*ppp = pp;
+				de_exit= de; //return (de);
+				break;
 			}
 		}
-		vxfs_put_page(pp);
+		if (!de_exit)
+			vxfs_put_page(pp);
+		else
+			break;
 	}
 
-	return NULL;
+	F_EXIT_V2("\"%s\": %p", name, de_exit);
+	return de_exit;
 }
 
 /**
@@ -180,11 +234,10 @@  vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
 
 	de = vxfs_find_entry(dip, dp, &pp);
 	if (de) {
-		ino = de->d_ino;
-		kunmap(pp);
-		page_cache_release(pp);
+		ino = be32_to_cpu(de->d_ino);
+		vxfs_put_page(pp);
 	}
-	
+
 	return (ino);
 }
 
@@ -207,17 +260,17 @@  vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
 {
 	struct inode		*ip = NULL;
 	ino_t			ino;
-			 
+
 	if (dp->d_name.len > VXFS_NAMELEN)
 		return ERR_PTR(-ENAMETOOLONG);
-				 
+
 	ino = vxfs_inode_by_name(dip, dp);
 	if (ino) {
 		ip = vxfs_iget(dip->i_sb, ino);
 		if (IS_ERR(ip))
 			return ERR_CAST(ip);
+		d_add(dp, ip);
 	}
-	d_add(dp, ip);
 	return NULL;
 }
 
@@ -234,80 +287,95 @@  vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
  * Returns:
  *   Zero.
  */
+
 static int
 vxfs_readdir(struct file *fp, struct dir_context *ctx)
 {
 	struct inode		*ip = file_inode(fp);
 	struct super_block	*sbp = ip->i_sb;
 	u_long			bsize = sbp->s_blocksize;
-	u_long			page, npages, block, pblocks, nblocks, offset;
-	loff_t			pos;
+	loff_t			pos, limit;
+
+	F_ENTER_V3("pos %ld, ino %ld, size %ld", (long)ctx->pos, ip->i_ino, (long)ip->i_size);
 
 	if (ctx->pos == 0) {
 		if (!dir_emit_dot(fp, ctx))
-			return 0;
-		ctx->pos = 1;
+			goto out;
+		ctx->pos++;
 	}
 	if (ctx->pos == 1) {
 		if (!dir_emit(ctx, "..", 2, VXFS_INO(ip)->vii_dotdot, DT_DIR))
-			return 0;
-		ctx->pos = 2;
+			goto out;
+		ctx->pos++;
 	}
-	pos = ctx->pos - 2;
-	
-	if (pos > VXFS_DIRROUND(ip->i_size))
-		return 0;
 
-	npages = dir_pages(ip);
-	nblocks = dir_blocks(ip);
-	pblocks = VXFS_BLOCK_PER_PAGE(sbp);
+	limit = VXFS_DIRROUND(ip->i_size);
+	if (ctx->pos > limit) {
+//		ctx->pos = 0;
+		goto out;
+	}
 
-	page = pos >> PAGE_CACHE_SHIFT;
-	offset = pos & ~PAGE_CACHE_MASK;
-	block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
+	pos = ctx->pos & ~3L;
 
-	for (; page < npages; page++, block = 0) {
-		char			*kaddr;
-		struct page		*pp;
+	while (pos < limit) {
+		struct page *pp;
+		char *kaddr;
+		int pg_ofs = pos & ~PAGE_CACHE_MASK;
+		int rc = 0;
 
-		pp = vxfs_get_page(ip->i_mapping, page);
-		if (IS_ERR(pp))
-			continue;
+		pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_CACHE_SHIFT);
+		if (IS_ERR(pp)) {
+			return -ENOMEM;
+		}
 		kaddr = (char *)page_address(pp);
 
-		for (; block <= nblocks && block <= pblocks; block++) {
-			char			*baddr, *limit;
-			struct vxfs_dirblk	*dbp;
-			struct vxfs_direct	*de;
-
-			baddr = kaddr + (block * bsize);
-			limit = baddr + bsize - VXFS_DIRLEN(1);
-	
-			dbp = (struct vxfs_dirblk *)baddr;
-			de = (struct vxfs_direct *)
-				(offset ?
-				 (kaddr + offset) :
-				 (baddr + VXFS_DIRBLKOV(dbp)));
-
-			for (; (char *)de <= limit; de = vxfs_next_entry(de)) {
-				if (!de->d_reclen)
-					break;
-				if (!de->d_ino)
-					continue;
-
-				offset = (char *)de - kaddr;
-				ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
-				if (!dir_emit(ctx, de->d_name, de->d_namelen,
-					de->d_ino, DT_UNKNOWN)) {
-					vxfs_put_page(pp);
-					return 0;
-				}
+#ifdef DIAGNOSTIC_V3
+		printk("%s:%d pos %ld, lim %ld, %p\n", __FUNCTION__, __LINE__, pos, limit, kaddr);
+#endif
+		while (pg_ofs < PAGE_SIZE && pos < limit) {
+			struct vxfs_direct *de;
+
+			if ((pos & (bsize - 1)) < 4) {
+				struct vxfs_dirblk *dbp = 
+				    (struct vxfs_dirblk *)(kaddr + (pos & ~PAGE_CACHE_MASK ));
+				pos += VXFS_dirblk_ovh(dbp);
+				pg_ofs += VXFS_dirblk_ovh(dbp);
+			}
+			de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+#ifdef DIAGNOSTIC_V3
+			printk("%s:%d de=%p, pgo %d: \"%10s\", %d %d %d\n", __FUNCTION__, __LINE__,
+				de, pg_ofs,
+				de->d_name, be16_to_cpu(de->d_namelen),
+				be16_to_cpu(de->d_reclen), be32_to_cpu(de->d_ino));
+#endif
+			if (!de->d_reclen) {
+				pos += bsize - 1;
+				pos &= ~(bsize - 1);
+				break;
+			}
+
+			pg_ofs += be16_to_cpu(de->d_reclen);
+			pos += be16_to_cpu(de->d_reclen);
+			if (!de->d_ino) {
+				continue;
+			}
+
+			if (! (rc = dir_emit(ctx, de->d_name, be16_to_cpu(de->d_namelen),
+				be32_to_cpu(de->d_ino), DT_UNKNOWN))) {
+				// the dir entry was not submitted, so fix pos.
+				pos -= be16_to_cpu(de->d_reclen); 
+				break;
 			}
-			offset = 0;
 		}
 		vxfs_put_page(pp);
-		offset = 0;
+		if (!rc)
+			break;
 	}
-	ctx->pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2;
+
+	ctx->pos = pos | 2;
+
+out:
+	F_EXIT_V3("pos %ld", (long)ctx->pos);
 	return 0;
 }
diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c
index 0495008..19a1cab 100644
--- a/fs/freevxfs/vxfs_olt.c
+++ b/fs/freevxfs/vxfs_olt.c
@@ -2,6 +2,10 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ *
+ * 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -43,14 +47,14 @@  static inline void
 vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
 {
 	BUG_ON(infp->vsi_fshino);
-	infp->vsi_fshino = fshp->olt_fsino[0];
+	infp->vsi_fshino = be32_to_cpu(fshp->olt_fsino[0]);
 }
 
 static inline void
 vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
 {
 	BUG_ON(infp->vsi_iext);
-	infp->vsi_iext = ilistp->olt_iext[0]; 
+	infp->vsi_iext = be32_to_cpu(ilistp->olt_iext[0]); 
 }
 
 static inline u_long
@@ -80,6 +84,7 @@  vxfs_read_olt(struct super_block *sbp, u_long bsize)
 	struct buffer_head	*bp;
 	struct vxfs_olt		*op;
 	char			*oaddr, *eaddr;
+	u32 j;
 
 
 	bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
@@ -87,8 +92,8 @@  vxfs_read_olt(struct super_block *sbp, u_long bsize)
 		goto fail;
 
 	op = (struct vxfs_olt *)bp->b_data;
-	if (op->olt_magic != VXFS_OLT_MAGIC) {
-		printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
+	if ((j = be32_to_cpu(op->olt_magic)) != VXFS_OLT_MAGIC) {
+		printk(KERN_NOTICE "vxfs: ivalid olt magic number %08x at +%d\n", j, infp->vsi_oltext);
 		goto fail;
 	}
 
@@ -97,19 +102,24 @@  vxfs_read_olt(struct super_block *sbp, u_long bsize)
 	 * I've not seen any such filesystem yet and I'm lazy..  --hch
 	 */
 	if (infp->vsi_oltsize > 1) {
-		printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n");
+		printk(KERN_NOTICE "vxfs: oltsize > 1 detected (%d).\n", infp->vsi_oltsize);
 		printk(KERN_NOTICE "vxfs: please notify hch@infradead.org\n");
 		goto fail;
 	}
 
-	oaddr = bp->b_data + op->olt_size;
+	oaddr = bp->b_data + be32_to_cpu(op->olt_size);
 	eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
 
 	while (oaddr < eaddr) {
-		struct vxfs_oltcommon	*ocp =
+		struct vxfs_oltcommon *ocp =
 			(struct vxfs_oltcommon *)oaddr;
-		
-		switch (ocp->olt_type) {
+
+#ifdef DIAGNOSTIC
+		printk(KERN_DEBUG "oltc_type %d, sz %d at +%d\n", 
+			be32_to_cpu(ocp->olt_type), be32_to_cpu(ocp->olt_size), (int)(oaddr - bp->b_data));
+#endif
+
+		switch (be32_to_cpu(ocp->olt_type)) {
 		case VXFS_OLT_FSHEAD:
 			vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
 			break;
@@ -118,11 +128,16 @@  vxfs_read_olt(struct super_block *sbp, u_long bsize)
 			break;
 		}
 
-		oaddr += ocp->olt_size;
+		oaddr += be32_to_cpu(ocp->olt_size);
 	}
 
+#ifdef DIAGNOSTIC
+	printk(KERN_DEBUG "olt_size %d, vsi_fshino %d, vsi_iext %ld\n",
+	    be32_to_cpu(op->olt_size), (u32)infp->vsi_fshino, infp->vsi_iext);
+#endif
+
 	brelse(bp);
-	return 0;
+	return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
 
 fail:
 	brelse(bp);
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 7ca8c75..9fbf271 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -2,6 +2,38 @@ 
  * Copyright (c) 2000-2001 Christoph Hellwig.
  * All rights reserved.
  *
+ * (c) 2016 Krzysztof Blaszkowski.
+ *       Many bug fixes, improvements & tests.
+ *
+ * These bugs and improvements were as follows:
+ *   - code not aware of cpu endianess and ondisk data is BE.
+ *   - misaligned structures read from block device
+ *   - wrong SB block number. default offset is 8kB
+ *   - kmem_cache_alloc() objectes released with kfree()
+ *   - inode.i_private released in evict_inode() callback.
+ *   - refactored vxfs_readdir() and vxfs_find_entry()
+ *
+ * Tests were performed with image of HP 9000/779 disk (/ lvol)
+ * Example: */
+// *  cksum mnt/usr/share/man/man3.Z/* 
+// *  cksum mnt/usr/share/doc/10.20RelNotes 
+// *  cksum mnt/usr/local/doom/*
+// *  cksum mnt/usr/sprockets/tools/instrument/16700/*
+// *  cksum mnt/usr/share/doc/*
+// *  cksum mnt/usr/sprockets/lib/*
+// *  cksum mnt/usr/sprockets/bin/*
+/*
+ * Needles to say that checksums of files match these evaluated by
+ * HP-UX B.10.20 cksum. E.g.:
+ *  3457951056 4196020 /usr/local/doom/doom1.wad
+ *  2527157998 35344 /usr/local/doom/doomlaunch
+ *  2974998129 413696 /usr/local/doom/hpdoom
+ *
+ * The hpux_mdsetup tool project which is aimed at making possible
+ * accessing HP-UX logical volumes by device mapper is here:
+ *       https://sourceforge.net/projects/linux-vxfs/
+ *
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -41,6 +73,7 @@ 
 #include <linux/stat.h>
 #include <linux/vfs.h>
 #include <linux/mount.h>
+#include <linux/byteorder/generic.h>
 
 #include "vxfs.h"
 #include "vxfs_extern.h"
@@ -48,7 +81,7 @@ 
 #include "vxfs_inode.h"
 
 
-MODULE_AUTHOR("Christoph Hellwig");
+MODULE_AUTHOR("Christoph Hellwig, Krzysztof Blaszkowski");
 MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver");
 MODULE_LICENSE("Dual BSD/GPL");
 
@@ -59,6 +92,7 @@  static int		vxfs_statfs(struct dentry *, struct kstatfs *);
 static int		vxfs_remount(struct super_block *, int *, char *);
 
 static const struct super_operations vxfs_super_ops = {
+	.destroy_inode = vxfs_destroy_inode,
 	.evict_inode =		vxfs_evict_inode,
 	.put_super =		vxfs_put_super,
 	.statfs =		vxfs_statfs,
@@ -153,6 +187,7 @@  static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 	u_long			bsize;
 	struct inode *root;
 	int ret = -EINVAL;
+	int j;
 
 	sbp->s_flags |= MS_RDONLY;
 
@@ -168,7 +203,7 @@  static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 		goto out;
 	}
 
-	bp = sb_bread(sbp, 1);
+	bp = sb_bread(sbp, 8);
 	if (!bp || !buffer_mapped(bp)) {
 		if (!silent) {
 			printk(KERN_WARNING
@@ -178,32 +213,30 @@  static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 	}
 
 	rsbp = (struct vxfs_sb *)bp->b_data;
-	if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
+	if (be32_to_cpu(rsbp->vs_magic) != VXFS_SUPER_MAGIC) {
 		if (!silent)
-			printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
+			printk(KERN_NOTICE "vxfs: WRONG superblock magic %08x\n", rsbp->vs_magic);
 		goto out;
 	}
 
-	if ((rsbp->vs_version < 2 || rsbp->vs_version > 4) && !silent) {
-		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n",
-		       rsbp->vs_version);
+	j = be32_to_cpu(rsbp->vs_version);
+	if ((j < 2 || j > 4) && !silent) {
+		printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", j);
 		goto out;
 	}
 
-#ifdef DIAGNOSTIC
-	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", rsbp->vs_version);
-	printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize);
-#endif
 
-	sbp->s_magic = rsbp->vs_magic;
+	sbp->s_magic = be32_to_cpu(rsbp->vs_magic);
 	sbp->s_fs_info = infp;
 
 	infp->vsi_raw = rsbp;
 	infp->vsi_bp = bp;
-	infp->vsi_oltext = rsbp->vs_oltext[0];
-	infp->vsi_oltsize = rsbp->vs_oltsize;
+	infp->vsi_oltext = be32_to_cpu(rsbp->vs_oltext[0]);
+	infp->vsi_oltsize = be32_to_cpu(rsbp->vs_oltsize);
+
+	printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", be32_to_cpu(rsbp->vs_version));
 
-	if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
+	if (!sb_set_blocksize(sbp, be32_to_cpu(rsbp->vs_bsize))) {
 		printk(KERN_WARNING "vxfs: unable to set final block size\n");
 		goto out;
 	}
@@ -229,6 +262,8 @@  static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
 		printk(KERN_WARNING "vxfs: unable to get root dentry.\n");
 		goto out_free_ilist;
 	}
+	printk(KERN_DEBUG "vxfs: blocksize: %d, oltext %d, oltsize %d\n", 
+	    be32_to_cpu(rsbp->vs_bsize), infp->vsi_oltext, infp->vsi_oltsize);
 
 	return 0;
 	
@@ -237,6 +272,7 @@  out_free_ilist:
 	vxfs_put_fake_inode(infp->vsi_ilist);
 	vxfs_put_fake_inode(infp->vsi_stilist);
 out:
+	printk(KERN_ERR "vxfs: mount failed %d\n", ret);
 	brelse(bp);
 	kfree(infp);
 	return ret;
@@ -264,29 +300,22 @@  MODULE_ALIAS("vxfs");
 static int __init
 vxfs_init(void)
 {
-	int rv;
+	int rc = vxfs_inode_info_cache(0);
 
-	vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
-			sizeof(struct vxfs_inode_info), 0,
-			SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
-	if (!vxfs_inode_cachep)
-		return -ENOMEM;
-	rv = register_filesystem(&vxfs_fs_type);
-	if (rv < 0)
-		kmem_cache_destroy(vxfs_inode_cachep);
-	return rv;
+	if (!rc) {
+		rc = register_filesystem(&vxfs_fs_type);
+		if (rc < 0)
+			vxfs_inode_info_cache(1);
+	}
+	printk(KERN_DEBUG "%s: **** %s %s rc %d\n", __FUNCTION__, __DATE__, __TIME__, rc);
+	return rc;
 }
 
 static void __exit
 vxfs_cleanup(void)
 {
 	unregister_filesystem(&vxfs_fs_type);
-	/*
-	 * Make sure all delayed rcu free inodes are flushed before we
-	 * destroy cache.
-	 */
-	rcu_barrier();
-	kmem_cache_destroy(vxfs_inode_cachep);
+	vxfs_inode_info_cache(1);
 }
 
 module_init(vxfs_init);