Commit 0a7736d0 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'freevxfs-for-4.8' of git://git.infradead.org/users/hch/freevxfs

Pull freevxfs updates from Christoph Hellwig:
 "Support for foreign endianess and HP-UP superblocks from
  Krzysztof Błaszkowski"

* tag 'freevxfs-for-4.8' of git://git.infradead.org/users/hch/freevxfs:
  freevxfs: update Kconfig information
  freevxfs: refactor readdir and lookup code
  freevxfs: fix lack of inode initialization
  freevxfs: fix memory leak in vxfs_read_fshead()
  freevxfs: update documentation and cresdits for HP-UX support
  freevxfs: implement ->alloc_inode and ->destroy_inode
  freevxfs: avoid the need for forward declaring the super operations
  freevxfs: move VFS inode allocation into vxfs_blkiget and vxfs_stiget
  freevxfs: remove vxfs_put_fake_inode
  freevxfs: handle big endian HP-UX file systems
parents a54809f1 bf1bb4b4
......@@ -5,12 +5,21 @@ 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.
Currently only readonly access is supported.
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 and VxFX versions
2, 3 and 4. Tests were performed with HP-UX VxFS version 3.
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.
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -38,13 +39,6 @@
*/
#include <linux/types.h>
/*
* Data types for use with the VxFS ondisk format.
*/
typedef int32_t vx_daddr_t;
typedef int32_t vx_ino_t;
/*
* Superblock magic number (vxfs_super->vs_magic).
*/
......@@ -60,6 +54,14 @@ typedef int32_t vx_ino_t;
*/
#define VXFS_NEFREE 32
enum vxfs_byte_order {
VXFS_BO_LE,
VXFS_BO_BE,
};
typedef __u16 __bitwise __fs16;
typedef __u32 __bitwise __fs32;
typedef __u64 __bitwise __fs64;
/*
* VxFS superblock (disk).
......@@ -71,83 +73,83 @@ struct vxfs_sb {
* Lots of this fields are no more used by version 2
* and never filesystems.
*/
u_int32_t vs_magic; /* Magic number */
int32_t vs_version; /* VxFS version */
u_int32_t vs_ctime; /* create time - secs */
u_int32_t vs_cutime; /* create time - usecs */
int32_t __unused1; /* unused */
int32_t __unused2; /* unused */
vx_daddr_t vs_old_logstart; /* obsolete */
vx_daddr_t vs_old_logend; /* obsolete */
int32_t vs_bsize; /* block size */
int32_t vs_size; /* number of blocks */
int32_t vs_dsize; /* number of data blocks */
u_int32_t vs_old_ninode; /* obsolete */
int32_t vs_old_nau; /* obsolete */
int32_t __unused3; /* unused */
int32_t vs_old_defiextsize; /* obsolete */
int32_t vs_old_ilbsize; /* obsolete */
int32_t vs_immedlen; /* size of immediate data area */
int32_t vs_ndaddr; /* number of direct extentes */
vx_daddr_t vs_firstau; /* address of first AU */
vx_daddr_t vs_emap; /* offset of extent map in AU */
vx_daddr_t vs_imap; /* offset of inode map in AU */
vx_daddr_t vs_iextop; /* offset of ExtOp. map in AU */
vx_daddr_t vs_istart; /* offset of inode list in AU */
vx_daddr_t vs_bstart; /* offset of fdblock in AU */
vx_daddr_t vs_femap; /* aufirst + emap */
vx_daddr_t vs_fimap; /* aufirst + imap */
vx_daddr_t vs_fiextop; /* aufirst + iextop */
vx_daddr_t vs_fistart; /* aufirst + istart */
vx_daddr_t vs_fbstart; /* aufirst + bstart */
int32_t vs_nindir; /* number of entries in indir */
int32_t vs_aulen; /* length of AU in blocks */
int32_t vs_auimlen; /* length of imap in blocks */
int32_t vs_auemlen; /* length of emap in blocks */
int32_t vs_auilen; /* length of ilist in blocks */
int32_t vs_aupad; /* length of pad in blocks */
int32_t vs_aublocks; /* data blocks in AU */
int32_t vs_maxtier; /* log base 2 of aublocks */
int32_t vs_inopb; /* number of inodes per blk */
int32_t vs_old_inopau; /* obsolete */
int32_t vs_old_inopilb; /* obsolete */
int32_t vs_old_ndiripau; /* obsolete */
int32_t vs_iaddrlen; /* size of indirect addr ext. */
int32_t vs_bshift; /* log base 2 of bsize */
int32_t vs_inoshift; /* log base 2 of inobp */
int32_t vs_bmask; /* ~( bsize - 1 ) */
int32_t vs_boffmask; /* bsize - 1 */
int32_t vs_old_inomask; /* old_inopilb - 1 */
int32_t vs_checksum; /* checksum of V1 data */
__fs32 vs_magic; /* Magic number */
__fs32 vs_version; /* VxFS version */
__fs32 vs_ctime; /* create time - secs */
__fs32 vs_cutime; /* create time - usecs */
__fs32 __unused1; /* unused */
__fs32 __unused2; /* unused */
__fs32 vs_old_logstart; /* obsolete */
__fs32 vs_old_logend; /* obsolete */
__fs32 vs_bsize; /* block size */
__fs32 vs_size; /* number of blocks */
__fs32 vs_dsize; /* number of data blocks */
__fs32 vs_old_ninode; /* obsolete */
__fs32 vs_old_nau; /* obsolete */
__fs32 __unused3; /* unused */
__fs32 vs_old_defiextsize; /* obsolete */
__fs32 vs_old_ilbsize; /* obsolete */
__fs32 vs_immedlen; /* size of immediate data area */
__fs32 vs_ndaddr; /* number of direct extentes */
__fs32 vs_firstau; /* address of first AU */
__fs32 vs_emap; /* offset of extent map in AU */
__fs32 vs_imap; /* offset of inode map in AU */
__fs32 vs_iextop; /* offset of ExtOp. map in AU */
__fs32 vs_istart; /* offset of inode list in AU */
__fs32 vs_bstart; /* offset of fdblock in AU */
__fs32 vs_femap; /* aufirst + emap */
__fs32 vs_fimap; /* aufirst + imap */
__fs32 vs_fiextop; /* aufirst + iextop */
__fs32 vs_fistart; /* aufirst + istart */
__fs32 vs_fbstart; /* aufirst + bstart */
__fs32 vs_nindir; /* number of entries in indir */
__fs32 vs_aulen; /* length of AU in blocks */
__fs32 vs_auimlen; /* length of imap in blocks */
__fs32 vs_auemlen; /* length of emap in blocks */
__fs32 vs_auilen; /* length of ilist in blocks */
__fs32 vs_aupad; /* length of pad in blocks */
__fs32 vs_aublocks; /* data blocks in AU */
__fs32 vs_maxtier; /* log base 2 of aublocks */
__fs32 vs_inopb; /* number of inodes per blk */
__fs32 vs_old_inopau; /* obsolete */
__fs32 vs_old_inopilb; /* obsolete */
__fs32 vs_old_ndiripau; /* obsolete */
__fs32 vs_iaddrlen; /* size of indirect addr ext. */
__fs32 vs_bshift; /* log base 2 of bsize */
__fs32 vs_inoshift; /* log base 2 of inobp */
__fs32 vs_bmask; /* ~( bsize - 1 ) */
__fs32 vs_boffmask; /* bsize - 1 */
__fs32 vs_old_inomask; /* old_inopilb - 1 */
__fs32 vs_checksum; /* checksum of V1 data */
/*
* Version 1, writable
*/
int32_t vs_free; /* number of free blocks */
int32_t vs_ifree; /* number of free inodes */
int32_t vs_efree[VXFS_NEFREE]; /* number of free extents by size */
int32_t vs_flags; /* flags ?!? */
u_int8_t vs_mod; /* filesystem has been changed */
u_int8_t vs_clean; /* clean FS */
u_int16_t __unused4; /* unused */
u_int32_t vs_firstlogid; /* mount time log ID */
u_int32_t vs_wtime; /* last time written - sec */
u_int32_t vs_wutime; /* last time written - usec */
u_int8_t vs_fname[6]; /* FS name */
u_int8_t vs_fpack[6]; /* FS pack name */
int32_t vs_logversion; /* log format version */
int32_t __unused5; /* unused */
__fs32 vs_free; /* number of free blocks */
__fs32 vs_ifree; /* number of free inodes */
__fs32 vs_efree[VXFS_NEFREE]; /* number of free extents by size */
__fs32 vs_flags; /* flags ?!? */
__u8 vs_mod; /* filesystem has been changed */
__u8 vs_clean; /* clean FS */
__fs16 __unused4; /* unused */
__fs32 vs_firstlogid; /* mount time log ID */
__fs32 vs_wtime; /* last time written - sec */
__fs32 vs_wutime; /* last time written - usec */
__u8 vs_fname[6]; /* FS name */
__u8 vs_fpack[6]; /* FS pack name */
__fs32 vs_logversion; /* log format version */
__u32 __unused5; /* unused */
/*
* Version 2, Read-only
*/
vx_daddr_t vs_oltext[2]; /* OLT extent and replica */
int32_t vs_oltsize; /* OLT extent size */
int32_t vs_iauimlen; /* size of inode map */
int32_t vs_iausize; /* size of IAU in blocks */
int32_t vs_dinosize; /* size of inode in bytes */
int32_t vs_old_dniaddr; /* indir levels per inode */
int32_t vs_checksum2; /* checksum of V2 RO */
__fs32 vs_oltext[2]; /* OLT extent and replica */
__fs32 vs_oltsize; /* OLT extent size */
__fs32 vs_iauimlen; /* size of inode map */
__fs32 vs_iausize; /* size of IAU in blocks */
__fs32 vs_dinosize; /* size of inode in bytes */
__fs32 vs_old_dniaddr; /* indir levels per inode */
__fs32 vs_checksum2; /* checksum of V2 RO */
/*
* Actually much more...
......@@ -168,8 +170,32 @@ struct vxfs_sb_info {
ino_t vsi_fshino; /* fileset header inode */
daddr_t vsi_oltext; /* OLT extent */
daddr_t vsi_oltsize; /* OLT size */
enum vxfs_byte_order byte_order;
};
static inline u16 fs16_to_cpu(struct vxfs_sb_info *sbi, __fs16 a)
{
if (sbi->byte_order == VXFS_BO_BE)
return be16_to_cpu((__force __be16)a);
else
return le16_to_cpu((__force __le16)a);
}
static inline u32 fs32_to_cpu(struct vxfs_sb_info *sbi, __fs32 a)
{
if (sbi->byte_order == VXFS_BO_BE)
return be32_to_cpu((__force __be32)a);
else
return le32_to_cpu((__force __le32)a);
}
static inline u64 fs64_to_cpu(struct vxfs_sb_info *sbi, __fs64 a)
{
if (sbi->byte_order == VXFS_BO_BE)
return be64_to_cpu((__force __be64)a);
else
return le64_to_cpu((__force __le64)a);
}
/*
* File modes. File types above 0xf000 are vxfs internal only, they should
......@@ -247,13 +273,6 @@ enum {
#define VXFS_ISIMMED(ip) VXFS_IS_ORG((ip), VXFS_ORG_IMMED)
#define VXFS_ISTYPED(ip) VXFS_IS_ORG((ip), VXFS_ORG_TYPED)
/*
* Get filesystem private data from VFS inode.
*/
#define VXFS_INO(ip) \
((struct vxfs_inode_info *)(ip)->i_private)
/*
* Get filesystem private data from VFS superblock.
*/
......
......@@ -68,8 +68,9 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
{
struct super_block *sb = ip->i_sb;
struct vxfs_inode_info *vip = VXFS_INO(ip);
struct vxfs_sb_info *sbi = VXFS_SBI(sb);
unsigned long bsize = sb->s_blocksize;
u32 indsize = vip->vii_ext4.ve4_indsize;
u32 indsize = fs32_to_cpu(sbi, vip->vii_ext4.ve4_indsize);
int i;
if (indsize > sb->s_blocksize)
......@@ -77,22 +78,24 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
for (i = 0; i < VXFS_NDADDR; i++) {
struct direct *d = vip->vii_ext4.ve4_direct + i;
if (bn >= 0 && bn < d->size)
return (bn + d->extent);
bn -= d->size;
if (bn >= 0 && bn < fs32_to_cpu(sbi, d->size))
return (bn + fs32_to_cpu(sbi, d->extent));
bn -= fs32_to_cpu(sbi, d->size);
}
if ((bn / (indsize * indsize * bsize / 4)) == 0) {
struct buffer_head *buf;
daddr_t bno;
u32 *indir;
__fs32 *indir;
buf = sb_bread(sb, vip->vii_ext4.ve4_indir[0]);
buf = sb_bread(sb,
fs32_to_cpu(sbi, vip->vii_ext4.ve4_indir[0]));
if (!buf || !buffer_mapped(buf))
goto fail_buf;
indir = (u32 *)buf->b_data;
bno = indir[(bn/indsize) % (indsize*bn)] + (bn%indsize);
indir = (__fs32 *)buf->b_data;
bno = fs32_to_cpu(sbi, indir[(bn / indsize) % (indsize * bn)]) +
(bn % indsize);
brelse(buf);
return bno;
......@@ -127,6 +130,7 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
static daddr_t
vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
{
struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
struct buffer_head *bp = NULL;
daddr_t pblock = 0;
int i;
......@@ -142,24 +146,27 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
typ = ((struct vxfs_typed *)bp->b_data) +
(i % VXFS_TYPED_PER_BLOCK(ip->i_sb));
off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
off = fs64_to_cpu(sbi, typ->vt_hdr) & VXFS_TYPED_OFFSETMASK;
if (block < off) {
brelse(bp);
continue;
}
switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
switch ((u_int32_t)(fs64_to_cpu(sbi, typ->vt_hdr) >>
VXFS_TYPED_TYPESHIFT)) {
case VXFS_TYPED_INDIRECT:
pblock = vxfs_bmap_indir(ip, typ->vt_block,
typ->vt_size, block - off);
pblock = vxfs_bmap_indir(ip,
fs32_to_cpu(sbi, typ->vt_block),
fs32_to_cpu(sbi, typ->vt_size),
block - off);
if (pblock == -2)
break;
goto out;
case VXFS_TYPED_DATA:
if ((block - off) >= typ->vt_size)
if ((block - off) >= fs32_to_cpu(sbi, typ->vt_size))
break;
pblock = (typ->vt_block + block - off);
pblock = fs32_to_cpu(sbi, typ->vt_block) + block - off;
goto out;
case VXFS_TYPED_INDIRECT_DEV4:
case VXFS_TYPED_DATA_DEV4: {
......@@ -167,13 +174,15 @@ vxfs_bmap_indir(struct inode *ip, long indir, int size, long block)
(struct vxfs_typed_dev4 *)typ;
printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
(unsigned long long) typ4->vd4_block,
(unsigned long long) typ4->vd4_size,
typ4->vd4_dev);
printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
fs64_to_cpu(sbi, typ4->vd4_block),
fs64_to_cpu(sbi, typ4->vd4_size),
fs32_to_cpu(sbi, typ4->vd4_dev));
goto fail;
}
default:
printk(KERN_ERR "%s:%d vt_hdr %llu\n", __func__,
__LINE__, fs64_to_cpu(sbi, typ->vt_hdr));
BUG();
}
brelse(bp);
......@@ -201,28 +210,33 @@ static daddr_t
vxfs_bmap_typed(struct inode *ip, long iblock)
{
struct vxfs_inode_info *vip = VXFS_INO(ip);
struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
daddr_t pblock = 0;
int i;
for (i = 0; i < VXFS_NTYPED; i++) {
struct vxfs_typed *typ = vip->vii_org.typed + i;
int64_t off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK);
u64 hdr = fs64_to_cpu(sbi, typ->vt_hdr);
int64_t off = (hdr & VXFS_TYPED_OFFSETMASK);
#ifdef DIAGNOSTIC
vxfs_typdump(typ);
#endif
if (iblock < off)
continue;
switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) {
switch ((u32)(hdr >> VXFS_TYPED_TYPESHIFT)) {
case VXFS_TYPED_INDIRECT:
pblock = vxfs_bmap_indir(ip, typ->vt_block,
typ->vt_size, iblock - off);
pblock = vxfs_bmap_indir(ip,
fs32_to_cpu(sbi, typ->vt_block),
fs32_to_cpu(sbi, typ->vt_size),
iblock - off);
if (pblock == -2)
break;
return (pblock);
case VXFS_TYPED_DATA:
if ((iblock - off) < typ->vt_size)
return (typ->vt_block + iblock - off);
if ((iblock - off) < fs32_to_cpu(sbi, typ->vt_size))
return (fs32_to_cpu(sbi, typ->vt_block) +
iblock - off);
break;
case VXFS_TYPED_INDIRECT_DEV4:
case VXFS_TYPED_DATA_DEV4: {
......@@ -230,10 +244,10 @@ vxfs_bmap_typed(struct inode *ip, long iblock)
(struct vxfs_typed_dev4 *)typ;
printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n");
printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n",
(unsigned long long) typ4->vd4_block,
(unsigned long long) typ4->vd4_size,
typ4->vd4_dev);
printk(KERN_INFO "block: %llu\tsize: %lld\tdev: %d\n",
fs64_to_cpu(sbi, typ4->vd4_block),
fs64_to_cpu(sbi, typ4->vd4_size),
fs32_to_cpu(sbi, typ4->vd4_dev));
return 0;
}
default:
......
......@@ -48,9 +48,9 @@
* Linux driver for now.
*/
struct vxfs_dirblk {
u_int16_t d_free; /* free space in dirblock */
u_int16_t d_nhash; /* no of hash chains */
u_int16_t d_hash[1]; /* hash chain */
__fs16 d_free; /* free space in dirblock */
__fs16 d_nhash; /* no of hash chains */
__fs16 d_hash[1]; /* hash chain */
};
/*
......@@ -63,10 +63,10 @@ struct vxfs_dirblk {
* VxFS directory entry.
*/
struct vxfs_direct {
vx_ino_t d_ino; /* inode number */
u_int16_t d_reclen; /* record length */
u_int16_t d_namelen; /* d_name length */
u_int16_t d_hashnext; /* next hash entry */
__fs32 d_ino; /* inode number */
__fs16 d_reclen; /* record length */
__fs16 d_namelen; /* d_name length */
__fs16 d_hashnext; /* next hash entry */
char d_name[VXFS_NAMELEN]; /* name */
};
......@@ -87,6 +87,7 @@ struct vxfs_direct {
/*
* VXFS_DIRBLKOV is the overhead of a specific dirblock.
*/
#define VXFS_DIRBLKOV(dbp) ((sizeof(short) * dbp->d_nhash) + 4)
#define VXFS_DIRBLKOV(sbi, dbp) \
((sizeof(short) * fs16_to_cpu(sbi, dbp->d_nhash)) + 4)
#endif /* _VXFS_DIR_H_ */
......@@ -52,14 +52,10 @@ extern int vxfs_read_fshead(struct super_block *);
/* 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 *);
extern void vxfs_put_fake_inode(struct inode *);
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 struct inode *vxfs_blkiget(struct super_block *, u_long, ino_t);
extern struct inode *vxfs_stiget(struct super_block *, ino_t);
extern struct inode *vxfs_iget(struct super_block *, ino_t);
extern void vxfs_evict_inode(struct inode *);
/* vxfs_lookup.c */
......
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -108,31 +109,26 @@ vxfs_read_fshead(struct super_block *sbp)
{
struct vxfs_sb_info *infp = VXFS_SBI(sbp);
struct vxfs_fsh *pfp, *sfp;
struct vxfs_inode_info *vip, *tip;
struct vxfs_inode_info *vip;
vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
if (!vip) {
infp->vsi_fship = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino);
if (!infp->vsi_fship) {
printk(KERN_ERR "vxfs: unable to read fsh inode\n");
return -EINVAL;
}
vip = VXFS_INO(infp->vsi_fship);
if (!VXFS_ISFSH(vip)) {
printk(KERN_ERR "vxfs: fsh list inode is of wrong type (%x)\n",
vip->vii_mode & VXFS_TYPE_MASK);
goto out_free_fship;
goto out_iput_fship;
}
#ifdef DIAGNOSTIC
printk("vxfs: fsh inode dump:\n");
vxfs_dumpi(vip, infp->vsi_fshino);
#endif
infp->vsi_fship = vxfs_get_fake_inode(sbp, vip);
if (!infp->vsi_fship) {
printk(KERN_ERR "vxfs: unable to get fsh inode\n");
goto out_free_fship;
}
sfp = vxfs_getfsh(infp->vsi_fship, 0);
if (!sfp) {
printk(KERN_ERR "vxfs: unable to get structural fsh\n");
......@@ -153,14 +149,10 @@ vxfs_read_fshead(struct super_block *sbp)
vxfs_dumpfsh(pfp);
#endif
tip = vxfs_blkiget(sbp, infp->vsi_iext, sfp->fsh_ilistino[0]);
if (!tip)
goto out_free_pfp;
infp->vsi_stilist = vxfs_get_fake_inode(sbp, tip);
infp->vsi_stilist = vxfs_blkiget(sbp, infp->vsi_iext,
fs32_to_cpu(infp, sfp->fsh_ilistino[0]));
if (!infp->vsi_stilist) {
printk(KERN_ERR "vxfs: unable to get structural list inode\n");
kfree(tip);
goto out_free_pfp;
}
if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) {
......@@ -169,13 +161,9 @@ vxfs_read_fshead(struct super_block *sbp)
goto out_iput_stilist;
}
tip = vxfs_stiget(sbp, pfp->fsh_ilistino[0]);
if (!tip)
goto out_iput_stilist;
infp->vsi_ilist = vxfs_get_fake_inode(sbp, tip);
infp->vsi_ilist = vxfs_stiget(sbp, fs32_to_cpu(infp, pfp->fsh_ilistino[0]));
if (!infp->vsi_ilist) {
printk(KERN_ERR "vxfs: unable to get inode list inode\n");
kfree(tip);
goto out_iput_stilist;
}
if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) {
......@@ -184,6 +172,8 @@ vxfs_read_fshead(struct super_block *sbp)
goto out_iput_ilist;
}
kfree(pfp);
kfree(sfp);
return 0;
out_iput_ilist:
......@@ -197,7 +187,4 @@ vxfs_read_fshead(struct super_block *sbp)
out_iput_fship:
iput(infp->vsi_fship);
return -EINVAL;
out_free_fship:
kfree(vip);
return -EINVAL;
}
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -42,20 +43,20 @@
* Fileset header
*/
struct vxfs_fsh {
u_int32_t fsh_version; /* fileset header version */
u_int32_t fsh_fsindex; /* fileset index */
u_int32_t fsh_time; /* modification time - sec */
u_int32_t fsh_utime; /* modification time - usec */
u_int32_t fsh_extop; /* extop flags */
vx_ino_t fsh_ninodes; /* allocated inodes */
u_int32_t fsh_nau; /* number of IAUs */
u_int32_t fsh_old_ilesize; /* old size of ilist */
u_int32_t fsh_dflags; /* flags */
u_int32_t fsh_quota; /* quota limit */
vx_ino_t fsh_maxinode; /* maximum inode number */
vx_ino_t fsh_iauino; /* IAU inode */
vx_ino_t fsh_ilistino[2]; /* ilist inodes */
vx_ino_t fsh_lctino; /* link count table inode */
__fs32 fsh_version; /* fileset header version */
__fs32 fsh_fsindex; /* fileset index */
__fs32 fsh_time; /* modification time - sec */
__fs32 fsh_utime; /* modification time - usec */
__fs32 fsh_extop; /* extop flags */
__fs32 fsh_ninodes; /* allocated inodes */
__fs32 fsh_nau; /* number of IAUs */
__fs32 fsh_old_ilesize; /* old size of ilist */
__fs32 fsh_dflags; /* flags */
__fs32 fsh_quota; /* quota limit */
__fs32 fsh_maxinode; /* maximum inode number */
__fs32 fsh_iauino; /* IAU inode */
__fs32 fsh_ilistino[2]; /* ilist inodes */
__fs32 fsh_lctino; /* link count table inode */
/*
* Slightly more fields follow, but they
......
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -42,9 +43,6 @@
#include "vxfs_extern.h"
struct kmem_cache *vxfs_inode_cachep;
#ifdef DIAGNOSTIC
/*
* Dump inode contents (partially).
......@@ -68,6 +66,83 @@ vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino)
}
#endif
/**
* vxfs_transmod - mode for a VxFS inode
* @vip: VxFS inode
*
* Description:
* vxfs_transmod returns a Linux mode_t for a given
* VxFS inode structure.
*/
static __inline__ umode_t
vxfs_transmod(struct vxfs_inode_info *vip)
{
umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK;
if (VXFS_ISFIFO(vip))
ret |= S_IFIFO;
if (VXFS_ISCHR(vip))
ret |= S_IFCHR;
if (VXFS_ISDIR(vip))
ret |= S_IFDIR;
if (VXFS_ISBLK(vip))
ret |= S_IFBLK;
if (VXFS_ISLNK(vip))
ret |= S_IFLNK;
if (VXFS_ISREG(vip))
ret |= S_IFREG;
if (VXFS_ISSOC(vip))
ret |= S_IFSOCK;
return (ret);
}
static inline void dip2vip_cpy(struct vxfs_sb_info *sbi,
struct vxfs_inode_info *vip, struct vxfs_dinode *dip)
{
struct inode *inode = &vip->vfs_inode;
vip->vii_mode = fs32_to_cpu(sbi, dip->vdi_mode);
vip->vii_nlink = fs32_to_cpu(sbi, dip->vdi_nlink);
vip->vii_uid = fs32_to_cpu(sbi, dip->vdi_uid);
vip->vii_gid = fs32_to_cpu(sbi, dip->vdi_gid);
vip->vii_size = fs64_to_cpu(sbi, dip->vdi_size);
vip->vii_atime = fs32_to_cpu(sbi, dip->vdi_atime);
vip->vii_autime = fs32_to_cpu(sbi, dip->vdi_autime);
vip->vii_mtime = fs32_to_cpu(sbi, dip->vdi_mtime);
vip->vii_mutime = fs32_to_cpu(sbi, dip->vdi_mutime);
vip->vii_ctime = fs32_to_cpu(sbi, dip->vdi_ctime);
vip->vii_cutime = fs32_to_cpu(sbi, dip->vdi_cutime);
vip->vii_orgtype = dip->vdi_orgtype;
vip->vii_blocks = fs32_to_cpu(sbi, dip->vdi_blocks);
vip->vii_gen = fs32_to_cpu(sbi, dip->vdi_gen);
if (VXFS_ISDIR(vip))
vip->vii_dotdot = fs32_to_cpu(sbi, dip->vdi_dotdot);
else if (!VXFS_ISREG(vip) && !VXFS_ISLNK(vip))
vip->vii_rdev = fs32_to_cpu(sbi, dip->vdi_rdev);
/* don't endian swap the fields that differ by orgtype */
memcpy(&vip->vii_org, &dip->vdi_org, sizeof(vip->vii_org));
inode->i_mode = vxfs_transmod(vip);
i_uid_write(inode, (uid_t)vip->vii_uid);
i_gid_write(inode, (gid_t)vip->vii_gid);
set_nlink(inode, vip->vii_nlink);
inode->i_size = vip->vii_size;
inode->i_atime.tv_sec = vip->vii_atime;
inode->i_ctime.tv_sec = vip->vii_ctime;
inode->i_mtime.tv_sec = vip->vii_mtime;
inode->i_atime.tv_nsec = 0;
inode->i_ctime.tv_nsec = 0;
inode->i_mtime.tv_nsec = 0;
inode->i_blocks = vip->vii_blocks;
inode->i_generation = vip->vii_gen;
}
/**
* vxfs_blkiget - find inode based on extent #
......@@ -85,50 +160,55 @@ 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 *
struct inode *
vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino)
{
struct buffer_head *bp;
struct inode *inode;
u_long block, offset;
inode = new_inode(sbp);
if (!inode)
return NULL;
inode->i_ino = get_next_ino();
block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize);
offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE);
bp = sb_bread(sbp, block);
if (bp && buffer_mapped(bp)) {
struct vxfs_inode_info *vip;
struct vxfs_inode_info *vip = VXFS_INO(inode);
struct vxfs_dinode *dip;
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(VXFS_SBI(sbp), vip, dip);
vip->vfs_inode.i_mapping->a_ops = &vxfs_aops;
#ifdef DIAGNOSTIC
vxfs_dumpi(vip, ino);
#endif
brelse(bp);
return (vip);
return inode;
}
fail:
printk(KERN_WARNING "vxfs: unable to read block %ld\n", block);
brelse(bp);
iput(inode);
return NULL;
}
/**
* __vxfs_iget - generic find inode facility
* @sbp: VFS superblock
* @ino: inode number
* @ilistp: inode list
* @vip: VxFS inode to fill in
* @ino: inode number
*
* Description:
* Search the for inode number @ino in the filesystem
* described by @sbp. Use the specified inode table (@ilistp).
* Returns the matching VxFS inode on success, else an error code.
* Returns the matching inode on success, else an error code.
*/
static struct vxfs_inode_info *
__vxfs_iget(ino_t ino, struct inode *ilistp)
static int
__vxfs_iget(struct inode *ilistp, struct vxfs_inode_info *vip, ino_t ino)
{
struct page *pp;
u_long offset;
......@@ -137,28 +217,22 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
pp = vxfs_get_page(ilistp->i_mapping, ino * VXFS_ISIZE / PAGE_SIZE);
if (!IS_ERR(pp)) {
struct vxfs_inode_info *vip;
struct vxfs_dinode *dip;
caddr_t kaddr = (char *)page_address(pp);
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(VXFS_SBI(ilistp->i_sb), vip, dip);
vip->vfs_inode.i_mapping->a_ops = &vxfs_aops;
#ifdef DIAGNOSTIC
vxfs_dumpi(vip, ino);
#endif
vxfs_put_page(pp);
return (vip);
return 0;
}
printk(KERN_WARNING "vxfs: error on page %p\n", pp);
return ERR_CAST(pp);
fail:
printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino);
vxfs_put_page(pp);
return ERR_PTR(-ENOMEM);
printk(KERN_WARNING "vxfs: error on page 0x%p for inode %ld\n",
pp, (unsigned long)ino);
return PTR_ERR(pp);
}
/**
......@@ -169,116 +243,26 @@ __vxfs_iget(ino_t ino, struct inode *ilistp)
* Description:
* Find inode @ino in the filesystem described by @sbp using
* the structural inode list.
* Returns the matching VxFS inode on success, else a NULL pointer.
*/
struct vxfs_inode_info *
vxfs_stiget(struct super_block *sbp, ino_t ino)
{
struct vxfs_inode_info *vip;
vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist);
return IS_ERR(vip) ? NULL : vip;
}
/**
* vxfs_transmod - mode for a VxFS inode
* @vip: VxFS inode
*
* Description:
* vxfs_transmod returns a Linux mode_t for a given
* VxFS inode structure.
*/
static __inline__ umode_t
vxfs_transmod(struct vxfs_inode_info *vip)
{
umode_t ret = vip->vii_mode & ~VXFS_TYPE_MASK;
if (VXFS_ISFIFO(vip))
ret |= S_IFIFO;
if (VXFS_ISCHR(vip))
ret |= S_IFCHR;
if (VXFS_ISDIR(vip))
ret |= S_IFDIR;
if (VXFS_ISBLK(vip))
ret |= S_IFBLK;
if (VXFS_ISLNK(vip))
ret |= S_IFLNK;
if (VXFS_ISREG(vip))
ret |= S_IFREG;
if (VXFS_ISSOC(vip))
ret |= S_IFSOCK;
return (ret);
}
/**
* vxfs_iinit- helper to fill inode fields
* @ip: VFS inode
* @vip: VxFS inode
*
* Description:
* vxfs_instino is a helper function to fill in all relevant
* fields in @ip from @vip.
*/
static void
vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip)
{
ip->i_mode = vxfs_transmod(vip);
i_uid_write(ip, (uid_t)vip->vii_uid);
i_gid_write(ip, (gid_t)vip->vii_gid);
set_nlink(ip, vip->vii_nlink);
ip->i_size = vip->vii_size;
ip->i_atime.tv_sec = vip->vii_atime;
ip->i_ctime.tv_sec = vip->vii_ctime;
ip->i_mtime.tv_sec = vip->vii_mtime;
ip->i_atime.tv_nsec = 0;
ip->i_ctime.tv_nsec = 0;
ip->i_mtime.tv_nsec = 0;
ip->i_blocks = vip->vii_blocks;
ip->i_generation = vip->vii_gen;
ip->i_private = vip;
}
/**
* vxfs_get_fake_inode - get fake inode structure
* @sbp: filesystem superblock
* @vip: fspriv inode
*
* Description:
* vxfs_fake_inode gets a fake inode (not in the inode hash) for a
* superblock, vxfs_inode pair.
* Returns the filled VFS inode.
* Returns the matching inode on success, else a NULL pointer.
*/
struct inode *
vxfs_get_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip)
vxfs_stiget(struct super_block *sbp, ino_t ino)
{
struct inode *ip = NULL;
if ((ip = new_inode(sbp))) {
ip->i_ino = get_next_ino();
vxfs_iinit(ip, vip);
ip->i_mapping->a_ops = &vxfs_aops;
struct inode *inode;
int error;
inode = new_inode(sbp);
if (!inode)
return NULL;
inode->i_ino = get_next_ino();
error = __vxfs_iget(VXFS_SBI(sbp)->vsi_stilist, VXFS_INO(inode), ino);
if (error) {
iput(inode);
return NULL;
}
return (ip);
}
/**
* vxfs_put_fake_inode - free faked inode
* *ip: VFS inode
*
* Description:
* vxfs_put_fake_inode frees all data associated with @ip.
*/
void
vxfs_put_fake_inode(struct inode *ip)
{
iput(ip);
return inode;
}
/**
......@@ -296,6 +280,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
struct vxfs_inode_info *vip;
const struct address_space_operations *aops;
struct inode *ip;
int error;
ip = iget_locked(sbp, ino);
if (!ip)
......@@ -303,14 +288,13 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
if (!(ip->i_state & I_NEW))
return ip;
vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist);
if (IS_ERR(vip)) {
vip = VXFS_INO(ip);
error = __vxfs_iget(VXFS_SBI(sbp)->vsi_ilist, vip, ino);
if (error) {
iget_failed(ip);
return ERR_CAST(vip);
return ERR_PTR(error);
}
vxfs_iinit(ip, vip);
if (VXFS_ISIMMED(vip))
aops = &vxfs_immed_aops;
else
......@@ -341,12 +325,6 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
return ip;
}
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);
}
/**
* vxfs_evict_inode - remove inode from main memory
* @ip: inode to discard.
......@@ -360,5 +338,4 @@ vxfs_evict_inode(struct inode *ip)
{
truncate_inode_pages_final(&ip->i_data);
clear_inode(ip);
call_rcu(&ip->i_rcu, vxfs_i_callback);
}
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -66,74 +67,74 @@ enum {
* Data stored immediately in the inode.
*/
struct vxfs_immed {
u_int8_t vi_immed[VXFS_NIMMED];
__u8 vi_immed[VXFS_NIMMED];
};
struct vxfs_ext4 {
u_int32_t ve4_spare; /* ?? */
u_int32_t ve4_indsize; /* Indirect extent size */
vx_daddr_t ve4_indir[VXFS_NIADDR]; /* Indirect extents */
__fs32 ve4_spare; /* ?? */
__fs32 ve4_indsize; /* Indirect extent size */
__fs32 ve4_indir[VXFS_NIADDR]; /* Indirect extents */
struct direct { /* Direct extents */
vx_daddr_t extent; /* Extent number */
int32_t size; /* Size of extent */
__fs32 extent; /* Extent number */
__fs32 size; /* Size of extent */
} ve4_direct[VXFS_NDADDR];
};
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 */
__fs64 vt_hdr; /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
__fs32 vt_block; /* Extent block */
__fs32 vt_size; /* Size in blocks */
};
struct vxfs_typed_dev4 {
u_int64_t vd4_hdr; /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
u_int64_t vd4_block; /* Extent block */
u_int64_t vd4_size; /* Size in blocks */
int32_t vd4_dev; /* Device ID */
u_int32_t __pad1;
__fs64 vd4_hdr; /* Header, 0xTTOOOOOOOOOOOOOO; T=type,O=offs */
__fs64 vd4_block; /* Extent block */
__fs64 vd4_size; /* Size in blocks */
__fs32 vd4_dev; /* Device ID */
__u8 __pad1;
};
/*
* The inode as contained on the physical device.
*/
struct vxfs_dinode {
int32_t vdi_mode;
u_int32_t vdi_nlink; /* Link count */
u_int32_t vdi_uid; /* UID */
u_int32_t vdi_gid; /* GID */
u_int64_t vdi_size; /* Inode size in bytes */
u_int32_t vdi_atime; /* Last time accessed - sec */
u_int32_t vdi_autime; /* Last time accessed - usec */
u_int32_t vdi_mtime; /* Last modify time - sec */
u_int32_t vdi_mutime; /* Last modify time - usec */
u_int32_t vdi_ctime; /* Create time - sec */
u_int32_t vdi_cutime; /* Create time - usec */
u_int8_t vdi_aflags; /* Allocation flags */
u_int8_t vdi_orgtype; /* Organisation type */
u_int16_t vdi_eopflags;
u_int32_t vdi_eopdata;
__fs32 vdi_mode;
__fs32 vdi_nlink; /* Link count */
__fs32 vdi_uid; /* UID */
__fs32 vdi_gid; /* GID */
__fs64 vdi_size; /* Inode size in bytes */
__fs32 vdi_atime; /* Last time accessed - sec */
__fs32 vdi_autime; /* Last time accessed - usec */
__fs32 vdi_mtime; /* Last modify time - sec */
__fs32 vdi_mutime; /* Last modify time - usec */
__fs32 vdi_ctime; /* Create time - sec */
__fs32 vdi_cutime; /* Create time - usec */
__u8 vdi_aflags; /* Allocation flags */
__u8 vdi_orgtype; /* Organisation type */
__fs16 vdi_eopflags;
__fs32 vdi_eopdata;
union {
u_int32_t rdev;
u_int32_t dotdot;
__fs32 rdev;
__fs32 dotdot;
struct {
u_int32_t reserved;
u_int32_t fixextsize;
__u32 reserved;
__fs32 fixextsize;
} i_regular;
struct {
u_int32_t matchino;
u_int32_t fsetindex;
__fs32 matchino;
__fs32 fsetindex;
} i_vxspec;
u_int64_t align;
__u64 align;
} vdi_ftarea;
u_int32_t vdi_blocks; /* How much blocks does inode occupy */
u_int32_t vdi_gen; /* Inode generation */
u_int64_t vdi_version; /* Version */
__fs32 vdi_blocks; /* How much blocks does inode occupy */
__fs32 vdi_gen; /* Inode generation */
__fs64 vdi_version; /* Version */
union {
struct vxfs_immed immed;
struct vxfs_ext4 ext4;
struct vxfs_typed typed[VXFS_NTYPED];
} vdi_org;
u_int32_t vdi_iattrino;
__fs32 vdi_iattrino;
};
#define vdi_rdev vdi_ftarea.rdev
......@@ -149,32 +150,45 @@ struct vxfs_dinode {
/*
* The inode as represented in the main memory.
*
* TBD: This should become a separate structure...
*/
#define vxfs_inode_info vxfs_dinode
#define vii_mode vdi_mode
#define vii_uid vdi_uid
#define vii_gid vdi_gid
#define vii_nlink vdi_nlink
#define vii_size vdi_size
#define vii_atime vdi_atime
#define vii_ctime vdi_ctime
#define vii_mtime vdi_mtime
#define vii_blocks vdi_blocks
#define vii_org vdi_org
#define vii_orgtype vdi_orgtype
#define vii_gen vdi_gen
#define vii_rdev vdi_ftarea.rdev
#define vii_dotdot vdi_ftarea.dotdot
#define vii_fixextsize vdi_ftarea.regular.fixextsize
#define vii_matchino vdi_ftarea.vxspec.matchino
#define vii_fsetindex vdi_ftarea.vxspec.fsetindex
#define vii_immed vdi_org.immed
#define vii_ext4 vdi_org.ext4
#define vii_typed vdi_org.typed
struct vxfs_inode_info {
struct inode vfs_inode;
__u32 vii_mode;
__u32 vii_nlink; /* Link count */
__u32 vii_uid; /* UID */
__u32 vii_gid; /* GID */
__u64 vii_size; /* Inode size in bytes */
__u32 vii_atime; /* Last time accessed - sec */
__u32 vii_autime; /* Last time accessed - usec */
__u32 vii_mtime; /* Last modify time - sec */
__u32 vii_mutime; /* Last modify time - usec */
__u32 vii_ctime; /* Create time - sec */
__u32 vii_cutime; /* Create time - usec */
__u8 vii_orgtype; /* Organisation type */
union {
__u32 rdev;
__u32 dotdot;
} vii_ftarea;
__u32 vii_blocks; /* How much blocks does inode occupy */
__u32 vii_gen; /* Inode generation */
union {
struct vxfs_immed immed;
struct vxfs_ext4 ext4;
struct vxfs_typed typed[VXFS_NTYPED];
} vii_org;
};
#define vii_rdev vii_ftarea.rdev
#define vii_dotdot vii_ftarea.dotdot
#define vii_immed vii_org.immed
#define vii_ext4 vii_org.ext4
#define vii_typed vii_org.typed
static inline struct vxfs_inode_info *VXFS_INO(struct inode *inode)
{
return container_of(inode, struct vxfs_inode_info, vfs_inode);
}
#endif /* _VXFS_INODE_H_ */
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -61,33 +62,6 @@ const struct file_operations vxfs_dir_operations = {
.iterate_shared = vxfs_readdir,
};
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_find_entry - find a mathing directory entry for a dentry
......@@ -106,50 +80,64 @@ 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;
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;
struct vxfs_sb_info *sbi = VXFS_SBI(ip->i_sb);
pp = vxfs_get_page(ip->i_mapping, page);
while (pos < limit) {
struct page *pp;
char *kaddr;
int pg_ofs = pos & ~PAGE_MASK;
pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
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);
}
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_MASK));
int overhead = VXFS_DIRBLKOV(sbi, dbp);
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(sbi, de->d_reclen);
pos += fs16_to_cpu(sbi, de->d_reclen);
if (!de->d_ino)
continue;
if (namelen != fs16_to_cpu(sbi, 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;
}
/**
......@@ -173,7 +161,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
de = vxfs_find_entry(dip, dp, &pp);
if (de) {
ino = de->d_ino;
ino = fs32_to_cpu(VXFS_SBI(dip->i_sb), de->d_ino);
kunmap(pp);
put_page(pp);
}
......@@ -233,74 +221,80 @@ 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;
struct vxfs_sb_info *sbi = VXFS_SBI(sbp);
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)
goto out;
page = pos >> PAGE_SHIFT;
offset = pos & ~PAGE_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_MASK;
int rc = 0;
pp = vxfs_get_page(ip->i_mapping, page);
pp = vxfs_get_page(ip->i_mapping, pos >> PAGE_SHIFT);
if (IS_ERR(pp))
continue;
return -ENOMEM;
kaddr = (char *)page_address(pp);
for (; block <= nblocks && block <= pblocks; block++) {
char *baddr, *limit;
struct vxfs_dirblk *dbp;
struct vxfs_direct *de;
while (pg_ofs < PAGE_SIZE && pos < limit) {
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_SHIFT) | offset) + 2;
if (!dir_emit(ctx, de->d_name, de->d_namelen,
de->d_ino, DT_UNKNOWN)) {
vxfs_put_page(pp);
return 0;
}
if ((pos & (bsize - 1)) < 4) {
struct vxfs_dirblk *dbp =
(struct vxfs_dirblk *)
(kaddr + (pos & ~PAGE_MASK));
int overhead = VXFS_DIRBLKOV(sbi, dbp);
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(sbi, de->d_reclen);
pos += fs16_to_cpu(sbi, de->d_reclen);
if (!de->d_ino)
continue;
rc = dir_emit(ctx, de->d_name,
fs16_to_cpu(sbi, de->d_namelen),
fs32_to_cpu(sbi, de->d_ino),
DT_UNKNOWN);
if (!rc) {
/* the dir entry was not read, fix pos. */
pos -= fs16_to_cpu(sbi, de->d_reclen);
break;
}
offset = 0;
}
vxfs_put_page(pp);
offset = 0;
if (!rc)
break;
}
ctx->pos = ((page << PAGE_SHIFT) | offset) + 2;
ctx->pos = pos | 2;
out:
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, 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, ilistp->olt_iext[0]);
}
static inline u_long
......@@ -81,13 +81,12 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
struct vxfs_olt *op;
char *oaddr, *eaddr;
bp = sb_bread(sbp, vxfs_oblock(sbp, infp->vsi_oltext, bsize));
if (!bp || !bp->b_data)
goto fail;
op = (struct vxfs_olt *)bp->b_data;
if (op->olt_magic != VXFS_OLT_MAGIC) {
if (fs32_to_cpu(infp, op->olt_magic) != VXFS_OLT_MAGIC) {
printk(KERN_NOTICE "vxfs: ivalid olt magic number\n");
goto fail;
}
......@@ -102,14 +101,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(infp, 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(infp, ocp->olt_type)) {
case VXFS_OLT_FSHEAD:
vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp);
break;
......@@ -118,11 +117,11 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
break;
}
oaddr += ocp->olt_size;
oaddr += fs32_to_cpu(infp, ocp->olt_size);
}
brelse(bp);
return 0;
return (infp->vsi_fshino && infp->vsi_iext) ? 0 : -EINVAL;
fail:
brelse(bp);
......
......@@ -63,83 +63,83 @@ enum {
* the initial inode list, the fileset header or the device configuration.
*/
struct vxfs_olt {
u_int32_t olt_magic; /* magic number */
u_int32_t olt_size; /* size of this entry */
u_int32_t olt_checksum; /* checksum of extent */
u_int32_t __unused1; /* ??? */
u_int32_t olt_mtime; /* time of last mod. (sec) */
u_int32_t olt_mutime; /* time of last mod. (usec) */
u_int32_t olt_totfree; /* free space in OLT extent */
vx_daddr_t olt_extents[2]; /* addr of this extent, replica */
u_int32_t olt_esize; /* size of this extent */
vx_daddr_t olt_next[2]; /* addr of next extent, replica */
u_int32_t olt_nsize; /* size of next extent */
u_int32_t __unused2; /* align to 8 byte boundary */
__fs32 olt_magic; /* magic number */
__fs32 olt_size; /* size of this entry */
__fs32 olt_checksum; /* checksum of extent */
__u32 __unused1; /* ??? */
__fs32 olt_mtime; /* time of last mod. (sec) */
__fs32 olt_mutime; /* time of last mod. (usec) */
__fs32 olt_totfree; /* free space in OLT extent */
__fs32 olt_extents[2]; /* addr of this extent, replica */
__fs32 olt_esize; /* size of this extent */
__fs32 olt_next[2]; /* addr of next extent, replica */
__fs32 olt_nsize; /* size of next extent */
__u32 __unused2; /* align to 8 byte boundary */
};
/*
* VxFS common OLT entry (on disk).
*/
struct vxfs_oltcommon {
u_int32_t olt_type; /* type of this record */
u_int32_t olt_size; /* size of this record */
__fs32 olt_type; /* type of this record */
__fs32 olt_size; /* size of this record */
};
/*
* VxFS free OLT entry (on disk).
*/
struct vxfs_oltfree {
u_int32_t olt_type; /* type of this record */
u_int32_t olt_fsize; /* size of this free record */
__fs32 olt_type; /* type of this record */
__fs32 olt_fsize; /* size of this free record */
};
/*
* VxFS initial-inode list (on disk).
*/
struct vxfs_oltilist {
u_int32_t olt_type; /* type of this record */
u_int32_t olt_size; /* size of this record */
vx_ino_t olt_iext[2]; /* initial inode list, replica */
__fs32 olt_type; /* type of this record */
__fs32 olt_size; /* size of this record */
__fs32 olt_iext[2]; /* initial inode list, replica */
};
/*
* Current Usage Table
*/
struct vxfs_oltcut {
u_int32_t olt_type; /* type of this record */
u_int32_t olt_size; /* size of this record */
vx_ino_t olt_cutino; /* inode of current usage table */
u_int32_t __pad; /* unused, 8 byte align */
__fs32 olt_type; /* type of this record */
__fs32 olt_size; /* size of this record */
__fs32 olt_cutino; /* inode of current usage table */
__u8 __pad; /* unused, 8 byte align */
};
/*
* Inodes containing Superblock, Intent log and OLTs
*/
struct vxfs_oltsb {
u_int32_t olt_type; /* type of this record */
u_int32_t olt_size; /* size of this record */
vx_ino_t olt_sbino; /* inode of superblock file */
u_int32_t __unused1; /* ??? */
vx_ino_t olt_logino[2]; /* inode of log file,replica */
vx_ino_t olt_oltino[2]; /* inode of OLT, replica */
__fs32 olt_type; /* type of this record */
__fs32 olt_size; /* size of this record */
__fs32 olt_sbino; /* inode of superblock file */
__u32 __unused1; /* ??? */
__fs32 olt_logino[2]; /* inode of log file,replica */
__fs32 olt_oltino[2]; /* inode of OLT, replica */
};
/*
* Inode containing device configuration + it's replica
*/
struct vxfs_oltdev {
u_int32_t olt_type; /* type of this record */
u_int32_t olt_size; /* size of this record */
vx_ino_t olt_devino[2]; /* inode of device config files */
__fs32 olt_type; /* type of this record */
__fs32 olt_size; /* size of this record */
__fs32 olt_devino[2]; /* inode of device config files */
};
/*
* Fileset header
*/
struct vxfs_oltfshead {
u_int32_t olt_type; /* type number */
u_int32_t olt_size; /* size of this record */
vx_ino_t olt_fsino[2]; /* inodes of fileset header */
__fs32 olt_type; /* type number */
__fs32 olt_size; /* size of this record */
__fs32 olt_fsino[2]; /* inodes of fileset header */
};
#endif /* _VXFS_OLT_H_ */
/*
* Copyright (c) 2000-2001 Christoph Hellwig.
* Copyright (c) 2016 Krzysztof Blaszkowski
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
......@@ -48,22 +49,11 @@
#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");
static void vxfs_put_super(struct super_block *);
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 = {
.evict_inode = vxfs_evict_inode,
.put_super = vxfs_put_super,
.statfs = vxfs_statfs,
.remount_fs = vxfs_remount,
};
static struct kmem_cache *vxfs_inode_cachep;
/**
* vxfs_put_super - free superblock resources
......@@ -79,9 +69,9 @@ vxfs_put_super(struct super_block *sbp)
{
struct vxfs_sb_info *infp = VXFS_SBI(sbp);
vxfs_put_fake_inode(infp->vsi_fship);
vxfs_put_fake_inode(infp->vsi_ilist);
vxfs_put_fake_inode(infp->vsi_stilist);
iput(infp->vsi_fship);
iput(infp->vsi_ilist);
iput(infp->vsi_stilist);
brelse(infp->vsi_bp);
kfree(infp);
......@@ -109,14 +99,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, raw_sb->vs_dsize);
bufp->f_bfree = fs32_to_cpu(infp, 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, raw_sb->vs_ifree);
bufp->f_namelen = VXFS_NAMELEN;
return 0;
......@@ -129,6 +120,81 @@ static int vxfs_remount(struct super_block *sb, int *flags, char *data)
return 0;
}
static struct inode *vxfs_alloc_inode(struct super_block *sb)
{
struct vxfs_inode_info *vi;
vi = kmem_cache_alloc(vxfs_inode_cachep, GFP_KERNEL);
if (!vi)
return NULL;
inode_init_once(&vi->vfs_inode);
return &vi->vfs_inode;
}
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, VXFS_INO(inode));
}
static void vxfs_destroy_inode(struct inode *inode)
{
call_rcu(&inode->i_rcu, vxfs_i_callback);
}
static const struct super_operations vxfs_super_ops = {
.alloc_inode = vxfs_alloc_inode,
.destroy_inode = vxfs_destroy_inode,
.evict_inode = vxfs_evict_inode,
.put_super = vxfs_put_super,
.statfs = vxfs_statfs,
.remount_fs = vxfs_remount,
};
static int vxfs_try_sb_magic(struct super_block *sbp, int silent,
unsigned blk, __fs32 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 (!silent) {
printk(KERN_WARNING
"vxfs: unable to read disk superblock at %u\n",
blk);
}
break;
}
rc = -EINVAL;
rsbp = (struct vxfs_sb *)bp->b_data;
if (rsbp->vs_magic != magic) {
if (!silent)
printk(KERN_NOTICE
"vxfs: WRONG superblock magic %08x at %u\n",
rsbp->vs_magic, blk);
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 +215,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;
......@@ -168,42 +234,43 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
goto out;
}
bp = sb_bread(sbp, 1);
if (!bp || !buffer_mapped(bp)) {
if (!silent) {
printk(KERN_WARNING
"vxfs: unable to read disk superblock\n");
}
goto out;
}
sbp->s_op = &vxfs_super_ops;
sbp->s_fs_info = infp;
rsbp = (struct vxfs_sb *)bp->b_data;
if (rsbp->vs_magic != VXFS_SUPER_MAGIC) {
if (!vxfs_try_sb_magic(sbp, silent, 1,
(__force __fs32)cpu_to_le32(VXFS_SUPER_MAGIC))) {
/* Unixware, x86 */
infp->byte_order = VXFS_BO_LE;
} else if (!vxfs_try_sb_magic(sbp, silent, 8,
(__force __fs32)cpu_to_be32(VXFS_SUPER_MAGIC))) {
/* HP-UX, parisc */
infp->byte_order = VXFS_BO_BE;
} else {
if (!silent)
printk(KERN_NOTICE "vxfs: WRONG superblock magic\n");
printk(KERN_NOTICE "vxfs: can't find superblock.\n");
goto out;
}
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, 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);
printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", j);
printk(KERN_DEBUG "vxfs: blocksize: %d\n",
fs32_to_cpu(infp, rsbp->vs_bsize));
#endif
sbp->s_magic = rsbp->vs_magic;
sbp->s_fs_info = infp;
sbp->s_magic = fs32_to_cpu(infp, 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, rsbp->vs_oltext[0]);
infp->vsi_oltsize = fs32_to_cpu(infp, rsbp->vs_oltsize);
if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) {
j = fs32_to_cpu(infp, rsbp->vs_bsize);
if (!sb_set_blocksize(sbp, j)) {
printk(KERN_WARNING "vxfs: unable to set final block size\n");
goto out;
}
......@@ -218,7 +285,6 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
goto out;
}
sbp->s_op = &vxfs_super_ops;
root = vxfs_iget(sbp, VXFS_ROOT_INO);
if (IS_ERR(root)) {
ret = PTR_ERR(root);
......@@ -233,11 +299,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
return 0;
out_free_ilist:
vxfs_put_fake_inode(infp->vsi_fship);
vxfs_put_fake_inode(infp->vsi_ilist);
vxfs_put_fake_inode(infp->vsi_stilist);
iput(infp->vsi_fship);
iput(infp->vsi_ilist);
iput(infp->vsi_stilist);
out:
brelse(bp);
brelse(infp->vsi_bp);
kfree(infp);
return ret;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment