diff --git a/sys/fs/ext2fs/ext2_alloc.c b/sys/fs/ext2fs/ext2_alloc.c index c834077aded5..15d938c938fe 100644 --- a/sys/fs/ext2fs/ext2_alloc.c +++ b/sys/fs/ext2fs/ext2_alloc.c @@ -344,6 +344,7 @@ ext2_valloc(pvp, mode, cred, vpp) struct ucred *cred; struct vnode **vpp; { + struct timespec ts; struct inode *pip; struct m_ext2fs *fs; struct inode *ip; @@ -385,14 +386,14 @@ ext2_valloc(pvp, mode, cred, vpp) } ip = VTOI(*vpp); - /* - the question is whether using VGET was such good idea at all - - Linux doesn't read the old inode in when it's allocating a - new one. I will set at least i_size & i_blocks the zero. - */ - ip->i_mode = 0; + /* + * The question is whether using VGET was such good idea at all: + * Linux doesn't read the old inode in when it is allocating a + * new one. I will set at least i_size and i_blocks to zero. + */ ip->i_size = 0; ip->i_blocks = 0; + ip->i_mode = 0; ip->i_flags = 0; /* now we want to make sure that the block pointers are zeroed out */ for (i = 0; i < NDADDR; i++) @@ -406,6 +407,11 @@ ext2_valloc(pvp, mode, cred, vpp) */ if (ip->i_gen == 0 || ++ip->i_gen == 0) ip->i_gen = random() / 2 + 1; + + vfs_timestamp(&ts); + ip->i_birthtime = ts.tv_sec; + ip->i_birthnsec = ts.tv_nsec; + /* printf("ext2_valloc: allocated inode %d\n", ino); */ diff --git a/sys/fs/ext2fs/ext2_dinode.h b/sys/fs/ext2fs/ext2_dinode.h index 6893ccc3f7cc..1a7bf2d49c83 100755 --- a/sys/fs/ext2fs/ext2_dinode.h +++ b/sys/fs/ext2fs/ext2_dinode.h @@ -61,6 +61,16 @@ #define EXT2_NODUMP 0x00000040 /* do not dump file */ #define EXT2_NOATIME 0x00000080 /* do not update atime */ +/* + * Definitions for nanosecond timestamps. + * Ext3 inode versioning, 2006-12-13. + */ +#define EXT3_EPOCH_BITS 2 +#define EXT3_EPOCH_MASK ((1 << EXT3_EPOCH_BITS) - 1) +#define EXT3_NSEC_MASK (~0UL << EXT3_EPOCH_BITS) + +#define E2DI_HAS_XTIME(ip) (EXT2_INODE_SIZE((ip)->i_e2fs) > \ + E2FS_REV0_INODE_SIZE) /* * Structure of an inode on the disk @@ -77,7 +87,7 @@ struct ext2fs_dinode { uint16_t e2di_nlink; /* 26: File link count */ uint32_t e2di_nblock; /* 28: Blocks count */ uint32_t e2di_flags; /* 32: Status flags (chflags) */ - uint32_t e2di_linux_reserved1; /* 36 */ + uint32_t e2di_version; /* 36: Low 32 bits inode version */ uint32_t e2di_blocks[EXT2_N_BLOCKS]; /* 40: disk blocks */ uint32_t e2di_gen; /* 100: generation number */ uint32_t e2di_facl; /* 104: file ACL (not implemented) */ @@ -91,6 +101,12 @@ struct ext2fs_dinode { uint32_t e2di_linux_reserved3; /* 124 */ uint16_t e2di_extra_isize; uint16_t e2di_pad1; + uint32_t e2di_ctime_extra; /* Extra change time */ + uint32_t e2di_mtime_extra; /* Extra modification time */ + uint32_t e2di_atime_extra; /* Extra access time */ + uint32_t e2di_crtime; /* Creation (birth)time */ + uint32_t e2di_crtime_extra; /* Extra creation (birth)time */ + uint32_t e2di_version_hi; /* High 30 bits of inode version */ }; #endif /* !_FS_EXT2FS_EXT2_DINODE_H_ */ diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c index b042a5a458f0..20361a7a4294 100644 --- a/sys/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/fs/ext2fs/ext2_inode_cnv.c @@ -36,6 +36,9 @@ #include #include +#define XTIME_TO_NSEC(x) ((x & EXT3_NSEC_MASK) >> 2) +#define NSEC_TO_XTIME(t) ((t << 2) & EXT3_NSEC_MASK) + void ext2_print_inode( in ) struct inode *in; @@ -83,6 +86,13 @@ ext2_ei2i(ei, ip) ip->i_atime = ei->e2di_atime; ip->i_mtime = ei->e2di_mtime; ip->i_ctime = ei->e2di_ctime; + if (E2DI_HAS_XTIME(ip)) { + ip->i_atimensec = XTIME_TO_NSEC(ei->e2di_atime_extra); + ip->i_mtimensec = XTIME_TO_NSEC(ei->e2di_mtime_extra); + ip->i_ctimensec = XTIME_TO_NSEC(ei->e2di_ctime_extra); + ip->i_birthtime = ei->e2di_crtime; + ip->i_birthnsec = XTIME_TO_NSEC(ei->e2di_crtime_extra); + } ip->i_flags = 0; ip->i_flags |= (ei->e2di_flags & EXT2_APPEND) ? SF_APPEND : 0; ip->i_flags |= (ei->e2di_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0; @@ -121,6 +131,13 @@ ext2_i2ei(ip, ei) ei->e2di_atime = ip->i_atime; ei->e2di_mtime = ip->i_mtime; ei->e2di_ctime = ip->i_ctime; + if (E2DI_HAS_XTIME(ip)) { + ei->e2di_ctime_extra = NSEC_TO_XTIME(ip->i_ctimensec); + ei->e2di_mtime_extra = NSEC_TO_XTIME(ip->i_mtimensec); + ei->e2di_atime_extra = NSEC_TO_XTIME(ip->i_atimensec); + ei->e2di_crtime = ip->i_birthtime; + ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec); + } ei->e2di_flags = ip->i_flags; ei->e2di_flags = 0; ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND: 0; diff --git a/sys/fs/ext2fs/ext2_vfsops.c b/sys/fs/ext2fs/ext2_vfsops.c index 8f7e8b8bb683..48d5cb2b429b 100644 --- a/sys/fs/ext2fs/ext2_vfsops.c +++ b/sys/fs/ext2fs/ext2_vfsops.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -339,14 +340,21 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es, /* * Simple sanity check for superblock inode size value. */ - if (fs->e2fs_isize < E2FS_REV0_INODE_SIZE || - fs->e2fs_isize > fs->e2fs_bsize || + if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE || + EXT2_INODE_SIZE(fs) > fs->e2fs_bsize || (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) { - printf("EXT2-fs: invalid inode size %d\n", + printf("ext2fs: invalid inode size %d\n", fs->e2fs_isize); return (EIO); } } + /* Check for extra isize in big inodes. */ + if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT4F_ROCOMPAT_EXTRA_ISIZE) && + EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) { + printf("ext2fs: no space for extra inode timestamps\n"); + return (EINVAL); + } + fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs); fs->e2fs_itpg = fs->e2fs_ipg /fs->e2fs_ipb; fs->e2fs_descpb = fs->e2fs_bsize / sizeof(struct ext2_gd); @@ -358,8 +366,8 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es, fs->e2fs_gdbcount = db_count; fs->e2fs_gd = malloc(db_count * fs->e2fs_bsize, M_EXT2MNT, M_WAITOK); - fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * sizeof(*fs->e2fs_contigdirs), - M_EXT2MNT, M_WAITOK); + fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * + sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK); /* * Adjust logic_sb_block. @@ -390,7 +398,7 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es, fs->e2fs_contigdirs[i] = 0; } if (es->e2fs_rev == E2FS_REV0 || - (es->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE) == 0) + !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE)) fs->e2fs_maxfilesize = 0x7fffffff; else fs->e2fs_maxfilesize = 0x7fffffffffffffff; @@ -967,8 +975,6 @@ ext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) ip->i_block_group = ino_to_cg(fs, ino); ip->i_next_alloc_block = 0; ip->i_next_alloc_goal = 0; - ip->i_prealloc_count = 0; - ip->i_prealloc_block = 0; /* * Now we want to make sure that block pointers for unused diff --git a/sys/fs/ext2fs/ext2_vnops.c b/sys/fs/ext2fs/ext2_vnops.c index c357a2a85a52..136654c048c5 100644 --- a/sys/fs/ext2fs/ext2_vnops.c +++ b/sys/fs/ext2fs/ext2_vnops.c @@ -360,11 +360,15 @@ ext2_getattr(ap) vap->va_rdev = ip->i_rdev; vap->va_size = ip->i_size; vap->va_atime.tv_sec = ip->i_atime; - vap->va_atime.tv_nsec = ip->i_atimensec; + vap->va_atime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_atimensec : 0; vap->va_mtime.tv_sec = ip->i_mtime; - vap->va_mtime.tv_nsec = ip->i_mtimensec; + vap->va_mtime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_mtimensec : 0; vap->va_ctime.tv_sec = ip->i_ctime; - vap->va_ctime.tv_nsec = ip->i_ctimensec; + vap->va_ctime.tv_nsec = E2DI_HAS_XTIME(ip) ? ip->i_ctimensec : 0; + if E2DI_HAS_XTIME(ip) { + vap->va_birthtime.tv_sec = ip->i_birthtime; + vap->va_birthtime.tv_nsec = ip->i_birthnsec; + } vap->va_flags = ip->i_flags; vap->va_gen = ip->i_gen; vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; @@ -501,6 +505,8 @@ ext2_setattr(ap) ip->i_mtime = vap->va_mtime.tv_sec; ip->i_mtimensec = vap->va_mtime.tv_nsec; } + ip->i_birthtime = vap->va_birthtime.tv_sec; + ip->i_birthnsec = vap->va_birthtime.tv_nsec; error = ext2_update(vp, 0); if (error) return (error); diff --git a/sys/fs/ext2fs/ext2fs.h b/sys/fs/ext2fs/ext2fs.h index 14027ab12f50..83e2a68af85a 100755 --- a/sys/fs/ext2fs/ext2fs.h +++ b/sys/fs/ext2fs/ext2fs.h @@ -129,7 +129,7 @@ struct ext2fs { uint32_t e4fs_rbcount_hi; /* reserved blocks count */ uint32_t e4fs_fbcount_hi; /* free blocks count */ uint16_t e4fs_min_extra_isize;/* all inodes have at least some bytes */ - uint16_t e4fs_want_extra_isize; /* new inodes should reserve some bytes */ + uint16_t e4fs_want_extra_isize; /* inodes must reserve some bytes */ uint32_t e4fs_flags; /* miscellaneous flags */ uint16_t e4fs_raid_stride; /* RAID stride */ uint16_t e4fs_mmpintv; /* number of seconds to wait in MMP checking */ @@ -214,6 +214,7 @@ struct m_ext2fs { #define EXT2F_ROCOMPAT_SPARSESUPER 0x0001 #define EXT2F_ROCOMPAT_LARGEFILE 0x0002 #define EXT2F_ROCOMPAT_BTREE_DIR 0x0004 +#define EXT4F_ROCOMPAT_EXTRA_ISIZE 0x0040 #define EXT2F_INCOMPAT_COMP 0x0001 #define EXT2F_INCOMPAT_FTYPE 0x0002 @@ -227,8 +228,9 @@ struct m_ext2fs { * - EXT2F_INCOMPAT_FTYPE */ #define EXT2F_COMPAT_SUPP 0x0000 -#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \ - | EXT2F_ROCOMPAT_LARGEFILE) +#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER | \ + EXT2F_ROCOMPAT_LARGEFILE | \ + EXT4F_ROCOMPAT_EXTRA_ISIZE) #define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE /* Assume that user mode programs are passing in an ext2fs superblock, not diff --git a/sys/fs/ext2fs/inode.h b/sys/fs/ext2fs/inode.h index 659b950e1069..100a07687db7 100644 --- a/sys/fs/ext2fs/inode.h +++ b/sys/fs/ext2fs/inode.h @@ -77,8 +77,6 @@ struct inode { uint32_t i_block_group; uint32_t i_next_alloc_block; uint32_t i_next_alloc_goal; - uint32_t i_prealloc_block; - uint32_t i_prealloc_count; /* Fields from struct dinode in UFS. */ uint16_t i_mode; /* IFMT, permissions; see below. */