Index: sbin/newfs/extern.h
===================================================================
RCS file: /cvsroot/src/sbin/newfs/extern.h,v
retrieving revision 1.13
diff -u -r1.13 extern.h
--- sbin/newfs/extern.h	26 Aug 2006 22:03:47 -0000	1.13
+++ sbin/newfs/extern.h	18 Jan 2007 09:59:52 -0000
@@ -48,6 +48,7 @@
 extern int	minfree;	/* free space threshold */
 extern int	opt;		/* optimization preference (space or time) */
 extern int	density;	/* number of bytes per inode */
+extern int	jsize;		/* size of journal */
 extern int	num_inodes;	/* number of inodes (overrides density) */
 extern int	maxcontig;	/* max contiguous blocks to allocate */
 extern int	maxbpg;		/* maximum blocks per file in a cyl group */
Index: sbin/newfs/mkfs.c
===================================================================
RCS file: /cvsroot/src/sbin/newfs/mkfs.c,v
retrieving revision 1.102
diff -u -r1.102 mkfs.c
--- sbin/newfs/mkfs.c	16 Oct 2006 03:04:45 -0000	1.102
+++ sbin/newfs/mkfs.c	18 Jan 2007 09:59:53 -0000
@@ -119,6 +119,8 @@
 static void setblock(struct fs *, unsigned char *, int);
 static int ilog2(int);
 static void zap_old_sblock(int);
+static void ffs_alloc_dinode(struct ufs2_dinode *, int, struct fs *);
+static void ffs_write_dinode(struct ufs2_dinode *, int, struct fs *, void *);
 #ifdef MFS
 static void calc_memfree(void);
 static void *mkfs_malloc(size_t size);
@@ -310,7 +312,11 @@
 		sblock.fs_old_postblformat = FS_DYNAMICPOSTBLFMT;
 		sblock.fs_old_nrpos = 1;
 	} else {
-		sblock.fs_magic = FS_UFS2_MAGIC;
+		if (jsize)
+			sblock.fs_magic = FS_UFS2J_MAGIC;
+		else
+			sblock.fs_magic = FS_UFS2_MAGIC;
+
 		sblock.fs_sblockloc = SBLOCK_UFS2;
 		sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t);
 		sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
@@ -529,9 +535,12 @@
 		    sblock.fs_bsize, sblock.fs_fsize);
 		printf("\tusing %d cylinder groups of %.2fMB, %d blks, "
 		       "%d inodes.\n",
+			
 		    sblock.fs_ncg,
 		    (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
 		    sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
+		   if (jsize)
+			printf("\tjournal size %dbytes.\n", jsize);
 #undef B2MBFACTOR
 	}
 
@@ -996,6 +1005,7 @@
 fsinit(const struct timeval *tv, mode_t mfsmode, uid_t mfsuid, gid_t mfsgid)
 {
 	union dinode node;
+	char *buf2;
 #ifdef LOSTDIR
 	int i;
 	int dirblksiz = DIRBLKSIZ;
@@ -1092,7 +1102,7 @@
 		    node.dp1.di_size));
 		wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), sblock.fs_fsize, buf);
 	} else {
-		if (mfs) {
+	if (mfs) {
 			node.dp2.di_mode = IFDIR | mfsmode;
 			node.dp2.di_uid = mfsuid;
 			node.dp2.di_gid = mfsgid;
@@ -1119,6 +1129,58 @@
 		wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), sblock.fs_fsize, buf);
 	}
 	iput(&node, ROOTINO);
+
+	/*
+	 * XXX only create journal file for UFS2 for now.
+	 */
+	if (jsize) {
+		/*
+	 	 * create the journal file
+	 	 */
+		memset(&node, 0, sizeof(node));	
+		node.dp2.di_mode = IFREG | UMASK;
+		node.dp2.di_uid = geteuid();
+		node.dp2.di_gid = getegid();
+		node.dp2.di_atime = tv->tv_sec;
+		node.dp2.di_atimensec = tv->tv_usec * 1000;
+		node.dp2.di_mtime = tv->tv_sec;
+		node.dp2.di_mtimensec = tv->tv_usec * 1000;
+		node.dp2.di_ctime = tv->tv_sec;
+		node.dp2.di_ctimensec = tv->tv_usec * 1000;
+		node.dp2.di_birthtime = tv->tv_sec;
+		node.dp2.di_birthnsec = tv->tv_usec * 1000;
+		node.dp2.di_nlink = 1;
+		node.dp2.di_size = jsize;
+
+		buf2 = malloc(sblock.fs_bsize);
+		memset(buf2, 0, sblock.fs_bsize);
+
+		/* allocate blocks for journal file */
+		ffs_alloc_dinode(&node.dp2, 
+		    howmany(node.dp2.di_size, sblock.fs_bsize), &sblock);
+
+		/*
+		journal_sblock = (struct ffs_journal_sblock *)jbuf;
+		journal_sblock->flags = FFS_JOURNAL_CLEAN;
+		journal_sblock->begin = 0;
+		journal_sblock->end = 0;
+		*/
+
+		/* write changes to filesystem */
+		ffs_write_dinode(&node.dp2, 
+		    howmany(node.dp2.di_size, sblock.fs_bsize), &sblock, buf2);
+
+		/* XXX which inode do we place this at? Probably wants to be
+	 	 * as small as possible so that the read is quicker i.e. it's
+		 * at the outter tracks of the disk.
+	 	 * Also want to replace this magic number with a constant. 
+	 	 */
+		iput(&node, JINO);
+
+		/* record the inode number in the superblock. */
+		sblock.fs_ijournal = JINO;
+	}
+
 	return (1);
 }
 
@@ -1497,6 +1559,100 @@
 	wtfs(sblkoff/sectorsize, sizeof oldfs, &oldfs);
 }
 
+/*
+ * This function sets up a dinode entry with 'nblks' blocks allocated
+ * to it. NB we allocate full blocks (no fragments).
+ */
+void
+ffs_alloc_dinode(struct ufs2_dinode *dip, int nblocks, struct fs *fs)
+{
+	int i;
+	int bb, base, factor, lvl;
+	int32_t ifibc = 0;		/* How many indirects blocks */
+
+	dip->di_blocks = nblocks >> (fs->fs_bshift - fs->fs_fsbtodb + 
+			fs->fs_fsbtodb);
+
+	if (NDADDR < nblocks) {
+		/* Count up how many indirect blocks we need, recursively */
+		/* XXX We are only called with nblocks > 1 for Ifile */
+		bb = nblocks - NDADDR;
+		while (bb > 0) {
+			bb = howmany(bb, NINDIR(fs));
+			ifibc += bb;
+			--bb;
+		}
+		dip->di_blocks += (unsigned int)btodb(fragroundup(fs, dip->di_size));
+	}
+
+	/* Assign the block addresses for the ifile */
+	for (i = 0; i < MIN(nblocks,NDADDR); i++) {
+		dip->di_db[i] = alloc(fs->fs_bsize, dip->di_mode);
+		if (dip->di_db[i] == 0)
+			err(1, "Could not allocate block\n");
+	}
+	if(nblocks > NDADDR) {
+		dip->di_ib[0] = alloc(fs->fs_bsize,  dip->di_mode);
+		if (dip->di_ib[0] == 0)
+			err(1, "Could not allocate  block\n");
+		bb = howmany(nblocks - NDADDR, NINDIR(fs)) - 1;
+		factor = NINDIR(fs);
+		base = -NDADDR - factor;
+		lvl = 1;
+		while (bb > 0) {
+			dip->di_ib[lvl] = alloc(fs->fs_bsize, dip->di_mode);
+			if (dip->di_ib[lvl] == 0)
+				err(1, "Could not allocate block\n");
+			bb = howmany(bb, NINDIR(fs));
+			--bb;
+			factor *= NINDIR(fs);
+			base -= factor;
+			++lvl;
+		}
+	}
+}
+
+/*
+ * This function writes the data in 'data' to the on-disk inode, 'dip'.
+ */
+void
+ffs_write_dinode(struct ufs2_dinode *dip, int nblocks, struct fs *fs, void *data)
+{
+	int i;
+	int bb, base, factor, lvl;
+	int32_t ifibc = 0;		/* How many indirects blocks */
+
+	if (NDADDR < nblocks) {
+		/* Count up how many indirect blocks we need, recursively */
+		/* XXX We are only called with nblocks > 1 for Ifile */
+		bb = nblocks - NDADDR;
+		while (bb > 0) {
+			bb = howmany(bb, NINDIR(fs));
+			ifibc += bb;
+			--bb;
+		}
+	}
+
+	/* Assign the block addresses for the ifile */
+	for (i = 0; i < MIN(nblocks,NDADDR); i++) {
+		wtfs(fsbtodb(fs, dip->di_db[i]), fs->fs_fsize, data);
+	}
+	if(nblocks > NDADDR) {
+		wtfs(fsbtodb(fs, dip->di_ib[0]), fs->fs_bsize, data);
+		bb = howmany(nblocks - NDADDR, NINDIR(fs)) - 1;
+		factor = NINDIR(fs);
+		base = -NDADDR - factor;
+		lvl = 1;
+		while (bb > 0) {
+			wtfs(fsbtodb(fs, dip->di_ib[lvl]), fs->fs_fsize, data);
+			bb = howmany(bb, NINDIR(fs));
+			--bb;
+			factor *= NINDIR(fs);
+			base -= factor;
+			++lvl;
+		}
+	}
+}
 
 #ifdef MFS
 /*
Index: sbin/newfs/newfs.8
===================================================================
RCS file: /cvsroot/src/sbin/newfs/newfs.8,v
retrieving revision 1.69
diff -u -r1.69 newfs.8
--- sbin/newfs/newfs.8	25 Feb 2006 01:56:41 -0000	1.69
+++ sbin/newfs/newfs.8	18 Jan 2007 09:59:54 -0000
@@ -47,6 +47,7 @@
 .Op Fl g Ar avgfilesize
 .Op Fl h Ar avgfpdir
 .Op Fl i Ar bytes-per-inode
+.Op Fl j Ar journalsize
 .Op Fl m Ar free-space
 .Op Fl n Ar inodes
 .Op Fl O Ar filesystem-format
@@ -180,6 +181,9 @@
 .It \*[Gt]= 1024 MB
 8 KB
 .El
+.It Fl j Ar journalsize
+This is the size of the journal. It should be large enough to hold at
+least one journal entry.
 .It Fl m Ar free-space
 The percentage of space reserved from normal users; the minimum free
 space threshold.
Index: sbin/newfs/newfs.c
===================================================================
RCS file: /cvsroot/src/sbin/newfs/newfs.c,v
retrieving revision 1.96
diff -u -r1.96 newfs.c
--- sbin/newfs/newfs.c	25 Nov 2006 18:18:22 -0000	1.96
+++ sbin/newfs/newfs.c	18 Jan 2007 09:59:54 -0000
@@ -197,6 +197,7 @@
 
 int	mfs;			/* run as the memory based filesystem */
 int	Nflag;			/* run without writing file system */
+int	jsize = 0;		/* size of journal */
 int	Oflag = 1;		/* format as an 4.3BSD file system */
 int	verbosity;		/* amount of printf() output */
 #define DEFAULT_VERBOSITY 3	/* 4 is traditional behavior */
@@ -264,7 +265,7 @@
 
 	opstring = mfs ?
 	    "NT:V:a:b:d:e:f:g:h:i:m:n:o:p:s:u:" :
-	    "B:FINO:S:T:V:Za:b:d:e:f:g:h:i:l:m:n:o:r:s:v:";
+	    "B:FINO:S:T:V:Za:b:d:e:f:g:h:i:j:l:m:n:o:r:s:v:";
 	while ((ch = getopt(argc, argv, opstring)) != -1)
 		switch (ch) {
 		case 'B':
@@ -349,6 +350,10 @@
 			density = strsuftoi64("bytes per inode",
 			    optarg, 1, INT_MAX, NULL);
 			break;
+		case 'j':
+			jsize = strsuftoi64("journal size", optarg, 1, 
+				MAXJOURNALSIZE, NULL);
+			break;
 		case 'm':
 			minfree = strsuftoi64("free space %",
 			    optarg, 0, 99, NULL);
@@ -804,6 +809,7 @@
 	{ MFS_MOUNT,	"-g groupname\tgroup name of mount point" },
 	{ BOTH,		"-h avgfpdir\taverage files per directory" },
 	{ BOTH,		"-i density\tnumber of bytes per inode" },
+	{ NEWFS,	"-j jsize \tjournal size" },
 	{ BOTH,		"-m minfree\tminimum free space %%" },
 	{ BOTH,		"-n inodes\tnumber of inodes (overrides -i density)" },
 	{ BOTH,		"-o optim\toptimization preference (`space' or `time')"
Index: sys/lib/libsa/ufs.c
===================================================================
RCS file: /cvsroot/src/sys/lib/libsa/ufs.c,v
retrieving revision 1.49
diff -u -r1.49 ufs.c
--- sys/lib/libsa/ufs.c	11 May 2006 01:13:44 -0000	1.49
+++ sys/lib/libsa/ufs.c	18 Jan 2007 10:00:17 -0000
@@ -500,7 +500,8 @@
 		if (fs->fs_sblockloc != sblock_try[i])
 			/* an alternate superblock - try again */
 			continue;
-		if (fs->fs_magic == FS_UFS2_MAGIC) {
+		if (fs->fs_magic == FS_UFS2_MAGIC || 
+		    fs->fs_magic == FS_UFS2J_MAGIC) {
 			return 0;
 		}
 	}
Index: sys/ufs/files.ufs
===================================================================
RCS file: /cvsroot/src/sys/ufs/files.ufs,v
retrieving revision 1.16
diff -u -r1.16 files.ufs
--- sys/ufs/files.ufs	13 Nov 2006 16:12:54 -0000	1.16
+++ sys/ufs/files.ufs	18 Jan 2007 10:00:20 -0000
@@ -24,6 +24,7 @@
 file	ufs/ffs/ffs_balloc.c		ffs | mfs | ext2fs
 file	ufs/ffs/ffs_bswap.c		(ffs | mfs) & ffs_ei
 file	ufs/ffs/ffs_inode.c		ffs | mfs | ext2fs
+file	ufs/ffs/ffs_journal.c		ffs
 file	ufs/ffs/ffs_snapshot.c		ffs | mfs | ext2fs
 file	ufs/ffs/ffs_softdep.c		ffs & softdep
 file	ufs/ffs/ffs_softdep.stub.c	(ffs & !softdep) |
Index: sys/ufs/ffs/ffs_alloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_alloc.c,v
retrieving revision 1.97
diff -u -r1.97 ffs_alloc.c
--- sys/ufs/ffs/ffs_alloc.c	4 Jan 2007 16:55:29 -0000	1.97
+++ sys/ufs/ffs/ffs_alloc.c	18 Jan 2007 10:00:21 -0000
@@ -240,7 +240,7 @@
 	if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER, NULL) != 0 &&
 	    freespace(fs, fs->fs_minfree) <= 0)
 		goto nospace;
-	if (fs->fs_magic == FS_UFS2_MAGIC)
+	if (fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2J_MAGIC)
 		bprev = ufs_rw64(ip->i_ffs2_db[lbprev], UFS_FSNEEDSWAP(fs));
 	else
 		bprev = ufs_rw32(ip->i_ffs1_db[lbprev], UFS_FSNEEDSWAP(fs));
@@ -721,7 +721,7 @@
 	 */
 	ip->i_gen++;
 	DIP_ASSIGN(ip, gen, ip->i_gen);
-	if (fs->fs_magic == FS_UFS2_MAGIC) {
+	if (fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2J_MAGIC) {
 		vfs_timestamp(&ts);
 		ip->i_ffs2_birthtime = ts.tv_sec;
 		ip->i_ffs2_birthnsec = ts.tv_nsec;
@@ -1463,7 +1463,7 @@
 	 * Check to see if we need to initialize more inodes.
 	 */
 	initediblk = ufs_rw32(cgp->cg_initediblk, needswap);
-	if (fs->fs_magic == FS_UFS2_MAGIC &&
+	if ((fs->fs_magic == FS_UFS2_MAGIC || fs->fs_magic == FS_UFS2J_MAGIC) &&
 	    ipref + INOPB(fs) > initediblk &&
 	    initediblk < ufs_rw32(cgp->cg_niblk, needswap)) {
 		ibp = getblk(ip->i_devvp, fsbtodb(fs,
Index: sys/ufs/ffs/ffs_balloc.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_balloc.c,v
retrieving revision 1.43
diff -u -r1.43 ffs_balloc.c
--- sys/ufs/ffs/ffs_balloc.c	14 May 2006 21:32:45 -0000	1.43
+++ sys/ufs/ffs/ffs_balloc.c	18 Jan 2007 10:00:21 -0000
@@ -83,7 +83,8 @@
     struct buf **bpp)
 {
 
-	if (VTOI(vp)->i_fs->fs_magic == FS_UFS2_MAGIC)
+	if (VTOI(vp)->i_fs->fs_magic == FS_UFS2_MAGIC || 
+	    VTOI(vp)->i_fs->fs_magic == FS_UFS2J_MAGIC)
 		return ffs_balloc_ufs2(vp, off, size, cred, flags, bpp);
 	else
 		return ffs_balloc_ufs1(vp, off, size, cred, flags, bpp);
Index: sys/ufs/ffs/ffs_bswap.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_bswap.c,v
retrieving revision 1.32
diff -u -r1.32 ffs_bswap.c
--- sys/ufs/ffs/ffs_bswap.c	11 Dec 2005 12:25:25 -0000	1.32
+++ sys/ufs/ffs/ffs_bswap.c	18 Jan 2007 10:00:21 -0000
@@ -211,7 +211,8 @@
 	for (i = 0; i < MAXFRAG; i++)
 		n->cg_frsum[i] = bswap32(o->cg_frsum[i]);
 
-	if ((fs->fs_magic != FS_UFS2_MAGIC) &&
+	if ((fs->fs_magic != FS_UFS2_MAGIC && 
+	     fs->fs_magic != FS_UFS2J_MAGIC) &&
 			(fs->fs_old_postblformat == FS_42POSTBLFMT)) { /* old format */
 		struct ocg *on, *oo;
 		int j;
@@ -254,7 +255,8 @@
 		for (i = 1; i < fs->fs_contigsumsize + 1; i++)
 			n32[i] = bswap32(o32[i]);
 
-		if (fs->fs_magic == FS_UFS2_MAGIC)
+		if (fs->fs_magic == FS_UFS2_MAGIC ||
+		    fs->fs_magic == FS_UFS2J_MAGIC)
 			return;
 
 		n32 = (u_int32_t *)((u_int8_t *)n + btotoff);
Index: sys/ufs/ffs/ffs_extern.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_extern.h,v
retrieving revision 1.54
diff -u -r1.54 ffs_extern.h
--- sys/ufs/ffs/ffs_extern.h	13 Jul 2006 12:00:26 -0000	1.54
+++ sys/ufs/ffs/ffs_extern.h	18 Jan 2007 10:00:22 -0000
@@ -65,6 +65,10 @@
 struct vnode;
 struct mbuf;
 struct cg;
+struct ffs_log_entry;
+struct ffs_transaction;
+struct ffs_journal_entry;
+struct ffs_journal_sblock;
 
 #if defined(_KERNEL)
 
@@ -107,6 +111,15 @@
     const struct timespec *, int);
 int	ffs_truncate(struct vnode *, off_t, int, kauth_cred_t, struct lwp *);
 
+/* ffs_journal.c */
+int	ffs_journal_unmount(struct mount *, struct fs *);
+int	ffs_journal_mount(struct mount *);
+int	ffs_journal_replay(struct ffs_journal_entry *, int);
+void	ffs_roll_journal(struct ffs_journal_sblock *);
+int	ffs_begin_trans(void);
+int	ffs_finish_trans(void);
+int	ffs_journal_write_blocks(void);
+
 /* ffs_vfsops.c */
 void	ffs_init(void);
 void	ffs_reinit(void);
Index: sys/ufs/ffs/ffs_vfsops.c
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vfsops.c,v
retrieving revision 1.192
diff -u -r1.192 ffs_vfsops.c
--- sys/ufs/ffs/ffs_vfsops.c	7 Jan 2007 09:33:18 -0000	1.192
+++ sys/ufs/ffs/ffs_vfsops.c	18 Jan 2007 10:00:23 -0000
@@ -501,6 +501,14 @@
 		return (EINVAL);
 
 	ump = VFSTOUFS(mp);
+
+	/*
+	 * XXX If journaling is enabled on this filesystem we need
+	 * a better way to reload (we can't simply invalidate the meta-data).
+	 */
+	if (ump->um_fs->fs_magic == FS_UFS2J_MAGIC)
+		return (EOPNOTSUPP);
+
 	/*
 	 * Step 1: invalidate all cached meta-data.
 	 */
@@ -716,6 +724,7 @@
 	daddr_t sblockloc, fsblockloc;
 	int blks, fstype;
 	int error, i, size, ronly;
+	int journal = 0;
 #ifdef FFS_EI
 	int needswap = 0;		/* keep gcc happy */
 #endif
@@ -787,6 +796,18 @@
 			fstype = UFS2;
 			needswap = 1;
 #endif
+		} else if (fs->fs_magic == FS_UFS2J_MAGIC) {
+			sbsize = fs->fs_sbsize;
+			fstype = UFS2;
+			journal = 1;
+#ifdef FFS_EI
+			needswap = 0;
+		} else if (fs->fs_magic == bswap32(FS_UFS2J_MAGIC)) {
+			sbsize = bswap32(fs->fs_sbsize);
+			fstype = UFS2;
+			journal = 1;
+			needswap = 1;
+#endif
 		} else
 			continue;
 
@@ -1014,6 +1035,15 @@
 #endif
 	}
 #endif /* UFS_EXTATTR */
+
+	/*
+	 * Execute journal code.
+	 */
+	if (journal) {
+		if (ffs_journal_mount(mp) != 0)
+			goto out;
+	}
+
 	return (0);
 out:
 	if (fs)
@@ -1169,7 +1199,13 @@
 		} else
 			ufs_extattr_uepm_destroy(&ump->um_extattr);
 	}
+
 #endif /* UFS_EXTATTR */
+	if (fs->fs_magic == FS_UFS2J_MAGIC) {
+		if ((error = ffs_journal_unmount(mp, fs)))
+			return (error);
+	}
+
 	if (mp->mnt_flag & MNT_SOFTDEP) {
 		if ((error = softdep_flushfiles(mp, flags, l)) != 0)
 			return (error);
@@ -1177,6 +1213,7 @@
 		if ((error = ffs_flushfiles(mp, flags, l)) != 0)
 			return (error);
 	}
+
 	if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
 		printf("%s: unmount pending error: blocks %" PRId64
 		       " files %d\n",
Index: sys/ufs/ffs/fs.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ffs/fs.h,v
retrieving revision 1.46
diff -u -r1.46 fs.h
--- sys/ufs/ffs/fs.h	11 Dec 2005 12:25:25 -0000	1.46
+++ sys/ufs/ffs/fs.h	18 Jan 2007 10:00:24 -0000
@@ -356,6 +356,7 @@
 	int32_t  fs_spare5[2];		/* old fs_postbloff */
 					/* old fs_rotbloff */
 	int32_t	 fs_magic;		/* magic number */
+	int32_t  fs_ijournal;		/* inode of journal */
 };
 
 #define fs_old_postbloff	fs_spare5[0]
@@ -387,6 +388,7 @@
 #define	FS_UFS2_MAGIC	0x19540119	/* UFS2 fast file system magic number */
 #define FS_UFS1_MAGIC_SWAPPED	0x54190100
 #define FS_UFS2_MAGIC_SWAPPED	0x19015419
+#define	FS_UFS2J_MAGIC	0x19540120	/* UFS2 with journalling support */
 #define	FS_OKAY		0x7c269d38	/* superblock checksum */
 #define	FS_42INODEFMT	-1		/* 4.2BSD inode format */
 #define	FS_44INODEFMT	2		/* 4.4BSD inode format */
@@ -725,4 +727,71 @@
 } __attribute__((__packed__));
 
 
+/*
+ * Journaling support for FFS requires two data structures for
+ * transactions, an in-memory structure and an on-disk structure.
+ *
+ * The in-memory data structure is represetned by the 'ffs_transaction'
+ * structure, and the on-disk data structure is represented by the
+ * 'ffs_journal_entry' structure.
+ *
+ * These data structres have been taken from Dominic Giampaolo's
+ * "Practical File System Design with The Be File System", I'm not sure
+ * if they're totally applicable here.
+ */
+
+#define		MAXBLOCKS	128
+#define		MAXJOURNALSIZE	0x100000
+
+/*
+ * These flags are used in the journal superblock stored inside the log area.
+ * When all transactions complete, the flags of the superblock should be
+ * marked FFS_JOURNAL_CLEAN.
+ */
+#define	FFS_JOURNAL_CLEAN	0x0001	/* All transactions have completed. */
+#define	FFS_JOURNAL_DIRTY	0x0002	/* Transactions are outstanding. */
+
+
+/*
+ * In-memory data structures for a transaction.
+ *
+ * XXX We may want to support 'batched transactions'. But this can
+ * be added later.
+ */
+struct ffs_transaction {
+	blkcnt_t	nblks;		/* num of blocks in trans */
+	off_t		begin;		/* where this transaction starts
+					 * in the log area
+					 */
+	off_t		endl;		/* where we end in the log area */
+	int		nflushblks;	/* num of flushed blocks */
+	struct ffs_transaction_entry *te;
+};
+
+struct ffs_transaction_entry {
+	daddr_t		baddrs[MAXBLOCKS];	/* addr of metadata blocks */
+	struct buf	*data[MAXBLOCKS];	/* modified metadata blocks */
+};
+
+/* On-disk data structures for a transaction */
+struct ffs_journal_entry {
+	blkcnt_t	nblks;		/* num of blocks in trans */
+	daddr_t		addr[MAXBLOCKS];	/* block addresses */
+	struct buf	*data[MAXBLOCKS];	/* modified blocks */
+};
+
+/*
+ * The log area of the journal (which is simply a file) stores a superblock
+ * at the beginning.
+ *
+ * => begin: marks the beginning of a run of transactions.
+ * => end: points to one past the end of the transactions in the log. New
+ *         transactions are added to the log area at this address.
+ */
+struct ffs_journal_sblock {
+	off_t 	begin;
+	off_t 	end;
+	int	flags; 			/* See flags below. XXX May be removed*/
+};
+
 #endif /* !_UFS_FFS_FS_H_ */
Index: sys/ufs/ufs/dinode.h
===================================================================
RCS file: /cvsroot/src/sys/ufs/ufs/dinode.h,v
retrieving revision 1.19
diff -u -r1.19 dinode.h
--- sys/ufs/ufs/dinode.h	11 Dec 2005 12:25:28 -0000	1.19
+++ sys/ufs/ufs/dinode.h	18 Jan 2007 10:00:24 -0000
@@ -64,6 +64,12 @@
  */
 #define	WINO	((ino_t)1)
 
+/* 
+ * XXX This should really be calculated by "newfs(8)"
+ * This is the default inode number for the journal file.
+ */
+#define JINO	((ino_t)4)
+
 /*
  * A dinode contains all the meta-data associated with a UFS file.
  * This structure defines the on-disk format of a dinode. Since
@@ -167,6 +173,7 @@
 #define	IFLNK		0120000		/* Symbolic link. */
 #define	IFSOCK		0140000		/* UNIX domain socket. */
 #define	IFWHT		0160000		/* Whiteout. */
+#define	IFJNL		0130000		/* Journal file. */
 
 /* Size of the on-disk inode. */
 #define	DINODE1_SIZE	(sizeof(struct ufs1_dinode))		/* 128 */