@@ -5,12 +5,20 @@ config VXFS_FS
FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
file system format. VERITAS VxFS(TM) is the standard file system
of SCO UnixWare (and possibly others) and optionally available
- for Sunsoft Solaris, HP-UX and many other operating systems.
+ for Sunsoft Solaris, HP-UX and many other operating systems. However
+ these particular OS implementations of vxfs may differ in on-disk
+ data endianess and/or superblock offset. The vxfs module has been
+ tested with SCO UnixWare and HP-UX B.10.20 (pa-risc 1.1 arch.)
Currently only readonly access is supported.
NOTE: the file system type as used by mount(1), mount(2) and
fstab(5) is 'vxfs' as it describes the file system format, not
the actual driver.
+ There is a userspace utility for HP-UX logical volumes which makes
+ creating HP-UX logical volumes easy from HP-UX disk block device file
+ or regular file with image of the disk. See:
+ https://sourceforge.net/projects/linux-vxfs/
+
To compile this as a module, choose M here: the module will be
called freevxfs. If unsure, say N.
--
1.7.3.4
From c617f6bceedc2f68c62e7432f12b59124bab34f7 Mon Sep 17 00:00:00 2001
From: KB <kb@sysmikro.com.pl>
Date: Wed, 25 May 2016 22:12:05 +0200
Subject: [PATCH 2/7] cpu endian vs file system endian
Signed-off-by: KB <kb@sysmikro.com.pl>
---
fs/freevxfs/vxfs.h | 25 +++++++++++-
fs/freevxfs/vxfs_bmap.c | 24 ++++++-----
fs/freevxfs/vxfs_fshead.c | 25 +++++++++++-
fs/freevxfs/vxfs_inode.c | 61 +++++++++++++++++++++++++++-
fs/freevxfs/vxfs_inode.h | 8 ++--
fs/freevxfs/vxfs_lookup.c | 15 ++++++-
fs/freevxfs/vxfs_olt.c | 15 ++++---
fs/freevxfs/vxfs_super.c | 97 ++++++++++++++++++++++++++++++++-------------
8 files changed, 215 insertions(+), 55 deletions(-)
@@ -152,7 +152,7 @@ struct vxfs_sb {
/*
* Actually much more...
*/
-};
+} __packed;
/*
@@ -168,9 +168,32 @@ struct vxfs_sb_info {
ino_t vsi_fshino; /* fileset header inode */
daddr_t vsi_oltext; /* OLT extent */
daddr_t vsi_oltsize; /* OLT size */
+ int byte_order;
+ int silent;
+};
+
+enum {
+ BO_LE = 1,
+ BO_BE
};
+static inline u32 fs32_to_cpu(int bo, u32 a)
+{
+ return (bo == BO_BE) ? be32_to_cpu(a) : le32_to_cpu(a);
+}
+
+static inline u16 fs16_to_cpu(int bo, u16 a)
+{
+ return (bo == BO_BE) ? be16_to_cpu(a) : le16_to_cpu(a);
+}
+
+static inline u64 fs64_to_cpu(int bo, u64 a)
+{
+ return (bo == BO_BE) ? be64_to_cpu(a) : le64_to_cpu(a);
+}
+
+
/*
* File modes. File types above 0xf000 are vxfs internal only, they should
* not be passed back to higher levels of the system. vxfs file types must
@@ -92,7 +92,8 @@ 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 = fs32_to_cpu(VXFS_SBI(sb)->byte_order,
+ indir[(bn/indsize) % (indsize*bn)]) + (bn % indsize);
brelse(buf);
return bno;
@@ -130,6 +131,7 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
struct buffer_head *bp = NULL;
daddr_t pblock = 0;
int i;
+ int bo = VXFS_SBI(ip->i_sb)->byte_order;
for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) {
struct vxfs_typed *typ;
@@ -142,24 +144,24 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
typ = ((struct vxfs_typed *)bp->b_data) +
(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
- off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
+ off = fs64_to_cpu(bo, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;
if (block < off) {
brelse(bp);
continue;
}
- switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
+ switch ((u_int32_t)(fs64_to_cpu(bo, typ->vt_hdr) >> VXFS_TYPED_TYPESHIFT)) {
case VXFS_TYPED_INDIRECT:
- pblock = vxfs_bmap_indir(ip, typ->vt_block,
- typ->vt_size, block - off);
+ pblock = vxfs_bmap_indir(ip, fs32_to_cpu(bo, typ->vt_block),
+ fs32_to_cpu(bo, typ->vt_size), block - off);
if (pblock == -2)
break;
goto out;
case VXFS_TYPED_DATA:
- if ((block - off) >= typ->vt_size)
+ if ((block - off) >= fs32_to_cpu(bo, typ->vt_size))
break;
- pblock = (typ->vt_block + block - off);
+ pblock = fs32_to_cpu(bo, typ->vt_block) + block - off;
goto out;
case VXFS_TYPED_INDIRECT_DEV4:
case VXFS_TYPED_DATA_DEV4: {
@@ -168,12 +170,14 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
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);
+ (unsigned long long) fs64_to_cpu(bo, typ4->vd4_block),
+ (unsigned long long) fs64_to_cpu(bo, typ4->vd4_size),
+ fs32_to_cpu(bo, typ4->vd4_dev));
goto fail;
}
default:
+ printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__, __LINE__,
+ fs64_to_cpu(bo, typ->vt_hdr));
BUG();
}
brelse(bp);
@@ -60,6 +60,29 @@ vxfs_dumpfsh(struct vxfs_fsh *fhp)
}
#endif
+#define VXFS_FS32(field1, field2) fhp->field1 = fs32_to_cpu(bo, dbh->field2)
+static inline void dbh2fhp(struct vxfs_fsh *fhp, void *_dbh, int bo)
+{
+ struct vxfs_fsh *dbh = (struct vxfs_fsh *)_dbh;
+
+ VXFS_FS32(fsh_version, fsh_version);
+ VXFS_FS32(fsh_fsindex, fsh_fsindex);
+ VXFS_FS32(fsh_time, fsh_time);
+ VXFS_FS32(fsh_utime, fsh_utime);
+ VXFS_FS32(fsh_extop, fsh_extop);
+ VXFS_FS32(fsh_ninodes, fsh_ninodes);
+ VXFS_FS32(fsh_nau, fsh_nau);
+ VXFS_FS32(fsh_old_ilesize, fsh_old_ilesize);
+ VXFS_FS32(fsh_dflags, fsh_dflags);
+ VXFS_FS32(fsh_quota, fsh_quota);
+ VXFS_FS32(fsh_maxinode, fsh_maxinode);
+ VXFS_FS32(fsh_iauino, fsh_iauino);
+ VXFS_FS32(fsh_ilistino[0], fsh_ilistino[0]);
+ VXFS_FS32(fsh_ilistino[1], fsh_ilistino[1]);
+ VXFS_FS32(fsh_lctino, fsh_lctino);
+}
+
+
/**
* vxfs_getfsh - read fileset header into memory
* @ip: the (fake) fileset header inode
@@ -83,7 +106,7 @@ 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, VXFS_SBI(ip->i_sb)->byte_order);
put_bh(bp);
return (fhp);
@@ -67,6 +67,63 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
}
#endif
+#define VXFS_FS32(field1, field2) vip->field1 = fs32_to_cpu(bo, dip->field2)
+#define VXFS_FS64(field1, field2) vip->field1 = fs64_to_cpu(bo, dip->field2)
+#define VXFS_FS16(field1, field2) vip->field1 = fs16_to_cpu(bo, dip->field2)
+
+static inline void dip2vip_cpy(struct vxfs_inode_info *vip, struct vxfs_dinode *dip, int bo)
+{
+ int j;
+
+ VXFS_FS32(vdi_mode, vdi_mode);
+ VXFS_FS32(vdi_nlink, vdi_nlink);
+ VXFS_FS32(vdi_uid, vdi_uid);
+ VXFS_FS32(vdi_gid, vdi_gid);
+ VXFS_FS64(vdi_size, vdi_size);
+ VXFS_FS32(vdi_atime, vdi_atime);
+ VXFS_FS32(vdi_autime, vdi_autime);
+ VXFS_FS32(vdi_mtime, vdi_mtime);
+ VXFS_FS32(vdi_mutime, vdi_mutime);
+ VXFS_FS32(vdi_ctime, vdi_ctime);
+ VXFS_FS32(vdi_cutime, vdi_cutime);
+ vip->vdi_aflags = dip->vdi_aflags;
+ vip->vdi_orgtype = dip->vdi_orgtype;
+ VXFS_FS16(vdi_eopflags, vdi_eopflags);
+ VXFS_FS32(vdi_eopdata, vdi_eopdata);
+
+ VXFS_FS32(vdi_ftarea.i_regular.reserved, vdi_ftarea.i_regular.reserved);
+ VXFS_FS32(vdi_ftarea.i_regular.fixextsize, vdi_ftarea.i_regular.fixextsize);
+ VXFS_FS32(vdi_blocks, vdi_blocks);
+ VXFS_FS32(vdi_gen, vdi_gen);
+ VXFS_FS64(vdi_version, vdi_version);
+
+ switch (dip->vdi_orgtype) {
+ case VXFS_ORG_EXT4:
+ VXFS_FS32(vdi_org.ext4.ve4_spare, vdi_org.ext4.ve4_spare);
+ VXFS_FS32(vdi_org.ext4.ve4_indsize, vdi_org.ext4.ve4_indsize);
+ for (j = 0; j < VXFS_NIADDR; j++) {
+ VXFS_FS32(vdi_org.ext4.ve4_indir[j], vdi_org.ext4.ve4_indir[j]);
+ }
+ for (j = 0; j < VXFS_NDADDR; j++) {
+ VXFS_FS32(vdi_org.ext4.ve4_direct[j].extent, vdi_org.ext4.ve4_direct[j].extent);
+ VXFS_FS32(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_FS64(vdi_org.typed[j].vt_hdr, vdi_org.typed[j].vt_hdr);
+ VXFS_FS32(vdi_org.typed[j].vt_block, vdi_org.typed[j].vt_block);
+ VXFS_FS32(vdi_org.typed[j].vt_size, vdi_org.typed[j].vt_size);
+ }
+ break;
+ };
+
+ VXFS_FS32(vdi_iattrino, vdi_iattrino);
+}
+
/**
* vxfs_blkiget - find inode based on extent #
@@ -101,7 +158,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, VXFS_SBI(sbp)->byte_order);
#ifdef DIAGNOSTIC
vxfs_dumpi(vip, ino);
#endif
@@ -143,7 +200,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, VXFS_SBI(ilistp->i_sb)->byte_order);
#ifdef DIAGNOSTIC
vxfs_dumpi(vip, ino);
#endif
@@ -77,13 +77,13 @@ struct vxfs_ext4 {
vx_daddr_t extent; /* Extent number */
int32_t size; /* Size of extent */
} ve4_direct[VXFS_NDADDR];
-};
+} __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 */
-};
+} __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;
-};
+} __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;
-};
+} __packed;
#define vdi_rdev vdi_ftarea.rdev
#define vdi_dotdot vdi_ftarea.dotdot
@@ -96,6 +96,15 @@ vxfs_next_entry(struct vxfs_direct *de)
return ((struct vxfs_direct *)((char*)de + de->d_reclen));
}
+/*
+ * VXFS_dirblk_ovh is the overhead of a specific dirblock.
+ */
+static inline u_long VXFS_dirblk_ovh(struct vxfs_dirblk *dbp, int bo)
+{
+ return (sizeof(short) * fs16_to_cpu(bo, dbp->d_nhash)) + 4;
+}
+
+
/**
* vxfs_find_entry - find a mathing directory entry for a dentry
* @ip: directory inode
@@ -242,6 +251,8 @@ vxfs_readdir(struct file *fp, struct dir_context *ctx)
u_long bsize = sbp->s_blocksize;
u_long page, npages, block, pblocks, nblocks, offset;
loff_t pos;
+ int bo = VXFS_SBI(sbp)->byte_order;
+
if (ctx->pos == 0) {
if (!dir_emit_dot(fp, ctx))
@@ -297,8 +308,8 @@ vxfs_readdir(struct file *fp, struct dir_context *ctx)
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)) {
+ if (!dir_emit(ctx, de->d_name, fs16_to_cpu(bo, de->d_namelen),
+ fs32_to_cpu(bo, de->d_ino), DT_UNKNOWN)) {
vxfs_put_page(pp);
return 0;
}
@@ -43,14 +43,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 = fs32_to_cpu(infp->byte_order, 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 = fs32_to_cpu(infp->byte_order, ilistp->olt_iext[0]);
}
static inline u_long
@@ -80,6 +80,7 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
struct buffer_head *bp;
struct vxfs_olt *op;
char *oaddr, *eaddr;
+ int bo = infp->byte_order;
bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
@@ -87,7 +88,7 @@ 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) {
+ if (fs32_to_cpu(bo, op->olt_magic) != VXFS_OLT_MAGIC) {
printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
goto fail;
}
@@ -102,14 +103,14 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
goto fail;
}
- oaddr = bp->b_data + op->olt_size;
+ oaddr = bp->b_data + fs32_to_cpu(bo, op->olt_size);
eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
while (oaddr < eaddr) {
struct vxfs_oltcommon *ocp =
(struct vxfs_oltcommon *)oaddr;
- switch (ocp->olt_type) {
+ switch (fs32_to_cpu(bo, ocp->olt_type)) {
case VXFS_OLT_FSHEAD:
vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
break;
@@ -118,11 +119,11 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
break;
}
- oaddr += ocp->olt_size;
+ oaddr += fs32_to_cpu(bo, ocp->olt_size);
}
brelse(bp);
- return 0;
+ return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
fail:
brelse(bp);
@@ -109,14 +109,15 @@ static int
vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
{
struct vxfs_sb_info *infp = VXFS_SBI(dentry->d_sb);
+ struct vxfs_sb *raw_sb = infp->vsi_raw;
bufp->f_type = VXFS_SUPER_MAGIC;
bufp->f_bsize = dentry->d_sb->s_blocksize;
- bufp->f_blocks = infp->vsi_raw->vs_dsize;
- bufp->f_bfree = infp->vsi_raw->vs_free;
+ bufp->f_blocks = fs32_to_cpu(infp->byte_order, raw_sb->vs_dsize);
+ bufp->f_bfree = fs32_to_cpu(infp->byte_order, raw_sb->vs_free);
bufp->f_bavail = 0;
bufp->f_files = 0;
- bufp->f_ffree = infp->vsi_raw->vs_ifree;
+ bufp->f_ffree = fs32_to_cpu(infp->byte_order, raw_sb->vs_ifree);
bufp->f_namelen = VXFS_NAMELEN;
return 0;
@@ -129,6 +130,46 @@ static int vxfs_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
+
+static int vxfs_try_sb_magic(struct super_block *sbp, int blk, u32 magic)
+{
+ struct buffer_head *bp;
+ struct vxfs_sb *rsbp;
+ struct vxfs_sb_info *infp = VXFS_SBI(sbp);
+ int rc = -ENOMEM;
+
+ bp = sb_bread(sbp, blk);
+ do {
+ if (!bp || !buffer_mapped(bp)) {
+ if (!infp->silent) {
+ printk(KERN_WARNING "vxfs: unable to read"
+ " disk superblock at %d\n", blk);
+ }
+ break;
+ }
+
+ rc = -EINVAL;
+ rsbp = (struct vxfs_sb *)bp->b_data;
+ if (rsbp->vs_magic != magic) {
+ if (!infp->silent)
+ printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
+ break;
+ }
+
+ rc = 0;
+ infp->vsi_raw = rsbp;
+ infp->vsi_bp = bp;
+ } while (0);
+
+ if (rc) {
+ infp->vsi_raw = NULL;
+ infp->vsi_bp = NULL;
+ brelse(bp);
+ }
+
+ return rc;
+}
+
/**
* vxfs_read_super - read superblock into memory and initialize filesystem
* @sbp: VFS superblock (to fill)
@@ -149,10 +190,10 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
{
struct vxfs_sb_info *infp;
struct vxfs_sb *rsbp;
- struct buffer_head *bp = NULL;
u_long bsize;
struct inode *root;
int ret = -EINVAL;
+ u32 j;
sbp->s_flags |= MS_RDONLY;
@@ -162,48 +203,47 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
return -ENOMEM;
}
+ infp->silent = silent;
bsize = sb_min_blocksize(sbp, BLOCK_SIZE);
if (!bsize) {
printk(KERN_WARNING "vxfs: unable to set blocksize\n");
goto out;
}
- bp = sb_bread(sbp, 1);
- if (!bp || !buffer_mapped(bp)) {
- if (!silent) {
- printk(KERN_WARNING
- "vxfs: unable to read disk superblock\n");
+ sbp->s_fs_info = infp;
+ do {
+ if (!vxfs_try_sb_magic(sbp, 1, cpu_to_le32(VXFS_SUPER_MAGIC))) {
+ infp->byte_order = BO_LE; /* SCO */
+ break;
+ }
+
+ if (!vxfs_try_sb_magic(sbp, 8, cpu_to_be32(VXFS_SUPER_MAGIC))) {
+ infp->byte_order = BO_BE; /* HP-UX pa-risc likely */
+ break;
}
- goto out;
- }
- rsbp = (struct vxfs_sb *)bp->b_data;
- if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
- if (!silent)
- printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
goto out;
- }
+ } while (0);
- if ((rsbp->vs_version < 2 || rsbp->vs_version > 4) && !silent) {
- printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n",
- rsbp->vs_version);
+ rsbp = infp->vsi_raw;
+ j = fs32_to_cpu(infp->byte_order, 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: supported VxFS version (%d)\n", j);
printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize);
#endif
- sbp->s_magic = rsbp->vs_magic;
- sbp->s_fs_info = infp;
+ sbp->s_magic = fs32_to_cpu(infp->byte_order, rsbp->vs_magic);
- infp->vsi_raw = rsbp;
- infp->vsi_bp = bp;
- infp->vsi_oltext = rsbp->vs_oltext[0];
- infp->vsi_oltsize = rsbp->vs_oltsize;
+ infp->vsi_oltext = fs32_to_cpu(infp->byte_order, rsbp->vs_oltext[0]);
+ infp->vsi_oltsize = fs32_to_cpu(infp->byte_order, rsbp->vs_oltsize);
- if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
+ j = fs32_to_cpu(infp->byte_order, rsbp->vs_bsize);
+ if (!sb_set_blocksize(sbp, j)) {
printk(KERN_WARNING "vxfs: unable to set final block size\n");
goto out;
}
@@ -237,7 +277,8 @@ out_free_ilist:
vxfs_put_fake_inode(infp->vsi_ilist);
vxfs_put_fake_inode(infp->vsi_stilist);
out:
- brelse(bp);
+ if (infp->vsi_bp)
+ brelse(infp->vsi_bp);
kfree(infp);
return ret;
}
--
1.7.3.4
From b95e9b749b85be347c953ce33d2b3c5dde4e56d6 Mon Sep 17 00:00:00 2001
From: KB <kb@sysmikro.com.pl>
Date: Wed, 25 May 2016 22:13:20 +0200
Subject: [PATCH 3/7] missing kfree and kfree on kmem_cache obj
Signed-off-by: KB <kb@sysmikro.com.pl>
---
fs/freevxfs/vxfs_extern.h | 1 +
fs/freevxfs/vxfs_fshead.c | 8 +++++---
fs/freevxfs/vxfs_inode.c | 5 +++++
3 files changed, 11 insertions(+), 3 deletions(-)
@@ -64,6 +64,7 @@ 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_inode_info_free(struct vxfs_inode_info *vip);
/* vxfs_lookup.c */
extern const struct inode_operations vxfs_dir_inode_ops;
@@ -183,7 +183,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))) {
@@ -198,7 +198,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))) {
@@ -206,6 +206,8 @@ vxfs_read_fshead(struct super_block *sbp)
VXFS_INO(infp->vsi_ilist)->vii_mode & VXFS_TYPE_MASK);
goto out_iput_ilist;
}
+ kfree(pfp);
+ kfree(sfp);
return 0;
@@ -221,6 +223,6 @@ vxfs_read_fshead(struct super_block *sbp)
iput(infp->vsi_fship);
return -EINVAL;
out_free_fship:
- kfree(vip);
+ vxfs_inode_info_free(vip);
return -EINVAL;
}
@@ -415,3 +415,8 @@ vxfs_evict_inode(struct inode *ip)
clear_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);
+}
--
1.7.3.4
From e4979c6a29eb79d59d8bc2eca9acc0d2b416780f Mon Sep 17 00:00:00 2001
From: KB <kb@sysmikro.com.pl>
Date: Wed, 25 May 2016 22:15:20 +0200
Subject: [PATCH 4/7] super_operations.destroy_inode
Signed-off-by: KB <kb@sysmikro.com.pl>
---
fs/freevxfs/vxfs_extern.h | 1 +
fs/freevxfs/vxfs_inode.c | 16 ++++++++++++----
fs/freevxfs/vxfs_super.c | 1 +
3 files changed, 14 insertions(+), 4 deletions(-)
@@ -65,6 +65,7 @@ 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_inode_info_free(struct vxfs_inode_info *vip);
+extern void vxfs_destroy_inode(struct inode *ip);
/* vxfs_lookup.c */
extern const struct inode_operations vxfs_dir_inode_ops;
@@ -397,7 +397,15 @@ 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;
+ kmem_cache_free(vxfs_inode_cachep, priv);
+}
+
+void vxfs_destroy_inode(struct inode *ip)
+{
+ call_rcu(&ip->i_rcu, vxfs_i_callback);
}
/**
@@ -405,17 +413,17 @@ static void vxfs_i_callback(struct rcu_head *head)
* @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);
}
+
void vxfs_inode_info_free(struct vxfs_inode_info *vip)
{
kmem_cache_free(vxfs_inode_cachep, vip);
@@ -59,6 +59,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,
--
1.7.3.4
From 4a6ae0e351b6046367bbd2939547f292ed2b6e47 Mon Sep 17 00:00:00 2001
From: KB <kb@sysmikro.com.pl>
Date: Wed, 25 May 2016 22:28:37 +0200
Subject: [PATCH 5/7] refactoring of vxfs_readir() and find_entry()
Signed-off-by: KB <kb@sysmikro.com.pl>
---
fs/freevxfs/vxfs_lookup.c | 267 +++++++++++++++++++++------------------------
1 files changed, 124 insertions(+), 143 deletions(-)
@@ -61,48 +61,6 @@ const struct file_operations vxfs_dir_operations = {
.iterate = vxfs_readdir,
};
-
-static inline u_long
-dir_pages(struct inode *inode)
-{
- return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-}
-
-static inline u_long
-dir_blocks(struct inode *ip)
-{
- u_long bsize = ip->i_sb->s_blocksize;
- return (ip->i_size + bsize - 1) & ~(bsize - 1);
-}
-
-/*
- * NOTE! unlike strncmp, vxfs_match returns 1 for success, 0 for failure.
- *
- * len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
- */
-static inline int
-vxfs_match(int len, const char * const name, struct vxfs_direct *de)
-{
- if (len != 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_dirblk_ovh is the overhead of a specific dirblock.
- */
-static inline u_long VXFS_dirblk_ovh(struct vxfs_dirblk *dbp, int bo)
-{
- return (sizeof(short) * fs16_to_cpu(bo, dbp->d_nhash)) + 4;
-}
/**
@@ -122,50 +80,65 @@ static inline u_long VXFS_dirblk_ovh(struct vxfs_dirblk *dbp, int bo)
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;
+ int bo = VXFS_SBI(ip->i_sb)->byte_order;
+
+ 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);
+
+ 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));
+ int overhead = (sizeof(short) * fs16_to_cpu(bo, dbp->d_nhash)) + 4;
+
+ pos += overhead;
+ pg_ofs += overhead;
+ }
+ de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+ if (!de->d_reclen) {
+ pos += bsize - 1;
+ pos &= ~(bsize - 1);
+ break;
+ }
+
+ pg_ofs += fs16_to_cpu(bo, de->d_reclen);
+ pos += fs16_to_cpu(bo, de->d_reclen);
+ if (!de->d_ino) {
+ continue;
+ }
+
+ if (namelen != fs16_to_cpu(bo, de->d_namelen))
+ continue;
+ if (!memcmp(name, de->d_name, namelen)) {
+ *ppp = pp;
+ de_exit = de;
+ break;
}
}
- vxfs_put_page(pp);
+ if (!de_exit)
+ vxfs_put_page(pp);
+ else
+ break;
}
- return NULL;
+ return de_exit;
}
/**
@@ -185,15 +158,17 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
{
struct vxfs_direct *de;
struct page *pp;
- ino_t ino = 0;
+ ino_t ino = 0;
de = vxfs_find_entry(dip, dp, &pp);
if (de) {
- ino = de->d_ino;
+ int bo = VXFS_SBI(dip->i_sb)->byte_order;
+
+ ino = fs32_to_cpu(bo, de->d_ino);
kunmap(pp);
page_cache_release(pp);
}
-
+
return (ino);
}
@@ -225,8 +200,8 @@ vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
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;
}
@@ -249,76 +224,82 @@ 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;
int bo = VXFS_SBI(sbp)->byte_order;
-
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++;
+ }
+
+ limit = VXFS_DIRROUND(ip->i_size);
+ if (ctx->pos > limit) {
+#if 0
+ ctx->pos = 0;
+#endif
+ goto out;
}
- 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);
-
- page = pos >> PAGE_CACHE_SHIFT;
- offset = pos & ~PAGE_CACHE_MASK;
- block = (u_long)(pos >> sbp->s_blocksize_bits) % pblocks;
-
- for (; page < npages; page++, block = 0) {
- char *kaddr;
- struct page *pp;
-
- pp = vxfs_get_page(ip->i_mapping, page);
- if (IS_ERR(pp))
- continue;
+
+ pos = ctx->pos & ~3L;
+
+ 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, 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, fs16_to_cpu(bo, de->d_namelen),
- fs32_to_cpu(bo, de->d_ino), DT_UNKNOWN)) {
- vxfs_put_page(pp);
- return 0;
- }
+ 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));
+ int overhead = (sizeof(short) * fs16_to_cpu(bo, dbp->d_nhash)) + 4;
+
+ pos += overhead;
+ pg_ofs += overhead;
+ }
+ de = (struct vxfs_direct *)(kaddr + pg_ofs);
+
+ if (!de->d_reclen) {
+ pos += bsize - 1;
+ pos &= ~(bsize - 1);
+ break;
+ }
+
+ pg_ofs += fs16_to_cpu(bo, de->d_reclen);
+ pos += fs16_to_cpu(bo, de->d_reclen);
+ if (!de->d_ino) {
+ continue;
+ }
+
+ rc = dir_emit(ctx, de->d_name, fs16_to_cpu(bo, de->d_namelen),
+ fs32_to_cpu(bo, de->d_ino), DT_UNKNOWN);
+ if (!rc) {
+ /* the dir entry was not submitted, so fix pos. */
+ pos -= fs16_to_cpu(bo, 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:
return 0;
}
--
1.7.3.4
From e7f68291aada1535016c767a4f5a5fcfb19a1de6 Mon Sep 17 00:00:00 2001
From: KB <kb@sysmikro.com.pl>
Date: Wed, 25 May 2016 22:41:22 +0200
Subject: [PATCH 6/7] static cachep
Signed-off-by: KB <kb@sysmikro.com.pl>
---
fs/freevxfs/vxfs_extern.h | 4 +++-
fs/freevxfs/vxfs_inode.c | 24 +++++++++++++++++++++++-
fs/freevxfs/vxfs_super.c | 26 ++++++++++----------------
3 files changed, 36 insertions(+), 18 deletions(-)
@@ -55,7 +55,6 @@ 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 void vxfs_dumpi(struct vxfs_inode_info *, ino_t);
extern struct inode * vxfs_get_fake_inode(struct super_block *,
struct vxfs_inode_info *);
@@ -66,6 +65,9 @@ extern struct inode * vxfs_iget(struct super_block *, ino_t);
extern void vxfs_evict_inode(struct inode *);
extern void vxfs_inode_info_free(struct vxfs_inode_info *vip);
extern void vxfs_destroy_inode(struct inode *ip);
+extern int vxfs_ii_cache_init(void);
+extern void vxfs_ii_cache_destroy(void);
+
/* vxfs_lookup.c */
extern const struct inode_operations vxfs_dir_inode_ops;
@@ -41,7 +41,7 @@
#include "vxfs_extern.h"
-struct kmem_cache *vxfs_inode_cachep;
+static struct kmem_cache *vxfs_inode_cachep;
#ifdef DIAGNOSTIC
@@ -428,3 +428,25 @@ void vxfs_inode_info_free(struct vxfs_inode_info *vip)
{
kmem_cache_free(vxfs_inode_cachep, vip);
}
+
+
+int vxfs_ii_cache_init(void)
+{
+ vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
+ sizeof(struct vxfs_inode_info), 0,
+ SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
+
+ return vxfs_inode_cachep ? 0 : -ENOMEM;
+}
+
+
+void vxfs_ii_cache_destroy(void)
+{
+ /*
+ * Make sure all delayed rcu free inodes are flushed before we
+ * destroy cache.
+ */
+ rcu_barrier();
+ kmem_cache_destroy(vxfs_inode_cachep);
+}
+
@@ -306,29 +306,23 @@ MODULE_ALIAS("vxfs");
static int __init
vxfs_init(void)
{
- int rv;
+ int rc = vxfs_ii_cache_init();
- 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_ii_cache_destroy();
+ }
+ printk(KERN_DEBUG "%s: **** %s %s rc %d\n", __func__, __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_ii_cache_destroy();
}
module_init(vxfs_init);
--
1.7.3.4
From 2c0008e9f2f4e62bb3e10eecad54e2a0140e0c4c Mon Sep 17 00:00:00 2001
From: KB <kb@sysmikro.com.pl>
Date: Wed, 25 May 2016 22:58:08 +0200
Subject: [PATCH 7/7] the credits
Signed-off-by: KB <kb@sysmikro.com.pl>
---
fs/freevxfs/vxfs.h | 3 +++
fs/freevxfs/vxfs_fshead.c | 4 ++++
fs/freevxfs/vxfs_inode.c | 4 ++++
fs/freevxfs/vxfs_lookup.c | 4 ++++
fs/freevxfs/vxfs_super.c | 6 +++++-
5 files changed, 20 insertions(+), 1 deletions(-)
@@ -2,6 +2,9 @@
* Copyright (c) 2000-2001 Christoph Hellwig.
* All rights reserved.
*
+ * (c) 2016 Krzysztof Blaszkowski
+ * Many bug fixes, improvements & tests with HP-UX B.10.20 (pa-risc)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -2,6 +2,10 @@
* Copyright (c) 2000-2001 Christoph Hellwig.
* All rights reserved.
*
+ *
+ * (c) 2016 Krzysztof Blaszkowski
+ * Many bug fixes, improvements & tests with HP-UX B.10.20 (pa-risc)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -2,6 +2,10 @@
* Copyright (c) 2000-2001 Christoph Hellwig.
* All rights reserved.
*
+ *
+ * (c) 2016 Krzysztof Blaszkowski
+ * Many bug fixes, improvements & tests with HP-UX B.10.20 (pa-risc)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -2,6 +2,10 @@
* Copyright (c) 2000-2001 Christoph Hellwig.
* All rights reserved.
*
+ *
+ * (c) 2016 Krzysztof Blaszkowski
+ * Many bug fixes, improvements & tests with HP-UX B.10.20 (pa-risc)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -2,6 +2,10 @@
* Copyright (c) 2000-2001 Christoph Hellwig.
* All rights reserved.
*
+ *
+ * (c) 2016 Krzysztof Blaszkowski
+ * Many bug fixes, improvements & tests with HP-UX B.10.20 (pa-risc)
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -48,7 +52,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");