Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 8 Mar 2012 21:06:05 +0000 (UTC)
From:      "Pedro F. Giffuni" <pfg@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r232703 - head/sys/fs/ext2fs
Message-ID:  <201203082106.q28L65Bw064874@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: pfg
Date: Thu Mar  8 21:06:05 2012
New Revision: 232703
URL: http://svn.freebsd.org/changeset/base/232703

Log:
  Add support for ns timestamps and birthtime to the ext2/3 driver.
  
  When using big inodes there is sufficient space in ext3 to
  keep extra resolution and birthtime (creation) timestamps.
  The appropriate fields in the on-disk inode have been approved
  for a long time but support for this in ext3 has not been
  widely  distributed.
  
  In preparation for ext4 most linux distributions have enabled
  by default such bigger inodes and some people use nanosecond
  timestamps in ext3. We now support those when the inode is big
  enough and while we do recognize the EXT4F_ROCOMPAT_EXTRA_ISIZE,
  we maintain the extra timestamps even when they are not used.
  
  An additional note by Bruce Evans:
  We blindly accept unrepresentable tv_nsec in VOP_SETATTR(), but
  all file  systems have always done that.  When POSIX gets around
  to  specifying the behaviour, it will probably require certain
  rounding to the fs's resolution and not rejecting the request.
  This unfortunately means that syscalls that set times can't
  really tell if they succeeded without reading back the times
  using stat() or similar and checking that they were set close
  enough.
  
  Reviewed by:	bde
  Approved by:	jhb (mentor)
  MFC after:	2 weeks

Modified:
  head/sys/fs/ext2fs/ext2_alloc.c
  head/sys/fs/ext2fs/ext2_dinode.h
  head/sys/fs/ext2fs/ext2_inode_cnv.c
  head/sys/fs/ext2fs/ext2_vfsops.c
  head/sys/fs/ext2fs/ext2_vnops.c
  head/sys/fs/ext2fs/ext2fs.h
  head/sys/fs/ext2fs/inode.h

Modified: head/sys/fs/ext2fs/ext2_alloc.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_alloc.c	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/ext2_alloc.c	Thu Mar  8 21:06:05 2012	(r232703)
@@ -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);
 */

Modified: head/sys/fs/ext2fs/ext2_dinode.h
==============================================================================
--- head/sys/fs/ext2fs/ext2_dinode.h	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/ext2_dinode.h	Thu Mar  8 21:06:05 2012	(r232703)
@@ -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_ */

Modified: head/sys/fs/ext2fs/ext2_inode_cnv.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_inode_cnv.c	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/ext2_inode_cnv.c	Thu Mar  8 21:06:05 2012	(r232703)
@@ -36,6 +36,9 @@
 #include <fs/ext2fs/ext2_extern.h>
 #include <fs/ext2fs/ext2_dinode.h>
 
+#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;

Modified: head/sys/fs/ext2fs/ext2_vfsops.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_vfsops.c	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/ext2_vfsops.c	Thu Mar  8 21:06:05 2012	(r232703)
@@ -47,6 +47,7 @@
 #include <sys/bio.h>
 #include <sys/buf.h>
 #include <sys/conf.h>
+#include <sys/endian.h>
 #include <sys/fcntl.h>
 #include <sys/malloc.h>
 #include <sys/stat.h>
@@ -339,14 +340,21 @@ compute_sb_data(struct vnode *devvp, str
 		/*
 		 * 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, str
 	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, str
 		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, i
 	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

Modified: head/sys/fs/ext2fs/ext2_vnops.c
==============================================================================
--- head/sys/fs/ext2fs/ext2_vnops.c	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/ext2_vnops.c	Thu Mar  8 21:06:05 2012	(r232703)
@@ -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);

Modified: head/sys/fs/ext2fs/ext2fs.h
==============================================================================
--- head/sys/fs/ext2fs/ext2fs.h	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/ext2fs.h	Thu Mar  8 21:06:05 2012	(r232703)
@@ -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

Modified: head/sys/fs/ext2fs/inode.h
==============================================================================
--- head/sys/fs/ext2fs/inode.h	Thu Mar  8 20:34:13 2012	(r232702)
+++ head/sys/fs/ext2fs/inode.h	Thu Mar  8 21:06:05 2012	(r232703)
@@ -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. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203082106.q28L65Bw064874>