Support for ext2fs rev. 1 (from NetBSD)
authorjasoni <jasoni@openbsd.org>
Wed, 26 Apr 2000 23:24:39 +0000 (23:24 +0000)
committerjasoni <jasoni@openbsd.org>
Wed, 26 Apr 2000 23:24:39 +0000 (23:24 +0000)
sys/ufs/ext2fs/ext2fs.h
sys/ufs/ext2fs/ext2fs_alloc.c
sys/ufs/ext2fs/ext2fs_dinode.h
sys/ufs/ext2fs/ext2fs_dir.h
sys/ufs/ext2fs/ext2fs_extern.h
sys/ufs/ext2fs/ext2fs_inode.c
sys/ufs/ext2fs/ext2fs_lookup.c
sys/ufs/ext2fs/ext2fs_vfsops.c
sys/ufs/ext2fs/ext2fs_vnops.c

index e1d7b8c..a5d683b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs.h,v 1.3 1997/06/12 21:09:30 downsj Exp $       */
+/*     $OpenBSD: ext2fs.h,v 1.4 2000/04/26 23:24:39 jasoni Exp $       */
 /*     $NetBSD: ext2fs.h,v 1.1 1997/06/11 09:33:37 bouyer Exp $        */
 
 /*
  * Super block for an ext2fs file system.
  */
 struct ext2fs {
-       u_int32_t  e2fs_icount;                 /* Inode count */
-       u_int32_t  e2fs_bcount;                 /* blocks count */
-       u_int32_t  e2fs_rbcount;                /* reserved blocks count */
-       u_int32_t  e2fs_fbcount;                /* free blocks count */
-       u_int32_t  e2fs_ficount;                /* free inodes count */
+       u_int32_t  e2fs_icount;         /* Inode count */
+       u_int32_t  e2fs_bcount;         /* blocks count */
+       u_int32_t  e2fs_rbcount;        /* reserved blocks count */
+       u_int32_t  e2fs_fbcount;        /* free blocks count */
+       u_int32_t  e2fs_ficount;        /* free inodes count */
        u_int32_t  e2fs_first_dblock;   /* first data block */
-       u_int32_t  e2fs_log_bsize;              /* block size = 1024*(2^e2fs_log_bsize) */
-       u_int32_t  e2fs_fsize;                  /* fragment size */
-       u_int32_t  e2fs_bpg;                    /* blocks per group */
-       u_int32_t  e2fs_fpg;                    /* frags per group */
-       u_int32_t  e2fs_ipg;                    /* inodes per group */
-       u_int32_t  e2fs_mtime;                  /* mount time */
-       u_int32_t  e2fs_wtime;                  /* write time */
-       u_int16_t  e2fs_mnt_count;              /* mount count */
+       u_int32_t  e2fs_log_bsize;      /* block size = 1024*(2^e2fs_log_bsize) */
+       u_int32_t  e2fs_fsize;          /* fragment size */
+       u_int32_t  e2fs_bpg;            /* blocks per group */
+       u_int32_t  e2fs_fpg;            /* frags per group */
+       u_int32_t  e2fs_ipg;            /* inodes per group */
+       u_int32_t  e2fs_mtime;          /* mount time */
+       u_int32_t  e2fs_wtime;          /* write time */
+       u_int16_t  e2fs_mnt_count;      /* mount count */
        u_int16_t  e2fs_max_mnt_count;  /* max mount count */
-       u_int16_t  e2fs_magic;                  /* magic number */
-       u_int16_t  e2fs_state;                  /* file system state */
-       u_int16_t  e2fs_beh;                    /* behavior on errors */
-       u_int16_t  reserved;
-       u_int32_t  e2fs_lastfsck;               /* time of last fsck */
-       u_int32_t  e2fs_fsckintv;               /* max time between fscks */
-       u_int32_t  e2fs_creator;                /* creator OS */
-       u_int32_t  e2fs_rev;                    /* revision level */
-       u_int16_t  e2fs_ruid;                   /* default uid for reserved blocks */
-       u_int16_t  e2fs_rgid;                   /* default gid for reserved blocks */
-       u_int32_t  reserved2[235];
+       u_int16_t  e2fs_magic;          /* magic number */
+       u_int16_t  e2fs_state;          /* file system state */
+       u_int16_t  e2fs_beh;            /* behavior on errors */
+       u_int16_t  e2fs_minrev;         /* minor revision level */
+       u_int32_t  e2fs_lastfsck;       /* time of last fsck */
+       u_int32_t  e2fs_fsckintv;       /* max time between fscks */
+       u_int32_t  e2fs_creator;        /* creator OS */
+       u_int32_t  e2fs_rev;            /* revision level */
+       u_int16_t  e2fs_ruid;           /* default uid for reserved blocks */
+       u_int16_t  e2fs_rgid;           /* default gid for reserved blocks */
+       /* EXT2_DYNAMIC_REV superblocks */
+       u_int32_t  e2fs_first_ino;      /* first non-reserved inode */
+       u_int16_t  e2fs_inode_size;     /* size of inode structure */
+       u_int16_t  e2fs_block_group_nr; /* block grp number of this sblk*/
+       u_int32_t  e2fs_features_compat; /*  compatible feature set */
+       u_int32_t  e2fs_features_incompat; /* incompatible feature set */
+       u_int32_t  e2fs_features_rocompat; /* RO-compatible feature set */
+       u_int8_t   e2fs_uuid[16];       /* 128-bit uuid for volume */
+       char       e2fs_vname[16];      /* volume name */
+       char       e2fs_fsmnt[64];      /* name mounted on */
+       u_int32_t  e2fs_algo;           /* For compression */
+       u_int8_t   e2fs_prealloc;       /* # of blocks to preallocate */
+       u_int8_t   e2fs_dir_prealloc;   /* # of blocks to preallocate for dir */
+       u_int16_t  pad1;
+       u_int32_t  reserved2[204];
 };
 
 
@@ -133,18 +147,18 @@ struct ext2fs {
 struct m_ext2fs {
        struct ext2fs e2fs;
        u_char  e2fs_fsmnt[MAXMNTLEN];  /* name mounted on */
-       int8_t  e2fs_ronly;                             /* mounted read-only flag */
-       int8_t  e2fs_fmod;                              /* super block modified flag */
-       int32_t e2fs_bsize;                             /* block size */
-       int32_t e2fs_bshift;                    /* ``lblkno'' calc of logical blkno */
-       int32_t e2fs_bmask;                             /* ``blkoff'' calc of blk offsets */
-       int64_t e2fs_qbmask;                    /* ~fs_bmask - for use with quad size */
-       int32_t e2fs_fsbtodb;                   /* fsbtodb and dbtofsb shift constant */
-       int32_t e2fs_ncg;                               /* number of cylinder groups */
-       int32_t e2fs_ngdb;                              /* number of group descriptor block */
-       int32_t e2fs_ipb;                               /* number of inodes per block */
-       int32_t e2fs_itpg;                              /* number of inode table per group */
-       struct  ext2_gd *e2fs_gd;               /* group descripors */
+       int8_t  e2fs_ronly;             /* mounted read-only flag */
+       int8_t  e2fs_fmod;              /* super block modified flag */
+       int32_t e2fs_bsize;             /* block size */
+       int32_t e2fs_bshift;            /* ``lblkno'' calc of logical blkno */
+       int32_t e2fs_bmask;             /* ``blkoff'' calc of blk offsets */
+       int64_t e2fs_qbmask;            /* ~fs_bmask - for use with quad size */
+       int32_t e2fs_fsbtodb;           /* fsbtodb and dbtofsb shift constant */
+       int32_t e2fs_ncg;               /* number of cylinder groups */
+       int32_t e2fs_ngdb;              /* number of group descriptor block */
+       int32_t e2fs_ipb;               /* number of inodes per block */
+       int32_t e2fs_itpg;              /* number of inode table per group */
+       struct  ext2_gd *e2fs_gd;       /* group descripors */
 };
 
 
@@ -153,7 +167,23 @@ struct m_ext2fs {
  * Filesystem identification
  */
 #define        E2FS_MAGIC      0xef53  /* the ext2fs magic number */
-#define E2FS_REV       0               /* revision level */
+#define E2FS_REV0      0       /* revision level */
+#define E2FS_REV1      1       /* revision level */
+
+/* compatible/imcompatible features */
+#define EXT2F_COMPAT_PREALLOC          0x0001
+
+#define EXT2F_ROCOMPAT_SPARSESUPER     0x0001
+#define EXT2F_ROCOMPAT_LARGEFILE       0x0002
+#define EXT2F_ROCOMPAT_BTREE_DIR       0x0004
+
+#define EXT2F_INCOMPAT_COMP            0x0001
+#define EXT2F_INCOMPAT_FTYPE           0x0002
+
+/* features supported in this implementation */
+#define EXT2F_COMPAT_SUPP              0x0000
+#define EXT2F_ROCOMPAT_SUPP            EXT2F_ROCOMPAT_SPARSESUPER
+#define EXT2F_INCOMPAT_SUPP            EXT2F_INCOMPAT_FTYPE
 
 /*
  * OS identification
@@ -166,7 +196,7 @@ struct m_ext2fs {
  * Filesystem clean flags
  */
 #define        E2FS_ISCLEAN    0x01
-#define        E2FS_ERRORS             0x02
+#define        E2FS_ERRORS     0x02
 
 /* ext2 file system block group descriptor */
 
@@ -179,9 +209,44 @@ struct ext2_gd {
        u_int16_t ext2bgd_ndirs;        /* number of directories */
        u_int16_t reserved;
        u_int32_t reserved2[3];
-
 };
 
+/*
+ * If the EXT2F_ROCOMPAT_SPARSESUPER flag is set, the cylinder group has a
+ * copy of the super and cylinder group descriptors blocks only if it's
+ * a power of 3, 5 or 7
+ */
+
+static __inline__ int cg_has_sb __P((int)) __attribute__((__unused__));
+static __inline int
+cg_has_sb(i)
+       int i;
+{
+       int a3 ,a5 , a7;
+
+       if (i == 0 || i == 1)
+               return 1;
+       for (a3 = 3, a5 = 5, a7 = 7;
+           a3 <= i || a5 <= i || a7 <= i;
+           a3 *= 3, a5 *= 5, a7 *= 7)
+               if (i == a3 || i == a5 || i == a7)
+                       return 1;
+       return 0;
+}
+
+/*
+ * EXT2FS metadatas are stored in little-endian byte order.  These macros
+ * should aide in support for big-endian machines.
+ */
+#define h2fs16(x) (x)
+#define h2fs32(x) (x)
+#define fs2h16(x) (x)
+#define fs2h32(x) (x)
+#define e2fs_sbload(old, new) bcopy((old), (new), SBSIZE);
+#define e2fs_cgload(old, new, size) bcopy((old), (new), (size));
+#define e2fs_sbsave(old, new) bcopy((old), (new), SBSIZE);
+#define e2fs_cgsave(old, new, size) bcopy((old), (new), (size));
+
 /*
  * Turn file system block numbers into disk block addresses.
  * This maps file system blocks to device size blocks.
index 90897f7..77d761a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_alloc.c,v 1.4 1999/01/11 05:12:35 millert Exp $        */
+/*     $OpenBSD: ext2fs_alloc.c,v 1.5 2000/04/26 23:24:40 jasoni Exp $ */
 /*     $NetBSD: ext2fs_alloc.c,v 1.1 1997/06/11 09:33:41 bouyer Exp $  */
 
 /*
@@ -264,7 +264,7 @@ ext2fs_blkpref(ip, lbn, indx, bap)
        if (bap) {
                for (i = indx; i >= 0 ; i--) {
                        if (bap[i]) {
-                               return bap[i] + 1;
+                               return fs2h32(bap[i]) + 1;
                        }
                }
        }
@@ -352,7 +352,8 @@ ext2fs_alloccg(ip, cg, bpref, size)
        fs = ip->i_e2fs;
        if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
                return (NULL);
-       error = bread(ip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+       error = bread(ip->i_devvp, fsbtodb(fs, 
+               fs->e2fs_gd[cg].ext2bgd_b_bitmap),
                (int)fs->e2fs_bsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
@@ -440,7 +441,8 @@ ext2fs_nodealloccg(ip, cg, ipref, mode)
        fs = ip->i_e2fs;
        if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
                return (NULL);
-       error = bread(ip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+       error = bread(ip->i_devvp, fsbtodb(fs, 
+               fs->e2fs_gd[cg].ext2bgd_i_bitmap),
                (int)fs->e2fs_bsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
@@ -512,7 +514,8 @@ ext2fs_blkfree(ip, bno)
                ext2fs_fserr(fs, ip->i_e2fs_uid, "bad block");
                return;
        }
-       error = bread(ip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
+       error = bread(ip->i_devvp, fsbtodb(fs, 
+               fs->e2fs_gd[cg].ext2bgd_b_bitmap),
                (int)fs->e2fs_bsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
@@ -560,7 +563,8 @@ ext2fs_vfree(v)
                panic("ifree: range: dev = 0x%x, ino = %d, fs = %s",
                        pip->i_dev, ino, fs->e2fs_fsmnt);
        cg = ino_to_cg(fs, ino);
-       error = bread(pip->i_devvp, fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
+       error = bread(pip->i_devvp, 
+               fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
                (int)fs->e2fs_bsize, NOCRED, &bp);
        if (error) {
                brelse(bp);
index 5215322..fe5c280 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_dinode.h,v 1.3 1997/06/12 21:09:32 downsj Exp $        */
+/*     $OpenBSD: ext2fs_dinode.h,v 1.4 2000/04/26 23:24:40 jasoni Exp $        */
 /*     $NetBSD: ext2fs_dinode.h,v 1.1 1997/06/11 09:33:48 bouyer Exp $ */
 
 /*
@@ -117,10 +117,13 @@ struct ext2fs_dinode {
 #define EXT2_UNRM              0x00000002      /* Undelete */
 #define EXT2_COMPR             0x00000004      /* Compress file */
 #define EXT2_SYNC              0x00000008      /* Synchronous updates */
-#define EXT2_IMMUTABLE 0x00000010      /* Immutable file */
+#define EXT2_IMMUTABLE         0x00000010      /* Immutable file */
 #define EXT2_APPEND            0x00000020      /* writes to file may only append */
 #define EXT2_NODUMP            0x00000040      /* do not dump file */
 
+/* Size of on-disk inode. */
+#define        EXT2_DINODE_SIZE        (sizeof(struct ext2fs_dinode))  /* 128 */
+
 /*
  * The e2di_blocks fields may be overlaid with other information for
  * file types that do not have associated disk storage. Block
@@ -130,4 +133,11 @@ struct ext2fs_dinode {
  */
 
 #define e2di_rdev              e2di_blocks[0]
-#define e2di_shortlink e2di_blocks
+#define e2di_shortlink         e2di_blocks
+
+/*
+ * e2fs needs byte swapping on big-endian systems.  Use macros here to 
+ * aide in big-endian support.
+ */
+#define e2fs_iload(old, new) bcopy((old),(new),sizeof(struct ext2fs_dinode))
+#define e2fs_isave(old, new) bcopy((old),(new),sizeof(struct ext2fs_dinode))
index c959023..ae73124 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_dir.h,v 1.3 1997/06/12 21:09:32 downsj Exp $   */
+/*     $OpenBSD: ext2fs_dir.h,v 1.4 2000/04/26 23:24:40 jasoni Exp $   */
 /*     $NetBSD: ext2fs_dir.h,v 1.1 1997/06/11 09:33:50 bouyer Exp $    */
 
 /*
 struct ext2fs_direct {
        u_int32_t e2d_ino;              /* inode number of entry */
        u_int16_t e2d_reclen;           /* length of this record */
-       u_int16_t e2d_namlen;           /* length of string in d_name */
+       u_int8_t e2d_namlen;            /* length of string in d_name */
+       u_int8_t e2d_type;              /* file type */
        char      e2d_name[EXT2FS_MAXNAMLEN];/* name with length <= EXT2FS_MAXNAMLEN */
 };
 
+/* Ext2 directory file types (not the same as FFS. Sigh. */
+#define EXT2_FT_UNKNOWN         0
+#define EXT2_FT_REG_FILE        1 
+#define EXT2_FT_DIR             2
+#define EXT2_FT_CHRDEV          3
+#define EXT2_FT_BLKDEV          4
+#define EXT2_FT_FIFO            5
+#define EXT2_FT_SOCK            6
+#define EXT2_FT_SYMLINK         7
+#define EXT2_FT_MAX             8
+
+#define E2IFTODT(mode)    (((mode) & 0170000) >> 12)
+
+static __inline__ u_int8_t inot2ext2dt __P((u_int16_t))
+    __attribute__((__unused__));
+static __inline__ u_int8_t
+inot2ext2dt(type)
+       u_int16_t type;
+{
+       switch(type) {
+       case E2IFTODT(EXT2_IFIFO):
+               return EXT2_FT_FIFO;
+       case E2IFTODT(EXT2_IFCHR):
+               return EXT2_FT_CHRDEV;
+       case E2IFTODT(EXT2_IFDIR):
+               return EXT2_FT_DIR;
+       case E2IFTODT(EXT2_IFBLK):
+               return EXT2_FT_BLKDEV;
+       case E2IFTODT(EXT2_IFREG):
+               return EXT2_FT_REG_FILE;
+       case E2IFTODT(EXT2_IFLNK):
+               return EXT2_FT_SYMLINK;
+       case E2IFTODT(EXT2_IFSOCK):
+               return EXT2_FT_SOCK;
+       default:
+               return 0;
+       }
+}
+
 /*
  * The EXT2FS_DIRSIZ macro gives the minimum record length which will hold
  * the directory entryfor a name len "len" (without the terminating null byte).
@@ -104,11 +144,13 @@ struct    ext2fs_direct {
 struct ext2fs_dirtemplate {
        u_int32_t       dot_ino;
        int16_t         dot_reclen;
-       u_int16_t       dot_namlen;
+       u_int8_t        dot_namlen;
+       u_int8_t        dot_type;
        char            dot_name[4];    /* must be multiple of 4 */
        u_int32_t       dotdot_ino;
        int16_t         dotdot_reclen;
-       u_int16_t       dotdot_namlen;
+       u_int8_t        dotdot_namlen;
+       u_int8_t        dotdot_type;
        char            dotdot_name[4]; /* ditto */
 };
 
index 7310611..386399d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_extern.h,v 1.6 2000/02/07 04:57:18 assar Exp $ */
+/*     $OpenBSD: ext2fs_extern.h,v 1.7 2000/04/26 23:24:40 jasoni Exp $        */
 /*     $NetBSD: ext2fs_extern.h,v 1.1 1997/06/11 09:33:55 bouyer Exp $ */
 
 /*-
@@ -55,6 +55,8 @@ struct vfsconf;
 struct mbuf;
 struct componentname;
 
+extern struct pool ext2fs_inode_pool;          /* memory pool for inodes */
+
 __BEGIN_DECLS
 
 /* ext2fs_alloc.c */
@@ -142,6 +144,7 @@ int ext2fs_makeinode __P((int, struct vnode *, struct vnode **,
                           struct componentname *cnp));
 int ext2fs_fsync __P((void *));
 int ext2fs_reclaim __P((void *));
+
 __END_DECLS
 
 #define IS_EXT2_VNODE(vp)   (vp->v_tag == VT_EXT2FS)
index 9813965..d97a129 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_inode.c,v 1.7 1999/08/17 14:20:46 art Exp $    */
+/*     $OpenBSD: ext2fs_inode.c,v 1.8 2000/04/26 23:24:41 jasoni Exp $ */
 /*     $NetBSD: ext2fs_inode.c,v 1.1 1997/06/11 09:33:56 bouyer Exp $  */
 
 /*
@@ -61,7 +61,7 @@
 #include <ufs/ext2fs/ext2fs_extern.h>
 
 static int ext2fs_indirtrunc __P((struct inode *, daddr_t, daddr_t,
-                                                                       daddr_t, int, long *));
+                                 daddr_t, int, long *));
 
 int
 ext2fs_init(vfsp)
index e058064..11bc889 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_lookup.c,v 1.6 1999/01/11 05:12:37 millert Exp $       */
+/*     $OpenBSD: ext2fs_lookup.c,v 1.7 2000/04/26 23:24:41 jasoni Exp $        */
 /*     $NetBSD: ext2fs_lookup.c,v 1.1 1997/06/11 09:33:59 bouyer Exp $ */
 
 /* 
@@ -797,8 +797,14 @@ ext2fs_direnter(ip, dvp, cnp)
                panic("direnter: missing name");
 #endif
        dp = VTOI(dvp);
-       newdir.e2d_ino = ip->i_number;
+       newdir.e2d_ino = h2fs32(ip->i_number);
        newdir.e2d_namlen = cnp->cn_namelen;
+       if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
+           (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
+               newdir.e2d_type = inot2ext2dt(IFTODT(ip->i_ffs_mode));
+       } else {
+               newdir.e2d_type = 0;
+       };
        bcopy(cnp->cn_nameptr, newdir.e2d_name, (unsigned)cnp->cn_namelen + 1);
        newentrysize = EXT2FS_DIRSIZ(newdir.e2d_namlen);
        if (dp->i_count == 0) {
@@ -968,7 +974,13 @@ ext2fs_dirrewrite(dp, ip, cnp)
        error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp);
        if (error != 0)
                return (error);
-       ep->e2d_ino = ip->i_number;
+       ep->e2d_ino = h2fs32(ip->i_number);
+       if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
+           (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
+               ep->e2d_type = inot2ext2dt(IFTODT(ip->i_ffs_mode));
+       } else {
+               ep->e2d_type = 0;
+       }
        error = VOP_BWRITE(bp);
        dp->i_flag |= IN_CHANGE | IN_UPDATE;
        return (error);
index 2b6ba93..27aa535 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_vfsops.c,v 1.11 2000/02/07 04:57:18 assar Exp $        */
+/*     $OpenBSD: ext2fs_vfsops.c,v 1.12 2000/04/26 23:24:41 jasoni Exp $       */
 /*     $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */
 
 /*
@@ -54,6 +54,8 @@
 #include <sys/ioctl.h>
 #include <sys/errno.h>
 #include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/lock.h>
 
 #include <miscfs/specfs/specdev.h>
 
 #include <ufs/ext2fs/ext2fs.h>
 #include <ufs/ext2fs/ext2fs_extern.h>
 
+extern struct lock ufs_hashlock;
+
 int ext2fs_sbupdate __P((struct ufsmount *, int));
+static int ext2fs_checksb __P((struct ext2fs *, int));
+
+extern struct vnodeopv_desc ext2fs_vnodeop_opv_desc;
+extern struct vnodeopv_desc ext2fs_specop_opv_desc;
+extern struct vnodeopv_desc ext2fs_fifoop_opv_desc;
+
+struct vnodeopv_desc *ext2fs_vnodeopv_descs[] = {
+       &ext2fs_vnodeop_opv_desc,
+       &ext2fs_specop_opv_desc,
+       &ext2fs_fifoop_opv_desc,
+       NULL,
+};
 
 struct vfsops ext2fs_vfsops = {
        ext2fs_mount,
@@ -84,6 +100,8 @@ struct vfsops ext2fs_vfsops = {
        ufs_check_export
 };
 
+struct pool ext2fs_inode_pool;
+
 extern u_long ext2gennumber;
 
 /*
@@ -109,12 +127,16 @@ ext2fs_mountroot()
        if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp))
                panic("ext2fs_mountroot: can't setup bdevvp's");
 
-       if ((error = vfs_rootmountalloc("ext2fs", "root_device", &mp)) != 0)
+       if ((error = vfs_rootmountalloc("ext2fs", "root_device", &mp)) != 0) {
+               vrele(rootvp);
                return (error);
+       }
+
        if ((error = ext2fs_mountfs(rootvp, mp, p)) != 0) {
                mp->mnt_vfc->vfc_refcount--;
                vfs_unbusy(mp, p);
                free(mp, M_MOUNT);
+               vrele(rootvp);
                return (error);
        }
        simple_lock(&mountlist_slock);
@@ -122,9 +144,15 @@ ext2fs_mountroot()
        simple_unlock(&mountlist_slock);
        ump = VFSTOUFS(mp);
        fs = ump->um_e2fs;
-       (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt, MNAMELEN -1, 0);
+       bzero(fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt));
+       (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs_fsmnt, 
+           sizeof(fs->e2fs_fsmnt) - 1, 0);
+       if (fs->e2fs.e2fs_rev > E2FS_REV0) {
+               bzero(fs->e2fs.e2fs_fsmnt, sizeof(fs->e2fs.e2fs_fsmnt));
+               (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs.e2fs_fsmnt,
+                   sizeof(fs->e2fs.e2fs_fsmnt) - 1, 0);
+       }
        (void)ext2fs_statfs(mp, &mp->mnt_stat, p);
-
        vfs_unbusy(mp, p);
        inittodr(fs->e2fs.e2fs_wtime);
        return (0);
@@ -203,7 +231,6 @@ ext2fs_mount(mp, path, data, ndp, p)
                        else
                                fs->e2fs.e2fs_state = E2FS_ERRORS;
                        fs->e2fs_fmod = 1;
-                       (void) ext2fs_sbupdate(ump, MNT_WAIT);
                }
                if (args.fspec == 0) {
                        /*
@@ -259,9 +286,14 @@ ext2fs_mount(mp, path, data, ndp, p)
        }
        ump = VFSTOUFS(mp);
        fs = ump->um_e2fs;
-       (void) copyinstr(path, fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt) - 1, &size);
-       bcopy(&args, &mp->mnt_stat.mount_info.ufs_args, sizeof(args));
+       (void) copyinstr(path, fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt) - 1,
+           &size);
        bzero(fs->e2fs_fsmnt + size, sizeof(fs->e2fs_fsmnt) - size);
+       if (fs->e2fs.e2fs_rev > E2FS_REV0) {
+               (void) copystr(mp->mnt_stat.f_mntonname, fs->e2fs.e2fs_fsmnt,
+                   sizeof(fs->e2fs.e2fs_fsmnt) - 1, &size);
+               bzero(fs->e2fs.e2fs_fsmnt, sizeof(fs->e2fs.e2fs_fsmnt) - size);
+       }
        bcopy(fs->e2fs_fsmnt, mp->mnt_stat.f_mntonname, MNAMELEN);
        (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 
                &size);
@@ -304,6 +336,7 @@ ext2fs_reload(mountp, cred, p)
        struct ext2fs *newfs;
        struct partinfo dpart;
        int i, size, error;
+       caddr_t cp;
 
        if ((mountp->mnt_flag & MNT_RDONLY) == 0)
                return (EINVAL);
@@ -311,10 +344,7 @@ ext2fs_reload(mountp, cred, p)
         * Step 1: invalidate all cached meta-data.
         */
        devvp = VFSTOUFS(mountp)->um_devvp;
-       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
-       error = vinvalbuf(devvp, 0, cred, p, 0, 0);
-       VOP_UNLOCK(devvp, 0, p);
-       if (error)
+       if (vinvalbuf(devvp, 0, cred, p, 0, 0))
                panic("ext2fs_reload: dirty1");
 
        /*
@@ -324,37 +354,26 @@ ext2fs_reload(mountp, cred, p)
                size = DEV_BSIZE;
        else
                size = dpart.disklab->d_secsize;
-       error = bread(devvp, (daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
-       if (error)
-               return (error);
-       newfs = (struct ext2fs *)bp->b_data;
-       if (newfs->e2fs_magic != E2FS_MAGIC || newfs->e2fs_rev != E2FS_REV) {
-#ifdef DIAGNOSTIC
-               printf("Wrong magic number: %x (expected %x for ext2 fs)",
-                                       newfs->e2fs_magic, E2FS_MAGIC);
-               printf("or wrong revision number: %x (expected %x for ext2 fs)",
-                                       newfs->e2fs_rev, E2FS_REV);
-#endif
+       error = bread(devvp, (ufs_daddr_t)(SBOFF / size), SBSIZE, NOCRED, &bp);
+       if (error) {
                brelse(bp);
-               return (EIO);           /* XXX needs translation */
+               return (error);
        }
-       if (newfs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */
-#ifdef DIAGNOSTIC
-               printf("wrong block size: %d (expected <=2 for ext2 fs)\n",
-                       newfs->e2fs_log_bsize);
-#endif
+       newfs = (struct ext2fs *)bp->b_data;
+       error = ext2fs_checksb(newfs, (mountp->mnt_flag & MNT_RDONLY) != 0);
+       if (error) {
                brelse(bp);
-               return (EIO);      /* XXX needs translation */
+               return (error);
        }
 
-
        fs = VFSTOUFS(mountp)->um_e2fs;
        /* 
         * copy in new superblock, and compute in-memory values
         */
-       bcopy(newfs, &fs->e2fs, SBSIZE);
-       fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
-               fs->e2fs.e2fs_bpg);
+       e2fs_sbload(newfs, &fs->e2fs);
+       fs->e2fs_ncg =
+           howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock,
+           fs->e2fs.e2fs_bpg);
        /* XXX assume hw bsize = 512 */
        fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1;
        fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize;
@@ -363,7 +382,7 @@ ext2fs_reload(mountp, cred, p)
        fs->e2fs_bmask = ~fs->e2fs_qbmask;
        fs->e2fs_ngdb = howmany(fs->e2fs_ncg,
                        fs->e2fs_bsize / sizeof(struct ext2_gd));
-       fs->e2fs_ipb = fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
+       fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE;
        fs->e2fs_itpg = fs->e2fs.e2fs_ipg/fs->e2fs_ipb;
 
        /*
@@ -371,13 +390,16 @@ ext2fs_reload(mountp, cred, p)
         */
 
        for (i=0; i < fs->e2fs_ngdb; i++) {
-               error = bread(devvp , fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
-                               fs->e2fs_bsize, NOCRED, &bp);
-               if (error)
+               error = bread(devvp ,
+                   fsbtodb(fs, ((fs->e2fs_bsize>1024)? 0 : 1) + i + 1),
+                   fs->e2fs_bsize, NOCRED, &bp);
+               if (error) {
+                       brelse(bp);
                        return (error);
-               bcopy(bp->b_data,
-                       &fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
-                       fs->e2fs_bsize);
+               }
+               e2fs_cgload((struct ext2_gd*)bp->b_data,
+                   &fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
+                   fs->e2fs_bsize);
                brelse(bp);
        }
        
@@ -415,10 +437,9 @@ loop:
                        vput(vp);
                        return (error);
                }
-               bcopy((struct ext2fs_dinode *)bp->b_data +
-                       ino_to_fsbo(fs, ip->i_number),
-                       &ip->i_din.e2fs_din, sizeof(struct ext2fs_dinode));
-               ip->i_effnlink = ip->i_e2fs_nlink;
+               cp = (caddr_t)bp->b_data +
+                   (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE);
+               e2fs_iload((struct ext2fs_dinode *)cp, &ip->i_din.e2fs_din);
                brelse(bp);
                vput(vp);
                simple_lock(&mntvnode_slock);
@@ -458,10 +479,7 @@ ext2fs_mountfs(devvp, mp, p)
                return (error);
        if (vcount(devvp) > 1 && devvp != rootvp)
                return (EBUSY);
-       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
-       error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
-       VOP_UNLOCK(devvp, 0, p);
-       if (error)
+       if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0)
                return (error);
 
        ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
@@ -478,36 +496,20 @@ ext2fs_mountfs(devvp, mp, p)
 
 #ifdef DEBUG_EXT2
        printf("sb size: %d ino size %d\n", sizeof(struct ext2fs),
-                       sizeof(struct ext2fs_dinode));
+           EXT2_DINODE_SIZE);
 #endif
        error = bread(devvp, (SBOFF / DEV_BSIZE), SBSIZE, cred, &bp);
        if (error)
                goto out;
        fs = (struct ext2fs *)bp->b_data;
-       if (fs->e2fs_magic != E2FS_MAGIC || fs->e2fs_rev != E2FS_REV) {
-#ifdef DIAGNOSTIC
-               printf("Wrong magic number: %x (expected %x for ext2 fs)",
-                       fs->e2fs_magic, E2FS_MAGIC);
-               printf(" or wrong revision number: %x (expected %x for ext2 fs)\n",
-                       fs->e2fs_rev, E2FS_REV);
-#endif
-               error = EFTYPE;
-               goto out;
-       }
-
-       if (fs->e2fs_log_bsize > 2) { /* block size = 1024|2048|4096 */
-#ifdef DIAGNOSTIC
-               printf("wrong block size: %d (expected <2 for ext2 fs)\n",
-                       fs->e2fs_log_bsize);
-#endif
-               error = EFTYPE;
+       error = ext2fs_checksb(fs, ronly);
+       if (error)
                goto out;
-       }
-
        ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
-       bzero((caddr_t)ump, sizeof *ump);
+       memset((caddr_t)ump, 0, sizeof *ump);
        ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK);
-       bcopy(bp->b_data, ump->um_e2fs, SBSIZE);
+       memset((caddr_t)ump->um_e2fs, 0, sizeof(struct m_ext2fs));
+       e2fs_sbload((struct ext2fs*)bp->b_data, &ump->um_e2fs->e2fs);
        brelse(bp);
        bp = NULL;
        m_fs = ump->um_e2fs;
@@ -532,21 +534,23 @@ ext2fs_mountfs(devvp, mp, p)
        m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask;
        m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg,
                m_fs->e2fs_bsize / sizeof(struct ext2_gd));
-       m_fs->e2fs_ipb = m_fs->e2fs_bsize / sizeof(struct ext2fs_dinode);
+       m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE;
        m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg/m_fs->e2fs_ipb;
 
        m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize,
                M_UFSMNT, M_WAITOK);
        for (i=0; i < m_fs->e2fs_ngdb; i++) {
-               error = bread(devvp , fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)?0:1)+i+1),
-                       m_fs->e2fs_bsize, NOCRED, &bp);
+               error = bread(devvp ,
+                   fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)? 0 : 1) + i + 1),
+                   m_fs->e2fs_bsize, NOCRED, &bp);
                if (error) {
                        free(m_fs->e2fs_gd, M_UFSMNT);
                        goto out;
                }
-               bcopy(bp->b_data,
-                       &m_fs->e2fs_gd[i* m_fs->e2fs_bsize / sizeof(struct ext2_gd)],
-                       m_fs->e2fs_bsize);
+               e2fs_cgload((struct ext2_gd*)bp->b_data,
+                   &m_fs->e2fs_gd[
+                       i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)],
+                   m_fs->e2fs_bsize);
                brelse(bp);
                bp = NULL;
        }
@@ -555,6 +559,7 @@ ext2fs_mountfs(devvp, mp, p)
        mp->mnt_stat.f_fsid.val[0] = (long)dev;
        mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
        mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN;
+       mp->mnt_flag |= MNT_LOCAL;
        ump->um_mountp = mp;
        ump->um_dev = dev;
        ump->um_devvp = devvp;
@@ -564,10 +569,11 @@ ext2fs_mountfs(devvp, mp, p)
        devvp->v_specmountpoint = mp;
        return (0);
 out:
-       devvp->v_specmountpoint = NULL;
        if (bp)
                brelse(bp);
+       vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
        (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p);
+       VOP_UNLOCK(devvp, 0, p);
        if (ump) {
                free(ump->um_e2fs, M_UFSMNT);
                free(ump, M_UFSMNT);
@@ -603,14 +609,17 @@ ext2fs_unmount(mp, mntflags, p)
                (void) ext2fs_sbupdate(ump, MNT_WAIT);
        }
 
-       ump->um_devvp->v_specmountpoint = NULL;
+       if (ump->um_devvp->v_type != VBAD)
+               ump->um_devvp->v_specmountpoint = NULL;
+       vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p);
        error = VOP_CLOSE(ump->um_devvp, fs->e2fs_ronly ? FREAD : FREAD|FWRITE,
                NOCRED, p);
-       vrele(ump->um_devvp);
+       vput(ump->um_devvp);
        free(fs->e2fs_gd, M_UFSMNT);
        free(fs, M_UFSMNT);
        free(ump, M_UFSMNT);
        mp->mnt_data = (qaddr_t)0;
+       mp->mnt_flag &= ~MNT_LOCAL;
        return (error);
 }
 
@@ -653,6 +662,7 @@ ext2fs_statfs(mp, sbp, p)
        register struct ufsmount *ump;
        register struct m_ext2fs *fs;
        u_int32_t overhead, overhead_per_group;
+       int i, ngroups;
 
        ump = VFSTOUFS(mp);
        fs = ump->um_e2fs;
@@ -662,14 +672,21 @@ ext2fs_statfs(mp, sbp, p)
        /*
         * Compute the overhead (FS structures)
         */
-       overhead_per_group = 1 /* super block */ +
-                                                fs->e2fs_ngdb +
-                                                1 /* block bitmap */ +
-                                                1 /* inode bitmap */ +
-                                                fs->e2fs_itpg;
+       overhead_per_group = 1 /* block bitmap */ +
+                                1 /* inode bitmap */ +
+                                fs->e2fs_itpg;
        overhead = fs->e2fs.e2fs_first_dblock +
                   fs->e2fs_ncg * overhead_per_group;
-
+       if (fs->e2fs.e2fs_rev > E2FS_REV0 &&
+           fs->e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) {
+               for (i = 0, ngroups = 0; i < fs->e2fs_ncg; i++) {
+                       if (cg_has_sb(i))
+                               ngroups++;
+               }
+       } else {
+               ngroups = fs->e2fs_ncg;
+       }
+       overhead += ngroups * (1 + fs->e2fs_ngdb);
 
        sbp->f_bsize = fs->e2fs_bsize;
        sbp->f_iosize = fs->e2fs_bsize;
@@ -681,8 +698,6 @@ ext2fs_statfs(mp, sbp, p)
        if (sbp != &mp->mnt_stat) {
                bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
                bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
-               bcopy(&mp->mnt_stat.mount_info.ufs_args,
-                   &sbp->mount_info.ufs_args, sizeof(struct ufs_args));
        }
        strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
        return (0);
@@ -709,30 +724,23 @@ ext2fs_sync(mp, waitfor, cred, p)
        int error, allerror = 0;
 
        fs = ump->um_e2fs;
-       /*
-        * Write back modified superblock.
-        * Consistency check that the superblock
-        * is still in the buffer cache.
-        */
-       if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) {        /* XXX */
+       if (fs->e2fs_ronly != 0) {              /* XXX */
                printf("fs = %s\n", fs->e2fs_fsmnt);
                panic("update: rofs mod");
        }
+
        /*
         * Write back each (modified) inode.
         */
        simple_lock(&mntvnode_slock);
 loop:
-       for (vp = mp->mnt_vnodelist.lh_first;
-                vp != NULL;
-                vp = nvp) {
+       for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
                /*
                 * If the vnode that we are about to sync is no longer
                 * associated with this mount point, start over.
                 */
                if (vp->v_mount != mp)
                        goto loop;
-
                simple_lock(&vp->v_interlock);
                nvp = vp->v_mntvnodes.le_next;
                ip = VTOI(vp);
@@ -753,8 +761,7 @@ loop:
                }
                if ((error = VOP_FSYNC(vp, cred, waitfor, p)) != 0)
                        allerror = error;
-               VOP_UNLOCK(vp, 0, p);
-               vrele(vp);
+               vput(vp);
                simple_lock(&mntvnode_slock);
        }
        simple_unlock(&mntvnode_slock);
@@ -772,9 +779,12 @@ loop:
        /*
         * Write back modified superblock.
         */
-       
-       if (fs->e2fs_fmod != 0 && (error = ext2fs_sbupdate(ump, waitfor)) != 0)
-               allerror = error;
+       if (fs->e2fs_fmod != 0) {
+               fs->e2fs_fmod = 0;
+               fs->e2fs.e2fs_wtime = time.tv_sec;
+               if ((error = ext2fs_cgupdate(ump, waitfor)))
+                       allerror = error;
+       }
        return (allerror);
 }
 
@@ -1002,16 +1012,56 @@ ext2fs_cgupdate(mp, waitfor)
        allerror = ext2fs_sbupdate(mp, waitfor);
        for (i = 0; i < fs->e2fs_ngdb; i++) {
                bp = getblk(mp->um_devvp, fsbtodb(fs, ((fs->e2fs_bsize>1024)?0:1)+i+1),
-                       fs->e2fs_bsize, 0, 0);
-               bcopy(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)],
-                bp->b_data, fs->e2fs_bsize);
+                   fs->e2fs_bsize, 0, 0);
+               e2fs_cgsave(&fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)], (struct ext2_gd*)bp->b_data, fs->e2fs_bsize);
                if (waitfor == MNT_WAIT)
                        error = bwrite(bp);
                else
                        bawrite(bp);
        }
-
+       
        if (!allerror && error)
                allerror = error;
        return (allerror);
 }
+
+static int
+ext2fs_checksb(fs, ronly)
+       struct ext2fs *fs;
+       int ronly;
+{
+       if (fs2h16(fs->e2fs_magic) != E2FS_MAGIC) {
+               return (EIO);           /* XXX needs translation */
+       }
+       if (fs2h32(fs->e2fs_rev) > E2FS_REV1) {
+#ifdef DIAGNOSTIC
+               printf("Ext2 fs: unsupported revision number: %x\n",
+                   fs2h32(fs->e2fs_rev));
+#endif
+               return (EIO);           /* XXX needs translation */
+       }
+       if (fs2h32(fs->e2fs_log_bsize) > 2) { /* block size = 1024|2048|4096 */
+#ifdef DIAGNOSTIC
+               printf("Ext2 fs: bad block size: %d (expected <=2 for ext2 fs)\n",
+                   fs2h32(fs->e2fs_log_bsize));
+#endif
+               return (EIO);      /* XXX needs translation */
+       }
+       if (fs2h32(fs->e2fs_rev) > E2FS_REV0) {
+               if (fs2h32(fs->e2fs_first_ino) != EXT2_FIRSTINO ||
+                   fs2h16(fs->e2fs_inode_size) != EXT2_DINODE_SIZE) {
+                       printf("Ext2 fs: unsupported inode size\n");
+                       return (EINVAL);      /* XXX needs translation */
+               }
+               if (fs2h32(fs->e2fs_features_incompat) &
+                   ~EXT2F_INCOMPAT_SUPP) {
+                       printf("Ext2 fs: unsupported optionnal feature\n");
+                       return (EINVAL);      /* XXX needs translation */
+               }
+               if (!ronly && fs2h32(fs->e2fs_features_rocompat) &
+                   ~EXT2F_ROCOMPAT_SUPP) {
+                       return (EROFS);      /* XXX needs translation */
+               }
+       }
+       return (0);
+}
index 8348a54..57218f0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ext2fs_vnops.c,v 1.10 1999/02/26 16:35:33 millert Exp $       */
+/*     $OpenBSD: ext2fs_vnops.c,v 1.11 2000/04/26 23:24:42 jasoni Exp $        */
 /*     $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $  */
 
 /*
 #include <sys/vnode.h>
 #include <sys/lockf.h>
 #include <sys/malloc.h>
+#include <sys/pool.h>
 #include <sys/signalvar.h>
 
 #include <vm/vm.h>
 
+#include <uvm/uvm_extern.h>
+
 #include <miscfs/fifofs/fifo.h>
 #include <miscfs/specfs/specdev.h>
 
@@ -109,9 +112,9 @@ ext2fs_create(v)
                struct componentname *a_cnp;
                struct vattr *a_vap;
        } */ *ap = v;
-       return
-               ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
-                         ap->a_dvp, ap->a_vpp, ap->a_cnp);
+       return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type, 
+                                         ap->a_vap->va_mode),
+                               ap->a_dvp, ap->a_vpp, ap->a_cnp);
 }
 
 /*
@@ -144,7 +147,7 @@ ext2fs_mknod(v)
                 * Want to be able to use this to make badblock
                 * inodes, so don't truncate the dev number.
                 */
-               ip->i_din.e2fs_din.e2di_rdev = vap->va_rdev;
+               ip->i_din.e2fs_din.e2di_rdev = h2fs32(vap->va_rdev);
        }
        /*
         * Remove inode so that it will be reloaded by VFS_VGET and
@@ -198,13 +201,6 @@ ext2fs_access(v)
        register struct inode *ip = VTOI(vp);
        mode_t mode = ap->a_mode;
 
-#ifdef DIAGNOSTIC
-       if (!VOP_ISLOCKED(vp)) {
-               vprint("ext2fs_access: not locked", vp);
-               panic("ext2fs_access: not locked");
-       }
-#endif
-
        /* If immutable bit set, nobody gets to write it. */
        if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
                return (EPERM);
@@ -238,7 +234,7 @@ ext2fs_getattr(v)
        vap->va_nlink = ip->i_e2fs_nlink;
        vap->va_uid = ip->i_e2fs_uid;
        vap->va_gid = ip->i_e2fs_gid;
-       vap->va_rdev = (dev_t)ip->i_din.e2fs_din.e2di_rdev;
+       vap->va_rdev = (dev_t)fs2h32(ip->i_din.e2fs_din.e2di_rdev);
        vap->va_size = ip->i_e2fs_size;
        vap->va_atime.tv_sec = ip->i_e2fs_atime;
        vap->va_atime.tv_nsec = 0;
@@ -261,7 +257,7 @@ ext2fs_getattr(v)
                vap->va_blocksize = MAXBSIZE;
        else
                vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
-       vap->va_bytes = dbtob(ip->i_e2fs_nblock);
+       vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
        vap->va_type = vp->v_type;
        vap->va_filerev = ip->i_modrev;
        return (0);
@@ -297,24 +293,28 @@ ext2fs_setattr(v)
                return (EINVAL);
        }
        if (vap->va_flags != VNOVAL) {
+               if (vp->v_mount->mnt_flag & MNT_RDONLY)
+                       return (EROFS);
                if (cred->cr_uid != ip->i_e2fs_uid &&
                        (error = suser(cred, &p->p_acflag)))
                        return (error);
 #ifdef EXT2FS_SYSTEM_FLAGS
                if (cred->cr_uid == 0) {
-                       if ((ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE)) &&
-                               securelevel > 0)
+                       if ((ip->i_e2fs_flags & 
+                           (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0)
                                return (EPERM);
                        ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
-                       ip->i_e2fs_flags |= (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
-                                       (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
+                       ip->i_e2fs_flags |= 
+                           (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
+                           (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
                } else {
                        return (EPERM);
                }
 #else
                ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
-               ip->i_e2fs_flags |= (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
-                               (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
+               ip->i_e2fs_flags |= 
+                   (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
+                   (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
 #endif
                ip->i_flag |= IN_CHANGE;
                if (vap->va_flags & (IMMUTABLE | APPEND))
@@ -326,19 +326,36 @@ ext2fs_setattr(v)
         * Go through the fields and update iff not VNOVAL.
         */
        if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
+               if (vp->v_mount->mnt_flag & MNT_RDONLY)
+                       return (EROFS);
                error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
                if (error)
                        return (error);
        }
        if (vap->va_size != VNOVAL) {
-               if (vp->v_type == VDIR)
+               /*
+                * Disallow write attempts on read-only file systems;
+                * unless the file is a socket, fifo, or a block or
+                * character device resident on the file system.
+                */
+               switch (vp->v_type) {
+               case VDIR:
                        return (EISDIR);
+               case VLNK:
+               case VREG:
+                       if (vp->v_mount->mnt_flag & MNT_RDONLY)
+                               return (EROFS);
+               default:
+                       break;
+               }
                error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p);
                if (error)
                        return (error);
        }
        ip = VTOI(vp);
        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
+               if (vp->v_mount->mnt_flag & MNT_RDONLY)
+                       return (EROFS);
                if (cred->cr_uid != ip->i_e2fs_uid &&
                        (error = suser(cred, &p->p_acflag)) &&
                        ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || 
@@ -354,8 +371,11 @@ ext2fs_setattr(v)
                        return (error);
        }
        error = 0;
-       if (vap->va_mode != (mode_t)VNOVAL)
+       if (vap->va_mode != (mode_t)VNOVAL) {
+               if (vp->v_mount->mnt_flag & MNT_RDONLY)
+                       return (EROFS);
                error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p);
+       }
        return (error);
 }
 
@@ -387,7 +407,7 @@ ext2fs_chmod(vp, mode, cred, p)
        ip->i_flag |= IN_CHANGE;
        if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0)
 #if defined(UVM)
-               uvm_vnp_uncache(vp);
+               (void) uvm_vnp_uncache(vp);
 #else
                (void) vnode_pager_uncache(vp);
 #endif
@@ -454,8 +474,8 @@ ext2fs_remove(v)
 
        ip = VTOI(vp);
        if (vp->v_type == VDIR ||
-           (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
-           (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
+               (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
+               (VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
                error = EPERM;
                goto out;
        }
@@ -490,7 +510,6 @@ ext2fs_link(v)
        register struct componentname *cnp = ap->a_cnp;
        struct proc *p = cnp->cn_proc;
        register struct inode *ip;
-       struct timespec ts;
        int error;
 
 #ifdef DIAGNOSTIC
@@ -507,7 +526,7 @@ ext2fs_link(v)
                error = EXDEV;
                goto out2;
        }
-       if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p))) {
+       if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
                VOP_ABORTOP(dvp, cnp);
                goto out2;
        }
@@ -524,8 +543,7 @@ ext2fs_link(v)
        }
        ip->i_e2fs_nlink++;
        ip->i_flag |= IN_CHANGE;
-       TIMEVAL_TO_TIMESPEC(&time, &ts);
-       error = VOP_UPDATE(vp, &ts, &ts, 1);
+       error = VOP_UPDATE(vp, NULL, NULL, 1);
        if (!error)
                error = ext2fs_direnter(ip, dvp, cnp);
        if (error) {
@@ -586,7 +604,7 @@ ext2fs_rename(v)
        register struct inode *ip, *xp, *dp;
        struct proc *p = fcnp->cn_proc;
        struct ext2fs_dirtemplate dirbuf;
-       struct timespec ts;
+       //struct timespec ts;
        int doingdirectory = 0, oldparent = 0, newparent = 0;
        int error = 0;
        u_char namlen;
@@ -646,7 +664,7 @@ abortit:
                (void) relookup(fdvp, &fvp, fcnp);
                return (VOP_REMOVE(fdvp, fvp, fcnp));
        }
-       if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
+       if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
                goto abortit;
        dp = VTOI(fdvp);
        ip = VTOI(fvp);
@@ -662,14 +680,15 @@ abortit:
                goto abortit;
        }
        if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
-        error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
-        if (!error && tvp)
-                error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
-        if (error) {
-                VOP_UNLOCK(fvp, 0, p);
-                error = EACCES;
-                goto abortit;
-        }
+               error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
+               if (!error && tvp)
+                       error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred, 
+                           tcnp->cn_proc);
+               if (error) {
+                       VOP_UNLOCK(fvp, 0, p);
+                       error = EACCES;
+                       goto abortit;
+               }
                /*
                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                 */
@@ -705,8 +724,7 @@ abortit:
         */
        ip->i_e2fs_nlink++;
        ip->i_flag |= IN_CHANGE;
-       TIMEVAL_TO_TIMESPEC(&time, &ts);
-       if ((error = VOP_UPDATE(fvp, &ts, &ts, 1)) != 0) {
+       if ((error = VOP_UPDATE(fvp, NULL, NULL, 1)) != 0) {
                VOP_UNLOCK(fvp, 0, p);
                goto bad;
        }
@@ -764,7 +782,7 @@ abortit:
                        }
                        dp->i_e2fs_nlink++;
                        dp->i_flag |= IN_CHANGE;
-                       if ((error = VOP_UPDATE(tdvp, &ts, &ts, 1)) != 0)
+                       if ((error = VOP_UPDATE(tdvp, NULL, NULL, 1)) != 0)
                                goto bad;
                }
                error = ext2fs_direnter(ip, tdvp, tcnp);
@@ -772,7 +790,7 @@ abortit:
                        if (doingdirectory && newparent) {
                                dp->i_e2fs_nlink--;
                                dp->i_flag |= IN_CHANGE;
-                               (void)VOP_UPDATE(tdvp, &ts, &ts, 1);
+                               (void)VOP_UPDATE(tdvp, NULL, NULL, 1);
                        }
                        goto bad;
                }
@@ -899,7 +917,7 @@ abortit:
                        error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
                                sizeof (struct ext2fs_dirtemplate), (off_t)0,
                                UIO_SYSSPACE, IO_NODELOCKED, 
-                               tcnp->cn_cred, NULL, (struct proc *)0);
+                               tcnp->cn_cred, (size_t *)0, (struct proc *)0);
                        if (error == 0) {
                                        namlen = dirbuf.dotdot_namlen;
                                if (namlen != 2 ||
@@ -908,13 +926,13 @@ abortit:
                                        ufs_dirbad(xp, (doff_t)12,
                                            "ext2fs_rename: mangled dir");
                                } else {
-                                       dirbuf.dotdot_ino = newparent;
+                                       dirbuf.dotdot_ino = h2fs32(newparent);
                                        (void) vn_rdwr(UIO_WRITE, fvp,
                                            (caddr_t)&dirbuf,
                                            sizeof (struct dirtemplate),
                                            (off_t)0, UIO_SYSSPACE,
                                            IO_NODELOCKED|IO_SYNC,
-                                           tcnp->cn_cred, NULL,
+                                           tcnp->cn_cred, (size_t *)0,
                                            (struct proc *)0);
                                        cache_purge(fdvp);
                                }
@@ -941,7 +959,7 @@ bad:
 out:
        if (doingdirectory)
                ip->i_flag &= ~IN_RENAME;
-       if (vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p) == 0) {
+       if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
                ip->i_e2fs_nlink--;
                ip->i_flag |= IN_CHANGE;
                vput(fvp);
@@ -950,14 +968,6 @@ out:
        return (error);
 }
 
-/*
- * A virgin directory (no blushing please).
- */
-static struct ext2fs_dirtemplate mastertemplate = {
-       0, 12, 1, ".",
-       0, - 12, 2, ".." /* XXX -12 should be e2fs_bsize-12 */
-};
-
 /*
  * Mkdir system call
  */
@@ -976,8 +986,7 @@ ext2fs_mkdir(v)
        register struct componentname *cnp = ap->a_cnp;
        register struct inode *ip, *dp;
        struct vnode *tvp;
-       struct ext2fs_dirtemplate dirtemplate, *dtp;
-       struct timespec ts;
+       struct ext2fs_dirtemplate dirtemplate;
        int error, dmode;
 
 #ifdef DIAGNOSTIC
@@ -1005,8 +1014,7 @@ ext2fs_mkdir(v)
        ip->i_e2fs_mode = dmode;
        tvp->v_type = VDIR;     /* Rest init'd in getnewvnode(). */
        ip->i_e2fs_nlink = 2;
-       TIMEVAL_TO_TIMESPEC(&time, &ts);
-       error = VOP_UPDATE(tvp, &ts, &ts, 1);
+       error = VOP_UPDATE(tvp, NULL, NULL, 1);
 
        /*
         * Bump link count in parent directory
@@ -1016,19 +1024,30 @@ ext2fs_mkdir(v)
         */
        dp->i_e2fs_nlink++;
        dp->i_flag |= IN_CHANGE;
-       if ((error = VOP_UPDATE(dvp, &ts, &ts, 1)) != 0)
+       if ((error = VOP_UPDATE(dvp, NULL, NULL, 1)) != 0)
                goto bad;
 
        /* Initialize directory with "." and ".." from static template. */
-       dtp = &mastertemplate;
-       dirtemplate = *dtp;
-       dirtemplate.dot_ino = ip->i_number;
-       dirtemplate.dotdot_ino = dp->i_number;
-       /* Correct reclen of second entry */
-    dirtemplate.dotdot_reclen = VTOI(dvp)->i_e2fs->e2fs_bsize - 12;
+       bzero(&dirtemplate, sizeof(dirtemplate));
+       dirtemplate.dot_ino = h2fs32(ip->i_number);
+       dirtemplate.dot_reclen = h2fs16(12);
+       dirtemplate.dot_namlen = 1;
+       if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
+           (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
+               dirtemplate.dot_type = EXT2_FT_DIR;
+       }
+       dirtemplate.dot_name[0] = '.';
+       dirtemplate.dotdot_ino = h2fs32(dp->i_number);
+       dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
+       dirtemplate.dotdot_namlen = 2;
+       if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
+           (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
+               dirtemplate.dotdot_type = EXT2_FT_DIR;
+       }
+       dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
        error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
            sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
-           IO_NODELOCKED|IO_SYNC, cnp->cn_cred, NULL, (struct proc *)0);
+           IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0);
        if (error) {
                dp->i_e2fs_nlink--;
                dp->i_flag |= IN_CHANGE;