From f5ee6277148794ac46779f661b67a553e461b529 Mon Sep 17 00:00:00 2001 From: jasoni Date: Wed, 26 Apr 2000 23:24:39 +0000 Subject: [PATCH] Support for ext2fs rev. 1 (from NetBSD) --- sys/ufs/ext2fs/ext2fs.h | 145 +++++++++++++----- sys/ufs/ext2fs/ext2fs_alloc.c | 16 +- sys/ufs/ext2fs/ext2fs_dinode.h | 16 +- sys/ufs/ext2fs/ext2fs_dir.h | 50 ++++++- sys/ufs/ext2fs/ext2fs_extern.h | 5 +- sys/ufs/ext2fs/ext2fs_inode.c | 4 +- sys/ufs/ext2fs/ext2fs_lookup.c | 18 ++- sys/ufs/ext2fs/ext2fs_vfsops.c | 262 ++++++++++++++++++++------------- sys/ufs/ext2fs/ext2fs_vnops.c | 153 ++++++++++--------- 9 files changed, 437 insertions(+), 232 deletions(-) diff --git a/sys/ufs/ext2fs/ext2fs.h b/sys/ufs/ext2fs/ext2fs.h index e1d7b8c4842..a5d683b137d 100644 --- a/sys/ufs/ext2fs/ext2fs.h +++ b/sys/ufs/ext2fs/ext2fs.h @@ -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 $ */ /* @@ -100,32 +100,46 @@ * 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. diff --git a/sys/ufs/ext2fs/ext2fs_alloc.c b/sys/ufs/ext2fs/ext2fs_alloc.c index 90897f7fd09..77d761a4c3f 100644 --- a/sys/ufs/ext2fs/ext2fs_alloc.c +++ b/sys/ufs/ext2fs/ext2fs_alloc.c @@ -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); diff --git a/sys/ufs/ext2fs/ext2fs_dinode.h b/sys/ufs/ext2fs/ext2fs_dinode.h index 5215322d30f..fe5c280f497 100644 --- a/sys/ufs/ext2fs/ext2fs_dinode.h +++ b/sys/ufs/ext2fs/ext2fs_dinode.h @@ -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)) diff --git a/sys/ufs/ext2fs/ext2fs_dir.h b/sys/ufs/ext2fs/ext2fs_dir.h index c959023414b..ae73124ee95 100644 --- a/sys/ufs/ext2fs/ext2fs_dir.h +++ b/sys/ufs/ext2fs/ext2fs_dir.h @@ -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 $ */ /* @@ -83,10 +83,50 @@ 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 */ }; diff --git a/sys/ufs/ext2fs/ext2fs_extern.h b/sys/ufs/ext2fs/ext2fs_extern.h index 7310611b52b..386399dba4e 100644 --- a/sys/ufs/ext2fs/ext2fs_extern.h +++ b/sys/ufs/ext2fs/ext2fs_extern.h @@ -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) diff --git a/sys/ufs/ext2fs/ext2fs_inode.c b/sys/ufs/ext2fs/ext2fs_inode.c index 9813965c3f4..d97a1290e96 100644 --- a/sys/ufs/ext2fs/ext2fs_inode.c +++ b/sys/ufs/ext2fs/ext2fs_inode.c @@ -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 static int ext2fs_indirtrunc __P((struct inode *, daddr_t, daddr_t, - daddr_t, int, long *)); + daddr_t, int, long *)); int ext2fs_init(vfsp) diff --git a/sys/ufs/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c index e05806462f4..11bc88989f9 100644 --- a/sys/ufs/ext2fs/ext2fs_lookup.c +++ b/sys/ufs/ext2fs/ext2fs_lookup.c @@ -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); diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index 2b6ba93d951..27aa5357325 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -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 #include #include +#include +#include #include @@ -66,7 +68,21 @@ #include #include +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); +} diff --git a/sys/ufs/ext2fs/ext2fs_vnops.c b/sys/ufs/ext2fs/ext2fs_vnops.c index 8348a54b15d..57218f04e65 100644 --- a/sys/ufs/ext2fs/ext2fs_vnops.c +++ b/sys/ufs/ext2fs/ext2fs_vnops.c @@ -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 $ */ /* @@ -57,10 +57,13 @@ #include #include #include +#include #include #include +#include + #include #include @@ -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; -- 2.20.1