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 */