+/*
+ * 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 @@
#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 */