diff options
author | Krzysztof Błaszkowski <kb@sysmikro.com.pl> | 2016-05-31 08:45:13 +0200 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2016-06-01 09:01:28 +0200 |
commit | 0d83f7fc83f77d1cc8395b9e851325d8cc1892e3 (patch) | |
tree | 9cfc6aef0a098884097fd37bb413639e8e76f461 /fs/freevxfs/vxfs_super.c | |
parent | 6b15d6650c5301ce023d8df0cc3a60b1a76d377e (diff) |
freevxfs: handle big endian HP-UX file systems
To support VxFS filesystems from HP-UX on x86 systems we need to
implement byte swapping, and to keep support for Unixware filesystems
it needs to be the complicated dual-endian kind ala sysvfs.
To do this properly we have to split the on disk and in-core inode
so that we can keep the in-core one in native endianness. All other
structures are byteswapped on demand.
Signed-off-by: Krzysztof Błaszkowski <kb@sysmikro.com.pl>
[hch: make spare happy]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/freevxfs/vxfs_super.c')
-rw-r--r-- | fs/freevxfs/vxfs_super.c | 101 |
1 files changed, 73 insertions, 28 deletions
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 7ca8c75d50d3..6124091b4fdb 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -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, 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 +130,50 @@ 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 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 +194,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 +213,42 @@ 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_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; } @@ -237,7 +282,7 @@ out_free_ilist: vxfs_put_fake_inode(infp->vsi_ilist); vxfs_put_fake_inode(infp->vsi_stilist); out: - brelse(bp); + brelse(infp->vsi_bp); kfree(infp); return ret; } |