diff options
Diffstat (limited to 'fs/freevxfs')
-rw-r--r-- | fs/freevxfs/Makefile | 8 | ||||
-rw-r--r-- | fs/freevxfs/vxfs.h | 264 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_bmap.c | 280 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_dir.h | 92 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_extern.h | 76 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_fshead.c | 202 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_fshead.h | 67 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_immed.c | 114 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_inode.c | 351 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_inode.h | 180 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_kcompat.h | 49 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_lookup.c | 328 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_olt.c | 132 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_olt.h | 145 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_subr.c | 190 | ||||
-rw-r--r-- | fs/freevxfs/vxfs_super.c | 278 |
16 files changed, 2756 insertions, 0 deletions
diff --git a/fs/freevxfs/Makefile b/fs/freevxfs/Makefile new file mode 100644 index 00000000000..87ad097440d --- /dev/null +++ b/fs/freevxfs/Makefile @@ -0,0 +1,8 @@ +# +# VxFS Makefile +# + +obj-$(CONFIG_VXFS_FS) += freevxfs.o + +freevxfs-objs := vxfs_bmap.o vxfs_fshead.o vxfs_immed.o vxfs_inode.o \ + vxfs_lookup.o vxfs_olt.o vxfs_subr.o vxfs_super.o diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h new file mode 100644 index 00000000000..8da0252642a --- /dev/null +++ b/fs/freevxfs/vxfs.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef _VXFS_SUPER_H_ +#define _VXFS_SUPER_H_ + +/* + * Veritas filesystem driver - superblock structure. + * + * This file contains the definition of the disk and core + * superblocks of the Veritas Filesystem. + */ +#include <linux/types.h> +#include "vxfs_kcompat.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). + */ +#define VXFS_SUPER_MAGIC 0xa501FCF5 + +/* + * The root inode. + */ +#define VXFS_ROOT_INO 2 + +/* + * Num of entries in free extent array + */ +#define VXFS_NEFREE 32 + + +/* + * VxFS superblock (disk). + */ +struct vxfs_sb { + /* + * Readonly fields for the version 1 superblock. + * + * 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 */ + + /* + * 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 */ + + /* + * 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 */ + + /* + * Actually much more... + */ +}; + + +/* + * In core superblock filesystem private data for VxFS. + */ +struct vxfs_sb_info { + struct vxfs_sb *vsi_raw; /* raw (on disk) supeblock */ + struct buffer_head *vsi_bp; /* buffer for raw superblock*/ + struct inode *vsi_fship; /* fileset header inode */ + struct inode *vsi_ilist; /* inode list inode */ + struct inode *vsi_stilist; /* structual inode list inode */ + u_long vsi_iext; /* initial inode list */ + ino_t vsi_fshino; /* fileset header inode */ + daddr_t vsi_oltext; /* OLT extent */ + daddr_t vsi_oltsize; /* OLT size */ +}; + + +/* + * 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 + * never have one of the regular file type bits set. + */ +enum vxfs_mode { + VXFS_ISUID = 0x00000800, /* setuid */ + VXFS_ISGID = 0x00000400, /* setgid */ + VXFS_ISVTX = 0x00000200, /* sticky bit */ + VXFS_IREAD = 0x00000100, /* read */ + VXFS_IWRITE = 0x00000080, /* write */ + VXFS_IEXEC = 0x00000040, /* exec */ + + VXFS_IFIFO = 0x00001000, /* Named pipe */ + VXFS_IFCHR = 0x00002000, /* Character device */ + VXFS_IFDIR = 0x00004000, /* Directory */ + VXFS_IFNAM = 0x00005000, /* Xenix device ?? */ + VXFS_IFBLK = 0x00006000, /* Block device */ + VXFS_IFREG = 0x00008000, /* Regular file */ + VXFS_IFCMP = 0x00009000, /* Compressed file ?!? */ + VXFS_IFLNK = 0x0000a000, /* Symlink */ + VXFS_IFSOC = 0x0000c000, /* Socket */ + + /* VxFS internal */ + VXFS_IFFSH = 0x10000000, /* Fileset header */ + VXFS_IFILT = 0x20000000, /* Inode list */ + VXFS_IFIAU = 0x30000000, /* Inode allocation unit */ + VXFS_IFCUT = 0x40000000, /* Current usage table */ + VXFS_IFATT = 0x50000000, /* Attr. inode */ + VXFS_IFLCT = 0x60000000, /* Link count table */ + VXFS_IFIAT = 0x70000000, /* Indirect attribute file */ + VXFS_IFEMR = 0x80000000, /* Extent map reorg file */ + VXFS_IFQUO = 0x90000000, /* BSD quota file */ + VXFS_IFPTI = 0xa0000000, /* "Pass through" inode */ + VXFS_IFLAB = 0x11000000, /* Device label file */ + VXFS_IFOLT = 0x12000000, /* OLT file */ + VXFS_IFLOG = 0x13000000, /* Log file */ + VXFS_IFEMP = 0x14000000, /* Extent map file */ + VXFS_IFEAU = 0x15000000, /* Extent AU file */ + VXFS_IFAUS = 0x16000000, /* Extent AU summary file */ + VXFS_IFDEV = 0x17000000, /* Device config file */ + +}; + +#define VXFS_TYPE_MASK 0xfffff000 + +#define VXFS_IS_TYPE(ip,type) (((ip)->vii_mode & VXFS_TYPE_MASK) == (type)) +#define VXFS_ISFIFO(x) VXFS_IS_TYPE((x),VXFS_IFIFO) +#define VXFS_ISCHR(x) VXFS_IS_TYPE((x),VXFS_IFCHR) +#define VXFS_ISDIR(x) VXFS_IS_TYPE((x),VXFS_IFDIR) +#define VXFS_ISNAM(x) VXFS_IS_TYPE((x),VXFS_IFNAM) +#define VXFS_ISBLK(x) VXFS_IS_TYPE((x),VXFS_IFBLK) +#define VXFS_ISLNK(x) VXFS_IS_TYPE((x),VXFS_IFLNK) +#define VXFS_ISREG(x) VXFS_IS_TYPE((x),VXFS_IFREG) +#define VXFS_ISCMP(x) VXFS_IS_TYPE((x),VXFS_IFCMP) +#define VXFS_ISSOC(x) VXFS_IS_TYPE((x),VXFS_IFSOC) + +#define VXFS_ISFSH(x) VXFS_IS_TYPE((x),VXFS_IFFSH) +#define VXFS_ISILT(x) VXFS_IS_TYPE((x),VXFS_IFILT) + +/* + * Inmode organisation types. + */ +enum { + VXFS_ORG_NONE = 0, /* Inode has *no* format ?!? */ + VXFS_ORG_EXT4 = 1, /* Ext4 */ + VXFS_ORG_IMMED = 2, /* All data stored in inode */ + VXFS_ORG_TYPED = 3, /* Typed extents */ +}; + +#define VXFS_IS_ORG(ip,org) ((ip)->vii_orgtype == (org)) +#define VXFS_ISNONE(ip) VXFS_IS_ORG((ip), VXFS_ORG_NONE) +#define VXFS_ISEXT4(ip) VXFS_IS_ORG((ip), VXFS_ORG_EXT4) +#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)->u.generic_ip) + +/* + * Get filesystem private data from VFS superblock. + */ +#define VXFS_SBI(sbp) \ + ((struct vxfs_sb_info *)(sbp)->s_fs_info) + +#endif /* _VXFS_SUPER_H_ */ diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c new file mode 100644 index 00000000000..bc4b57da306 --- /dev/null +++ b/fs/freevxfs/vxfs_bmap.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - filesystem to disk block mapping. + */ +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/kernel.h> + +#include "vxfs.h" +#include "vxfs_inode.h" + + +#ifdef DIAGNOSTIC +static void +vxfs_typdump(struct vxfs_typed *typ) +{ + printk(KERN_DEBUG "type=%Lu ", typ->vt_hdr >> VXFS_TYPED_TYPESHIFT); + printk("offset=%Lx ", typ->vt_hdr & VXFS_TYPED_OFFSETMASK); + printk("block=%x ", typ->vt_block); + printk("size=%x\n", typ->vt_size); +} +#endif + +/** + * vxfs_bmap_ext4 - do bmap for ext4 extents + * @ip: pointer to the inode we do bmap for + * @iblock: logical block. + * + * Description: + * vxfs_bmap_ext4 performs the bmap operation for inodes with + * ext4-style extents (which are much like the traditional UNIX + * inode organisation). + * + * Returns: + * The physical block number on success, else Zero. + */ +static daddr_t +vxfs_bmap_ext4(struct inode *ip, long bn) +{ + struct super_block *sb = ip->i_sb; + struct vxfs_inode_info *vip = VXFS_INO(ip); + unsigned long bsize = sb->s_blocksize; + u32 indsize = vip->vii_ext4.ve4_indsize; + int i; + + if (indsize > sb->s_blocksize) + goto fail_size; + + for (i = 0; i < VXFS_NDADDR; i++) { + struct direct *d = vip->vii_ext4.ve4_direct + i; + if (bn >= 0 && bn < d->size) + return (bn + d->extent); + bn -= d->size; + } + + if ((bn / (indsize * indsize * bsize / 4)) == 0) { + struct buffer_head *buf; + daddr_t bno; + u32 *indir; + + buf = sb_bread(sb, 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); + + brelse(buf); + return bno; + } else + printk(KERN_WARNING "no matching indir?"); + + return 0; + +fail_size: + printk("vxfs: indirect extent to big!\n"); +fail_buf: + return 0; +} + +/** + * vxfs_bmap_indir - recursion for vxfs_bmap_typed + * @ip: pointer to the inode we do bmap for + * @indir: indirect block we start reading at + * @size: size of the typed area to search + * @block: partially result from further searches + * + * Description: + * vxfs_bmap_indir reads a &struct vxfs_typed at @indir + * and performs the type-defined action. + * + * Return Value: + * The physical block number on success, else Zero. + * + * Note: + * Kernelstack is rare. Unrecurse? + */ +static daddr_t +vxfs_bmap_indir(struct inode *ip, long indir, int size, long block) +{ + struct buffer_head *bp = NULL; + daddr_t pblock = 0; + int i; + + for (i = 0; i < size * VXFS_TYPED_PER_BLOCK(ip->i_sb); i++) { + struct vxfs_typed *typ; + int64_t off; + + bp = sb_bread(ip->i_sb, + indir + (i / VXFS_TYPED_PER_BLOCK(ip->i_sb))); + if (!buffer_mapped(bp)) + return 0; + + typ = ((struct vxfs_typed *)bp->b_data) + + (i % VXFS_TYPED_PER_BLOCK(ip->i_sb)); + off = (typ->vt_hdr & VXFS_TYPED_OFFSETMASK); + + if (block < off) { + brelse(bp); + continue; + } + + switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) { + case VXFS_TYPED_INDIRECT: + pblock = vxfs_bmap_indir(ip, typ->vt_block, + typ->vt_size, block - off); + if (pblock == -2) + break; + goto out; + case VXFS_TYPED_DATA: + if ((block - off) >= typ->vt_size) + break; + pblock = (typ->vt_block + block - off); + goto out; + case VXFS_TYPED_INDIRECT_DEV4: + case VXFS_TYPED_DATA_DEV4: { + struct vxfs_typed_dev4 *typ4 = + (struct vxfs_typed_dev4 *)typ; + + printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n"); + printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n", + (unsigned long long) typ4->vd4_block, + (unsigned long long) typ4->vd4_size, + typ4->vd4_dev); + goto fail; + } + default: + BUG(); + } + brelse(bp); + } + +fail: + pblock = 0; +out: + brelse(bp); + return (pblock); +} + +/** + * vxfs_bmap_typed - bmap for typed extents + * @ip: pointer to the inode we do bmap for + * @iblock: logical block + * + * Description: + * Performs the bmap operation for typed extents. + * + * Return Value: + * The physical block number on success, else Zero. + */ +static daddr_t +vxfs_bmap_typed(struct inode *ip, long iblock) +{ + struct vxfs_inode_info *vip = VXFS_INO(ip); + daddr_t pblock = 0; + int i; + + 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); + +#ifdef DIAGNOSTIC + vxfs_typdump(typ); +#endif + if (iblock < off) + continue; + switch ((u_int32_t)(typ->vt_hdr >> VXFS_TYPED_TYPESHIFT)) { + case VXFS_TYPED_INDIRECT: + pblock = vxfs_bmap_indir(ip, typ->vt_block, + 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); + break; + case VXFS_TYPED_INDIRECT_DEV4: + case VXFS_TYPED_DATA_DEV4: { + struct vxfs_typed_dev4 *typ4 = + (struct vxfs_typed_dev4 *)typ; + + printk(KERN_INFO "\n\nTYPED_DEV4 detected!\n"); + printk(KERN_INFO "block: %Lu\tsize: %Ld\tdev: %d\n", + (unsigned long long) typ4->vd4_block, + (unsigned long long) typ4->vd4_size, + typ4->vd4_dev); + return 0; + } + default: + BUG(); + } + } + + return 0; +} + +/** + * vxfs_bmap1 - vxfs-internal bmap operation + * @ip: pointer to the inode we do bmap for + * @iblock: logical block + * + * Description: + * vxfs_bmap1 perfoms a logical to physical block mapping + * for vxfs-internal purposes. + * + * Return Value: + * The physical block number on success, else Zero. + */ +daddr_t +vxfs_bmap1(struct inode *ip, long iblock) +{ + struct vxfs_inode_info *vip = VXFS_INO(ip); + + if (VXFS_ISEXT4(vip)) + return vxfs_bmap_ext4(ip, iblock); + if (VXFS_ISTYPED(vip)) + return vxfs_bmap_typed(ip, iblock); + if (VXFS_ISNONE(vip)) + goto unsupp; + if (VXFS_ISIMMED(vip)) + goto unsupp; + + printk(KERN_WARNING "vxfs: inode %ld has no valid orgtype (%x)\n", + ip->i_ino, vip->vii_orgtype); + BUG(); + +unsupp: + printk(KERN_WARNING "vxfs: inode %ld has an unsupported orgtype (%x)\n", + ip->i_ino, vip->vii_orgtype); + return 0; +} diff --git a/fs/freevxfs/vxfs_dir.h b/fs/freevxfs/vxfs_dir.h new file mode 100644 index 00000000000..8a4dfef1dda --- /dev/null +++ b/fs/freevxfs/vxfs_dir.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef _VXFS_DIR_H_ +#define _VXFS_DIR_H_ + +/* + * Veritas filesystem driver - directory structure. + * + * This file contains the definition of the vxfs directory format. + */ + + +/* + * VxFS directory block header. + * + * This entry is the head of every filesystem block in a directory. + * It is used for free space managment and additionally includes + * a hash for speeding up directory search (lookup). + * + * The hash may be empty and in fact we do not use it all in the + * 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 */ +}; + +/* + * VXFS_NAMELEN is the maximum length of the d_name field + * of an VxFS directory entry. + */ +#define VXFS_NAMELEN 256 + +/* + * 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 */ + char d_name[VXFS_NAMELEN]; /* name */ +}; + +/* + * VXFS_DIRPAD defines the directory entry boundaries, is _must_ be + * a multiple of four. + * VXFS_NAMEMIN is the length of a directory entry with a NULL d_name. + * VXFS_DIRROUND is an internal macros that rounds a length to a value + * usable for directory sizes. + * VXFS_DIRLEN calculates the directory entry size for an entry with + * a d_name with size len. + */ +#define VXFS_DIRPAD 4 +#define VXFS_NAMEMIN ((int)((struct vxfs_direct *)0)->d_name) +#define VXFS_DIRROUND(len) ((VXFS_DIRPAD + (len) - 1) & ~(VXFS_DIRPAD -1)) +#define VXFS_DIRLEN(len) (VXFS_DIRROUND(VXFS_NAMEMIN + (len))) + +/* + * VXFS_DIRBLKOV is the overhead of a specific dirblock. + */ +#define VXFS_DIRBLKOV(dbp) ((sizeof(short) * dbp->d_nhash) + 4) + +#endif /* _VXFS_DIR_H_ */ diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h new file mode 100644 index 00000000000..d8be917f979 --- /dev/null +++ b/fs/freevxfs/vxfs_extern.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef _VXFS_EXTERN_H_ +#define _VXFS_EXTERN_H_ + +/* + * Veritas filesystem driver - external prototypes. + * + * This file contains prototypes for all vxfs functions used + * outside their respective source files. + */ + + +struct kmem_cache_s; +struct super_block; +struct vxfs_inode_info; +struct inode; + + +/* vxfs_bmap.c */ +extern daddr_t vxfs_bmap1(struct inode *, long); + +/* vxfs_fshead.c */ +extern int vxfs_read_fshead(struct super_block *); + +/* vxfs_inode.c */ +extern struct kmem_cache_s *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 void vxfs_read_inode(struct inode *); +extern void vxfs_clear_inode(struct inode *); + +/* vxfs_lookup.c */ +extern struct inode_operations vxfs_dir_inode_ops; +extern struct file_operations vxfs_dir_operations; + +/* vxfs_olt.c */ +extern int vxfs_read_olt(struct super_block *, u_long); + +/* vxfs_subr.c */ +extern struct page * vxfs_get_page(struct address_space *, u_long); +extern void vxfs_put_page(struct page *); +extern struct buffer_head * vxfs_bread(struct inode *, int); + +#endif /* _VXFS_EXTERN_H_ */ diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c new file mode 100644 index 00000000000..05b19f70bf9 --- /dev/null +++ b/fs/freevxfs/vxfs_fshead.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - fileset header routines. + */ +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include "vxfs.h" +#include "vxfs_inode.h" +#include "vxfs_extern.h" +#include "vxfs_fshead.h" + + +#ifdef DIAGNOSTIC +static void +vxfs_dumpfsh(struct vxfs_fsh *fhp) +{ + printk("\n\ndumping fileset header:\n"); + printk("----------------------------\n"); + printk("version: %u\n", fhp->fsh_version); + printk("fsindex: %u\n", fhp->fsh_fsindex); + printk("iauino: %u\tninodes:%u\n", + fhp->fsh_iauino, fhp->fsh_ninodes); + printk("maxinode: %u\tlctino: %u\n", + fhp->fsh_maxinode, fhp->fsh_lctino); + printk("nau: %u\n", fhp->fsh_nau); + printk("ilistino[0]: %u\tilistino[1]: %u\n", + fhp->fsh_ilistino[0], fhp->fsh_ilistino[1]); +} +#endif + +/** + * vxfs_getfsh - read fileset header into memory + * @ip: the (fake) fileset header inode + * @which: 0 for the structural, 1 for the primary fsh. + * + * Description: + * vxfs_getfsh reads either the structural or primary fileset header + * described by @ip into memory. + * + * Returns: + * The fileset header structure on success, else Zero. + */ +static struct vxfs_fsh * +vxfs_getfsh(struct inode *ip, int which) +{ + struct buffer_head *bp; + + bp = vxfs_bread(ip, which); + if (buffer_mapped(bp)) { + struct vxfs_fsh *fhp; + + if (!(fhp = kmalloc(sizeof(*fhp), SLAB_KERNEL))) + return NULL; + memcpy(fhp, bp->b_data, sizeof(*fhp)); + + brelse(bp); + return (fhp); + } + + return NULL; +} + +/** + * vxfs_read_fshead - read the fileset headers + * @sbp: superblock to which the fileset belongs + * + * Description: + * vxfs_read_fshead will fill the inode and structural inode list in @sb. + * + * Returns: + * Zero on success, else a negative error code (-EINVAL). + */ +int +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; + + vip = vxfs_blkiget(sbp, infp->vsi_iext, infp->vsi_fshino); + if (!vip) { + printk(KERN_ERR "vxfs: unabled to read fsh inode\n"); + return -EINVAL; + } + 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; + } + + +#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: unabled to get fsh inode\n"); + goto out_free_fship; + } + + sfp = vxfs_getfsh(infp->vsi_fship, 0); + if (!sfp) { + printk(KERN_ERR "vxfs: unabled to get structural fsh\n"); + goto out_iput_fship; + } + +#ifdef DIAGNOSTIC + vxfs_dumpfsh(sfp); +#endif + + pfp = vxfs_getfsh(infp->vsi_fship, 1); + if (!pfp) { + printk(KERN_ERR "vxfs: unabled to get primary fsh\n"); + goto out_free_sfp; + } + +#ifdef DIAGNOSTIC + 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); + if (!infp->vsi_stilist) { + printk(KERN_ERR "vxfs: unabled to get structual list inode\n"); + kfree(tip); + goto out_free_pfp; + } + if (!VXFS_ISILT(VXFS_INO(infp->vsi_stilist))) { + printk(KERN_ERR "vxfs: structual list inode is of wrong type (%x)\n", + VXFS_INO(infp->vsi_stilist)->vii_mode & VXFS_TYPE_MASK); + 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); + if (!infp->vsi_ilist) { + printk(KERN_ERR "vxfs: unabled to get inode list inode\n"); + kfree(tip); + goto out_iput_stilist; + } + if (!VXFS_ISILT(VXFS_INO(infp->vsi_ilist))) { + printk(KERN_ERR "vxfs: inode list inode is of wrong type (%x)\n", + VXFS_INO(infp->vsi_ilist)->vii_mode & VXFS_TYPE_MASK); + goto out_iput_ilist; + } + + return 0; + + out_iput_ilist: + iput(infp->vsi_ilist); + out_iput_stilist: + iput(infp->vsi_stilist); + out_free_pfp: + kfree(pfp); + out_free_sfp: + kfree(sfp); + out_iput_fship: + iput(infp->vsi_fship); + return -EINVAL; + out_free_fship: + kfree(vip); + return -EINVAL; +} diff --git a/fs/freevxfs/vxfs_fshead.h b/fs/freevxfs/vxfs_fshead.h new file mode 100644 index 00000000000..ead0d640c18 --- /dev/null +++ b/fs/freevxfs/vxfs_fshead.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef _VXFS_FSHEAD_H_ +#define _VXFS_FSHEAD_H_ + +/* + * Veritas filesystem driver - fileset header structures. + * + * This file contains the physical structure of the VxFS + * fileset header. + */ + + +/* + * 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 */ + + /* + * Slightly more fields follow, but they + * a) are not of any interest for us, and + * b) differ a lot in different vxfs versions/ports + */ +}; + +#endif /* _VXFS_FSHEAD_H_ */ diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c new file mode 100644 index 00000000000..ac677ab262b --- /dev/null +++ b/fs/freevxfs/vxfs_immed.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - support for 'immed' inodes. + */ +#include <linux/fs.h> +#include <linux/pagemap.h> +#include <linux/namei.h> + +#include "vxfs.h" +#include "vxfs_inode.h" + + +static int vxfs_immed_follow_link(struct dentry *, struct nameidata *); + +static int vxfs_immed_readpage(struct file *, struct page *); + +/* + * Inode operations for immed symlinks. + * + * Unliked all other operations we do not go through the pagecache, + * but do all work directly on the inode. + */ +struct inode_operations vxfs_immed_symlink_iops = { + .readlink = generic_readlink, + .follow_link = vxfs_immed_follow_link, +}; + +/* + * Adress space operations for immed files and directories. + */ +struct address_space_operations vxfs_immed_aops = { + .readpage = vxfs_immed_readpage, +}; + +/** + * vxfs_immed_follow_link - follow immed symlink + * @dp: dentry for the link + * @np: pathname lookup data for the current path walk + * + * Description: + * vxfs_immed_follow_link restarts the pathname lookup with + * the data obtained from @dp. + * + * Returns: + * Zero on success, else a negative error code. + */ +static int +vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np) +{ + struct vxfs_inode_info *vip = VXFS_INO(dp->d_inode); + nd_set_link(np, vip->vii_immed.vi_immed); + return 0; +} + +/** + * vxfs_immed_readpage - read part of an immed inode into pagecache + * @file: file context (unused) + * @page: page frame to fill in. + * + * Description: + * vxfs_immed_readpage reads a part of the immed area of the + * file that hosts @pp into the pagecache. + * + * Returns: + * Zero on success, else a negative error code. + * + * Locking status: + * @page is locked and will be unlocked. + */ +static int +vxfs_immed_readpage(struct file *fp, struct page *pp) +{ + struct vxfs_inode_info *vip = VXFS_INO(pp->mapping->host); + u_int64_t offset = pp->index << PAGE_CACHE_SHIFT; + caddr_t kaddr; + + kaddr = kmap(pp); + memcpy(kaddr, vip->vii_immed.vi_immed + offset, PAGE_CACHE_SIZE); + kunmap(pp); + + flush_dcache_page(pp); + SetPageUptodate(pp); + unlock_page(pp); + + return 0; +} diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c new file mode 100644 index 00000000000..9672d2facff --- /dev/null +++ b/fs/freevxfs/vxfs_inode.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - inode routines. + */ +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/pagemap.h> +#include <linux/kernel.h> +#include <linux/slab.h> + +#include "vxfs.h" +#include "vxfs_inode.h" +#include "vxfs_extern.h" + + +extern struct address_space_operations vxfs_aops; +extern struct address_space_operations vxfs_immed_aops; + +extern struct inode_operations vxfs_immed_symlink_iops; + +static struct file_operations vxfs_file_operations = { + .open = generic_file_open, + .llseek = generic_file_llseek, + .read = generic_file_read, + .mmap = generic_file_mmap, + .sendfile = generic_file_sendfile, +}; + + +kmem_cache_t *vxfs_inode_cachep; + + +#ifdef DIAGNOSTIC +/* + * Dump inode contents (partially). + */ +void +vxfs_dumpi(struct vxfs_inode_info *vip, ino_t ino) +{ + printk(KERN_DEBUG "\n\n"); + if (ino) + printk(KERN_DEBUG "dumping vxfs inode %ld\n", ino); + else + printk(KERN_DEBUG "dumping unknown vxfs inode\n"); + + printk(KERN_DEBUG "---------------------------\n"); + printk(KERN_DEBUG "mode is %x\n", vip->vii_mode); + printk(KERN_DEBUG "nlink:%u, uid:%u, gid:%u\n", + vip->vii_nlink, vip->vii_uid, vip->vii_gid); + printk(KERN_DEBUG "size:%Lx, blocks:%u\n", + vip->vii_size, vip->vii_blocks); + printk(KERN_DEBUG "orgtype:%u\n", vip->vii_orgtype); +} +#endif + + +/** + * vxfs_blkiget - find inode based on extent # + * @sbp: superblock of the filesystem we search in + * @extent: number of the extent to search + * @ino: inode number to search + * + * Description: + * vxfs_blkiget searches inode @ino in the filesystem described by + * @sbp in the extent @extent. + * Returns the matching VxFS inode on success, else a NULL pointer. + * + * NOTE: + * While __vxfs_iget uses the pagecache vxfs_blkiget uses the + * buffercache. This function should not be used outside the + * read_super() method, otherwise the data may be incoherent. + */ +struct vxfs_inode_info * +vxfs_blkiget(struct super_block *sbp, u_long extent, ino_t ino) +{ + struct buffer_head *bp; + u_long block, offset; + + block = extent + ((ino * VXFS_ISIZE) / sbp->s_blocksize); + offset = ((ino % (sbp->s_blocksize / VXFS_ISIZE)) * VXFS_ISIZE); + bp = sb_bread(sbp, block); + + if (buffer_mapped(bp)) { + struct vxfs_inode_info *vip; + struct vxfs_dinode *dip; + + if (!(vip = kmem_cache_alloc(vxfs_inode_cachep, SLAB_KERNEL))) + goto fail; + dip = (struct vxfs_dinode *)(bp->b_data + offset); + memcpy(vip, dip, sizeof(*vip)); +#ifdef DIAGNOSTIC + vxfs_dumpi(vip, ino); +#endif + brelse(bp); + return (vip); + } + +fail: + printk(KERN_WARNING "vxfs: unable to read block %ld\n", block); + brelse(bp); + return NULL; +} + +/** + * __vxfs_iget - generic find inode facility + * @sbp: VFS superblock + * @ino: inode number + * @ilistp: inode list + * + * 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 a NULL pointer. + */ +static struct vxfs_inode_info * +__vxfs_iget(ino_t ino, struct inode *ilistp) +{ + struct page *pp; + u_long offset; + + offset = (ino % (PAGE_SIZE / VXFS_ISIZE)) * VXFS_ISIZE; + 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, SLAB_KERNEL))) + goto fail; + dip = (struct vxfs_dinode *)(kaddr + offset); + memcpy(vip, dip, sizeof(*vip)); +#ifdef DIAGNOSTIC + vxfs_dumpi(vip, ino); +#endif + vxfs_put_page(pp); + return (vip); + } + + printk(KERN_WARNING "vxfs: error on page %p\n", pp); + return NULL; + +fail: + printk(KERN_WARNING "vxfs: unable to read inode %ld\n", (unsigned long)ino); + vxfs_put_page(pp); + return NULL; +} + +/** + * vxfs_stiget - find inode using the structural inode list + * @sbp: VFS superblock + * @ino: inode # + * + * 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) +{ + return __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_stilist); +} + +/** + * 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__ mode_t +vxfs_transmod(struct vxfs_inode_info *vip) +{ + mode_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); + ip->i_uid = (uid_t)vip->vii_uid; + ip->i_gid = (gid_t)vip->vii_gid; + + ip->i_nlink = 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_blksize = PAGE_SIZE; + ip->i_blocks = vip->vii_blocks; + ip->i_generation = vip->vii_gen; + + ip->u.generic_ip = (void *)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. + */ +struct inode * +vxfs_get_fake_inode(struct super_block *sbp, struct vxfs_inode_info *vip) +{ + struct inode *ip = NULL; + + if ((ip = new_inode(sbp))) { + vxfs_iinit(ip, vip); + ip->i_mapping->a_ops = &vxfs_aops; + } + return (ip); +} + +/** + * vxfs_put_fake_inode - free faked inode + * *ip: VFS inode + * + * Description: + * vxfs_put_fake_inode frees all data asssociated with @ip. + */ +void +vxfs_put_fake_inode(struct inode *ip) +{ + iput(ip); +} + +/** + * vxfs_read_inode - fill in inode information + * @ip: inode pointer to fill + * + * Description: + * vxfs_read_inode reads the disk inode for @ip and fills + * in all relevant fields in @ip. + */ +void +vxfs_read_inode(struct inode *ip) +{ + struct super_block *sbp = ip->i_sb; + struct vxfs_inode_info *vip; + struct address_space_operations *aops; + ino_t ino = ip->i_ino; + + if (!(vip = __vxfs_iget(ino, VXFS_SBI(sbp)->vsi_ilist))) + return; + + vxfs_iinit(ip, vip); + + if (VXFS_ISIMMED(vip)) + aops = &vxfs_immed_aops; + else + aops = &vxfs_aops; + + if (S_ISREG(ip->i_mode)) { + ip->i_fop = &vxfs_file_operations; + ip->i_mapping->a_ops = aops; + } else if (S_ISDIR(ip->i_mode)) { + ip->i_op = &vxfs_dir_inode_ops; + ip->i_fop = &vxfs_dir_operations; + ip->i_mapping->a_ops = aops; + } else if (S_ISLNK(ip->i_mode)) { + if (!VXFS_ISIMMED(vip)) { + ip->i_op = &page_symlink_inode_operations; + ip->i_mapping->a_ops = &vxfs_aops; + } else + ip->i_op = &vxfs_immed_symlink_iops; + } else + init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev)); + + return; +} + +/** + * vxfs_clear_inode - remove inode from main memory + * @ip: inode to discard. + * + * Description: + * vxfs_clear_inode() is called on the final iput and frees the private + * inode area. + */ +void +vxfs_clear_inode(struct inode *ip) +{ + kmem_cache_free(vxfs_inode_cachep, ip->u.generic_ip); +} diff --git a/fs/freevxfs/vxfs_inode.h b/fs/freevxfs/vxfs_inode.h new file mode 100644 index 00000000000..240aeb11263 --- /dev/null +++ b/fs/freevxfs/vxfs_inode.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef _VXFS_INODE_H_ +#define _VXFS_INODE_H_ + +/* + * Veritas filesystem driver - inode structure. + * + * This file contains the definition of the disk and core + * inodes of the Veritas Filesystem. + */ + + +#define VXFS_ISIZE 0x100 /* Inode size */ + +#define VXFS_NDADDR 10 /* Number of direct addrs in inode */ +#define VXFS_NIADDR 2 /* Number of indirect addrs in inode */ +#define VXFS_NIMMED 96 /* Size of immediate data in inode */ +#define VXFS_NTYPED 6 /* Num of typed extents */ + +#define VXFS_TYPED_OFFSETMASK (0x00FFFFFFFFFFFFFFULL) +#define VXFS_TYPED_TYPEMASK (0xFF00000000000000ULL) +#define VXFS_TYPED_TYPESHIFT 56 + +#define VXFS_TYPED_PER_BLOCK(sbp) \ + ((sbp)->s_blocksize / sizeof(struct vxfs_typed)) + +/* + * Possible extent descriptor types for %VXFS_ORG_TYPED extents. + */ +enum { + VXFS_TYPED_INDIRECT = 1, + VXFS_TYPED_DATA = 2, + VXFS_TYPED_INDIRECT_DEV4 = 3, + VXFS_TYPED_DATA_DEV4 = 4, +}; + +/* + * Data stored immediately in the inode. + */ +struct vxfs_immed { + u_int8_t 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 */ + struct direct { /* Direct extents */ + vx_daddr_t extent; /* Extent number */ + int32_t 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 */ +}; + +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; +}; + +/* + * 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; + union { + u_int32_t rdev; + u_int32_t dotdot; + struct { + u_int32_t reserved; + u_int32_t fixextsize; + } i_regular; + struct { + u_int32_t matchino; + u_int32_t fsetindex; + } i_vxspec; + u_int64_t 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 */ + union { + struct vxfs_immed immed; + struct vxfs_ext4 ext4; + struct vxfs_typed typed[VXFS_NTYPED]; + } vdi_org; + u_int32_t vdi_iattrino; +}; + +#define vdi_rdev vdi_ftarea.rdev +#define vdi_dotdot vdi_ftarea.dotdot +#define vdi_fixextsize vdi_ftarea.regular.fixextsize +#define vdi_matchino vdi_ftarea.vxspec.matchino +#define vdi_fsetindex vdi_ftarea.vxspec.fsetindex + +#define vdi_immed vdi_org.immed +#define vdi_ext4 vdi_org.ext4 +#define vdi_typed vdi_org.typed + + +/* + * 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 + +#endif /* _VXFS_INODE_H_ */ diff --git a/fs/freevxfs/vxfs_kcompat.h b/fs/freevxfs/vxfs_kcompat.h new file mode 100644 index 00000000000..342a4cc860f --- /dev/null +++ b/fs/freevxfs/vxfs_kcompat.h @@ -0,0 +1,49 @@ +#ifndef _VXFS_KCOMPAT_H +#define _VXFS_KCOMPAT_H + +#include <linux/version.h> + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) + +#include <linux/blkdev.h> + +typedef long sector_t; + +/* From include/linux/fs.h (Linux 2.5.2-pre3) */ +static inline struct buffer_head * sb_bread(struct super_block *sb, int block) +{ + return bread(sb->s_dev, block, sb->s_blocksize); +} + +/* Dito. */ +static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block) +{ + bh->b_state |= 1 << BH_Mapped; + bh->b_dev = sb->s_dev; + bh->b_blocknr = block; +} + +/* From fs/block_dev.c (Linux 2.5.2-pre2) */ +static inline int sb_set_blocksize(struct super_block *sb, int size) +{ + int bits; + if (set_blocksize(sb->s_dev, size) < 0) + return 0; + sb->s_blocksize = size; + for (bits = 9, size >>= 9; size >>= 1; bits++) + ; + sb->s_blocksize_bits = bits; + return sb->s_blocksize; +} + +/* Dito. */ +static inline int sb_min_blocksize(struct super_block *sb, int size) +{ + int minsize = get_hardsect_size(sb->s_dev); + if (size < minsize) + size = minsize; + return sb_set_blocksize(sb, size); +} + +#endif /* Kernel 2.4 */ +#endif /* _VXFS_KCOMPAT_H */ diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c new file mode 100644 index 00000000000..506ae251d2c --- /dev/null +++ b/fs/freevxfs/vxfs_lookup.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - lookup and other directory related code. + */ +#include <linux/fs.h> +#include <linux/time.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/kernel.h> +#include <linux/pagemap.h> +#include <linux/smp_lock.h> + +#include "vxfs.h" +#include "vxfs_dir.h" +#include "vxfs_inode.h" +#include "vxfs_extern.h" + +/* + * Number of VxFS blocks per page. + */ +#define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_CACHE_SIZE / (sbp)->s_blocksize)) + + +static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *); +static int vxfs_readdir(struct file *, void *, filldir_t); + +struct inode_operations vxfs_dir_inode_ops = { + .lookup = vxfs_lookup, +}; + +struct file_operations vxfs_dir_operations = { + .readdir = 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_find_entry - find a mathing directory entry for a dentry + * @ip: directory inode + * @dp: dentry for which we want to find a direct + * @ppp: gets filled with the page the return value sits in + * + * Description: + * vxfs_find_entry finds a &struct vxfs_direct for the VFS directory + * cache entry @dp. @ppp will be filled with the page the return + * value resides in. + * + * Returns: + * The wanted direct on success, else a NULL pointer. + */ +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); + } + } + } + vxfs_put_page(pp); + } + + return NULL; +} + +/** + * vxfs_inode_by_name - find inode number for dentry + * @dip: directory to search in + * @dp: dentry we seach for + * + * Description: + * vxfs_inode_by_name finds out the inode number of + * the path component described by @dp in @dip. + * + * Returns: + * The wanted inode number on success, else Zero. + */ +static ino_t +vxfs_inode_by_name(struct inode *dip, struct dentry *dp) +{ + struct vxfs_direct *de; + struct page *pp; + ino_t ino = 0; + + de = vxfs_find_entry(dip, dp, &pp); + if (de) { + ino = de->d_ino; + kunmap(pp); + page_cache_release(pp); + } + + return (ino); +} + +/** + * vxfs_lookup - lookup pathname component + * @dip: dir in which we lookup + * @dp: dentry we lookup + * @nd: lookup nameidata + * + * Description: + * vxfs_lookup tries to lookup the pathname component described + * by @dp in @dip. + * + * Returns: + * A NULL-pointer on success, else an negative error code encoded + * in the return pointer. + */ +static struct dentry * +vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd) +{ + struct inode *ip = NULL; + ino_t ino; + + if (dp->d_name.len > VXFS_NAMELEN) + return ERR_PTR(-ENAMETOOLONG); + + lock_kernel(); + ino = vxfs_inode_by_name(dip, dp); + if (ino) { + ip = iget(dip->i_sb, ino); + if (!ip) { + unlock_kernel(); + return ERR_PTR(-EACCES); + } + } + unlock_kernel(); + d_add(dp, ip); + return NULL; +} + +/** + * vxfs_readdir - read a directory + * @fp: the directory to read + * @retp: return buffer + * @filler: filldir callback + * + * Description: + * vxfs_readdir fills @retp with directory entries from @fp + * using the VFS supplied callback @filler. + * + * Returns: + * Zero. + */ +static int +vxfs_readdir(struct file *fp, void *retp, filldir_t filler) +{ + struct inode *ip = fp->f_dentry->d_inode; + struct super_block *sbp = ip->i_sb; + u_long bsize = sbp->s_blocksize; + u_long page, npages, block, pblocks, nblocks, offset; + loff_t pos; + + switch ((long)fp->f_pos) { + case 0: + if (filler(retp, ".", 1, fp->f_pos, ip->i_ino, DT_DIR) < 0) + goto out; + fp->f_pos++; + /* fallthrough */ + case 1: + if (filler(retp, "..", 2, fp->f_pos, VXFS_INO(ip)->vii_dotdot, DT_DIR) < 0) + goto out; + fp->f_pos++; + /* fallthrough */ + } + + pos = fp->f_pos - 2; + + if (pos > VXFS_DIRROUND(ip->i_size)) { + unlock_kernel(); + 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) { + 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 <= 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 *) + (offset ? + (kaddr + offset) : + (baddr + VXFS_DIRBLKOV(dbp))); + + for (; (caddr_t)de <= limit; de = vxfs_next_entry(de)) { + int over; + + if (!de->d_reclen) + break; + if (!de->d_ino) + continue; + + offset = (caddr_t)de - kaddr; + over = filler(retp, de->d_name, de->d_namelen, + ((page << PAGE_CACHE_SHIFT) | offset) + 2, + de->d_ino, DT_UNKNOWN); + if (over) { + vxfs_put_page(pp); + goto done; + } + } + offset = 0; + } + vxfs_put_page(pp); + offset = 0; + } + +done: + fp->f_pos = ((page << PAGE_CACHE_SHIFT) | offset) + 2; +out: + unlock_kernel(); + return 0; +} diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c new file mode 100644 index 00000000000..7a204e31aad --- /dev/null +++ b/fs/freevxfs/vxfs_olt.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - object location table support. + */ +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/kernel.h> + +#include "vxfs.h" +#include "vxfs_olt.h" + + +static __inline__ void +vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp) +{ + if (infp->vsi_fshino) + BUG(); + infp->vsi_fshino = fshp->olt_fsino[0]; +} + +static __inline__ void +vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp) +{ + if (infp->vsi_iext) + BUG(); + infp->vsi_iext = ilistp->olt_iext[0]; +} + +static __inline__ u_long +vxfs_oblock(struct super_block *sbp, daddr_t block, u_long bsize) +{ + if (sbp->s_blocksize % bsize) + BUG(); + return (block * (sbp->s_blocksize / bsize)); +} + + +/** + * vxfs_read_olt - read olt + * @sbp: superblock of the filesystem + * @bsize: blocksize of the filesystem + * + * Description: + * vxfs_read_olt reads the olt of the filesystem described by @sbp + * into main memory and does some basic setup. + * + * Returns: + * Zero on success, else a negative error code. + */ +int +vxfs_read_olt(struct super_block *sbp, u_long bsize) +{ + struct vxfs_sb_info *infp = VXFS_SBI(sbp); + struct buffer_head *bp; + 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) { + printk(KERN_NOTICE "vxfs: ivalid olt magic number\n"); + goto fail; + } + + /* + * It is in theory possible that vsi_oltsize is > 1. + * I've not seen any such filesystem yet and I'm lazy.. --hch + */ + if (infp->vsi_oltsize > 1) { + printk(KERN_NOTICE "vxfs: oltsize > 1 detected.\n"); + printk(KERN_NOTICE "vxfs: please notify hch@infradead.org\n"); + goto fail; + } + + oaddr = (char *)bp->b_data + op->olt_size; + eaddr = (char *)bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize); + + while (oaddr < eaddr) { + struct vxfs_oltcommon *ocp = + (struct vxfs_oltcommon *)oaddr; + + switch (ocp->olt_type) { + case VXFS_OLT_FSHEAD: + vxfs_get_fshead((struct vxfs_oltfshead *)oaddr, infp); + break; + case VXFS_OLT_ILIST: + vxfs_get_ilist((struct vxfs_oltilist *)oaddr, infp); + break; + } + + oaddr += ocp->olt_size; + } + + brelse(bp); + return 0; + +fail: + brelse(bp); + return -EINVAL; +} diff --git a/fs/freevxfs/vxfs_olt.h b/fs/freevxfs/vxfs_olt.h new file mode 100644 index 00000000000..d8324296486 --- /dev/null +++ b/fs/freevxfs/vxfs_olt.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#ifndef _VXFS_OLT_H_ +#define _VXFS_OLT_H_ + +/* + * Veritas filesystem driver - Object Location Table data structures. + * + * This file contains definitions for the Object Location Table used + * by the Veritas Filesystem version 2 and newer. + */ + + +/* + * OLT magic number (vxfs_olt->olt_magic). + */ +#define VXFS_OLT_MAGIC 0xa504FCF5 + +/* + * VxFS OLT entry types. + */ +enum { + VXFS_OLT_FREE = 1, + VXFS_OLT_FSHEAD = 2, + VXFS_OLT_CUT = 3, + VXFS_OLT_ILIST = 4, + VXFS_OLT_DEV = 5, + VXFS_OLT_SB = 6 +}; + +/* + * VxFS OLT header. + * + * The Object Location Table header is placed at the beginning of each + * OLT extent. It is used to fing certain filesystem-wide metadata, e.g. + * the inital 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 */ +}; + +/* + * 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 */ +}; + +/* + * 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 */ +}; + +/* + * 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 */ +}; + +/* + * 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 */ +}; + +/* + * 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 */ +}; + +/* + * 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 */ +}; + +/* + * 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 */ +}; + +#endif /* _VXFS_OLT_H_ */ diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c new file mode 100644 index 00000000000..5e305612054 --- /dev/null +++ b/fs/freevxfs/vxfs_subr.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - shared subroutines. + */ +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pagemap.h> + +#include "vxfs_kcompat.h" +#include "vxfs_extern.h" + + +static int vxfs_readpage(struct file *, struct page *); +static sector_t vxfs_bmap(struct address_space *, sector_t); + +struct address_space_operations vxfs_aops = { + .readpage = vxfs_readpage, + .bmap = vxfs_bmap, + .sync_page = block_sync_page, +}; + +inline void +vxfs_put_page(struct page *pp) +{ + kunmap(pp); + page_cache_release(pp); +} + +/** + * vxfs_get_page - read a page into memory. + * @ip: inode to read from + * @n: page number + * + * Description: + * vxfs_get_page reads the @n th page of @ip into the pagecache. + * + * Returns: + * The wanted page on success, else a NULL pointer. + */ +struct page * +vxfs_get_page(struct address_space *mapping, u_long n) +{ + struct page * pp; + + pp = read_cache_page(mapping, n, + (filler_t*)mapping->a_ops->readpage, NULL); + + if (!IS_ERR(pp)) { + wait_on_page_locked(pp); + kmap(pp); + if (!PageUptodate(pp)) + goto fail; + /** if (!PageChecked(pp)) **/ + /** vxfs_check_page(pp); **/ + if (PageError(pp)) + goto fail; + } + + return (pp); + +fail: + vxfs_put_page(pp); + return ERR_PTR(-EIO); +} + +/** + * vxfs_bread - read buffer for a give inode,block tuple + * @ip: inode + * @block: logical block + * + * Description: + * The vxfs_bread function reads block no @block of + * @ip into the buffercache. + * + * Returns: + * The resulting &struct buffer_head. + */ +struct buffer_head * +vxfs_bread(struct inode *ip, int block) +{ + struct buffer_head *bp; + daddr_t pblock; + + pblock = vxfs_bmap1(ip, block); + bp = sb_bread(ip->i_sb, pblock); + + return (bp); +} + +/** + * vxfs_get_block - locate buffer for given inode,block tuple + * @ip: inode + * @iblock: logical block + * @bp: buffer skeleton + * @create: %TRUE if blocks may be newly allocated. + * + * Description: + * The vxfs_get_block function fills @bp with the right physical + * block and device number to perform a lowlevel read/write on + * it. + * + * Returns: + * Zero on success, else a negativ error code (-EIO). + */ +static int +vxfs_getblk(struct inode *ip, sector_t iblock, + struct buffer_head *bp, int create) +{ + daddr_t pblock; + + pblock = vxfs_bmap1(ip, iblock); + if (pblock != 0) { + map_bh(bp, ip->i_sb, pblock); + return 0; + } + + return -EIO; +} + +/** + * vxfs_readpage - read one page synchronously into the pagecache + * @file: file context (unused) + * @page: page frame to fill in. + * + * Description: + * The vxfs_readpage routine reads @page synchronously into the + * pagecache. + * + * Returns: + * Zero on success, else a negative error code. + * + * Locking status: + * @page is locked and will be unlocked. + */ +static int +vxfs_readpage(struct file *file, struct page *page) +{ + return block_read_full_page(page, vxfs_getblk); +} + +/** + * vxfs_bmap - perform logical to physical block mapping + * @mapping: logical to physical mapping to use + * @block: logical block (relative to @mapping). + * + * Description: + * Vxfs_bmap find out the corresponding phsical block to the + * @mapping, @block pair. + * + * Returns: + * Physical block number on success, else Zero. + * + * Locking status: + * We are under the bkl. + */ +static sector_t +vxfs_bmap(struct address_space *mapping, sector_t block) +{ + return generic_block_bmap(mapping, block, vxfs_getblk); +} diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c new file mode 100644 index 00000000000..0ae2c7b8182 --- /dev/null +++ b/fs/freevxfs/vxfs_super.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2000-2001 Christoph Hellwig. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL"). + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Veritas filesystem driver - superblock related routines. + */ +#include <linux/init.h> +#include <linux/module.h> + +#include <linux/blkdev.h> +#include <linux/fs.h> +#include <linux/buffer_head.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/vfs.h> + +#include "vxfs.h" +#include "vxfs_extern.h" +#include "vxfs_dir.h" +#include "vxfs_inode.h" + + +MODULE_AUTHOR("Christoph Hellwig"); +MODULE_DESCRIPTION("Veritas Filesystem (VxFS) driver"); +MODULE_LICENSE("Dual BSD/GPL"); + +MODULE_ALIAS("vxfs"); /* makes mount -t vxfs autoload the module */ + + +static void vxfs_put_super(struct super_block *); +static int vxfs_statfs(struct super_block *, struct kstatfs *); +static int vxfs_remount(struct super_block *, int *, char *); + +static struct super_operations vxfs_super_ops = { + .read_inode = vxfs_read_inode, + .clear_inode = vxfs_clear_inode, + .put_super = vxfs_put_super, + .statfs = vxfs_statfs, + .remount_fs = vxfs_remount, +}; + +/** + * vxfs_put_super - free superblock resources + * @sbp: VFS superblock. + * + * Description: + * vxfs_put_super frees all resources allocated for @sbp + * after the last instance of the filesystem is unmounted. + */ + +static void +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); + + brelse(infp->vsi_bp); + kfree(infp); +} + +/** + * vxfs_statfs - get filesystem information + * @sbp: VFS superblock + * @bufp: output buffer + * + * Description: + * vxfs_statfs fills the statfs buffer @bufp with information + * about the filesystem described by @sbp. + * + * Returns: + * Zero. + * + * Locking: + * No locks held. + * + * Notes: + * This is everything but complete... + */ +static int +vxfs_statfs(struct super_block *sbp, struct kstatfs *bufp) +{ + struct vxfs_sb_info *infp = VXFS_SBI(sbp); + + bufp->f_type = VXFS_SUPER_MAGIC; + bufp->f_bsize = sbp->s_blocksize; + bufp->f_blocks = infp->vsi_raw->vs_dsize; + bufp->f_bfree = infp->vsi_raw->vs_free; + bufp->f_bavail = 0; + bufp->f_files = 0; + bufp->f_ffree = infp->vsi_raw->vs_ifree; + bufp->f_namelen = VXFS_NAMELEN; + + return 0; +} + +static int vxfs_remount(struct super_block *sb, int *flags, char *data) +{ + *flags |= MS_RDONLY; + return 0; +} + +/** + * vxfs_read_super - read superblock into memory and initalize filesystem + * @sbp: VFS superblock (to fill) + * @dp: fs private mount data + * @silent: do not complain loudly when sth is wrong + * + * Description: + * We are called on the first mount of a filesystem to read the + * superblock into memory and do some basic setup. + * + * Returns: + * The superblock on success, else %NULL. + * + * Locking: + * We are under the bkl and @sbp->s_lock. + */ +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; + + sbp->s_flags |= MS_RDONLY; + + infp = kmalloc(sizeof(*infp), GFP_KERNEL); + if (!infp) { + printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n"); + return -ENOMEM; + } + memset(infp, 0, sizeof(*infp)); + + 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"); + } + 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; + } + + if ((rsbp->vs_version < 2 || rsbp->vs_version > 4) && !silent) { + printk(KERN_NOTICE "vxfs: unsupported VxFS version (%d)\n", + rsbp->vs_version); + goto out; + } + +#ifdef DIAGNOSTIC + printk(KERN_DEBUG "vxfs: supported VxFS version (%d)\n", rsbp->vs_version); + printk(KERN_DEBUG "vxfs: blocksize: %d\n", rsbp->vs_bsize); +#endif + + sbp->s_magic = rsbp->vs_magic; + sbp->s_fs_info = (void *)infp; + + infp->vsi_raw = rsbp; + infp->vsi_bp = bp; + infp->vsi_oltext = rsbp->vs_oltext[0]; + infp->vsi_oltsize = rsbp->vs_oltsize; + + if (!sb_set_blocksize(sbp, rsbp->vs_bsize)) { + printk(KERN_WARNING "vxfs: unable to set final block size\n"); + goto out; + } + + if (vxfs_read_olt(sbp, bsize)) { + printk(KERN_WARNING "vxfs: unable to read olt\n"); + goto out; + } + + if (vxfs_read_fshead(sbp)) { + printk(KERN_WARNING "vxfs: unable to read fshead\n"); + goto out; + } + + sbp->s_op = &vxfs_super_ops; + root = iget(sbp, VXFS_ROOT_INO); + sbp->s_root = d_alloc_root(root); + if (!sbp->s_root) { + iput(root); + printk(KERN_WARNING "vxfs: unable to get root dentry.\n"); + goto out_free_ilist; + } + + 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); +out: + brelse(bp); + kfree(infp); + return -EINVAL; +} + +/* + * The usual module blurb. + */ +static struct super_block *vxfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return get_sb_bdev(fs_type, flags, dev_name, data, vxfs_fill_super); +} + +static struct file_system_type vxfs_fs_type = { + .owner = THIS_MODULE, + .name = "vxfs", + .get_sb = vxfs_get_sb, + .kill_sb = kill_block_super, + .fs_flags = FS_REQUIRES_DEV, +}; + +static int __init +vxfs_init(void) +{ + vxfs_inode_cachep = kmem_cache_create("vxfs_inode", + sizeof(struct vxfs_inode_info), 0, + SLAB_RECLAIM_ACCOUNT, NULL, NULL); + if (vxfs_inode_cachep) + return (register_filesystem(&vxfs_fs_type)); + return -ENOMEM; +} + +static void __exit +vxfs_cleanup(void) +{ + unregister_filesystem(&vxfs_fs_type); + kmem_cache_destroy(vxfs_inode_cachep); +} + +module_init(vxfs_init); +module_exit(vxfs_cleanup); |