Hi,

Here is the first patch to bring Journaling to OpenBSD based on the McKusick 
paper: https://www.bsdcan.org/2010/schedule/attachments/141_suj-slides.pd and 
FreeBSD 10

This first patch is just for structures and definitions.

I know is my first patch suggestion and this feature is not usual, but I am 
fully focused on making it work, and I hope to receive help from expert 
developers.

Walter Neto

Index: sys/sys/mount.h
===================================================================
RCS file: /Volumes/CSP/cvs/src/sys/sys/mount.h,v
retrieving revision 1.121
diff -u -u -r1.121 mount.h
--- sys/sys/mount.h     8 Sep 2014 01:47:06 -0000       1.121
+++ sys/sys/mount.h     1 Sep 2015 20:23:03 -0000
@@ -413,6 +413,7 @@
 #define MNT_WANTRDWR   0x02000000      /* want upgrade to read/write */
 #define MNT_SOFTDEP     0x04000000      /* soft dependencies being done */
 #define MNT_DOOMED     0x08000000      /* device behind filesystem is gone */
+#define MNT_SUJ                0x10000000      /* using journaled soft updates 
*/
 
 /*
  * Flags for various system call interfaces.
Index: sys/ufs/ffs/softdep.h
===================================================================
RCS file: /Volumes/CSP/cvs/src/sys/ufs/ffs/softdep.h,v
retrieving revision 1.17
diff -u -u -r1.17 softdep.h
--- sys/ufs/ffs/softdep.h       11 Jun 2013 16:42:18 -0000      1.17
+++ sys/ufs/ffs/softdep.h       1 Sep 2015 20:23:03 -0000
@@ -165,6 +165,12 @@
 LIST_HEAD(allocindirhd, allocindir);
 LIST_HEAD(allocdirecthd, allocdirect);
 TAILQ_HEAD(allocdirectlst, allocdirect);
+LIST_HEAD(jaddrefhd, jaddref);
+LIST_HEAD(jremrefhd, jremref);
+LIST_HEAD(jmvrefhd, jmvref);
+LIST_HEAD(jnewblkhd, jnewblk);
+LIST_HEAD(jblkdephd, jblkdep);
+TAILQ_HEAD(jseglst, jseg);
 
 /*
  * The "pagedep" structure tracks the various dependencies related to
@@ -587,3 +593,246 @@
 #      define  db_state db_list.wk_state /* unused */
        struct  pagedep *db_pagedep;/* associated pagedep */
 };
+
+/*
+ * The inoref structure holds the elements common to jaddref and jremref
+ * so they may easily be queued in-order on the inodedep.
+ */
+struct inoref {
+       struct  worklist if_list;       /* Journal pending or jseg entries. */
+#      define  if_state if_list.wk_state
+       TAILQ_ENTRY(inoref) if_deps;    /* Links for inodedep. */
+       struct  jsegdep *if_jsegdep;    /* Will track our journal record. */
+       doff_t          if_diroff;      /* Directory offset. */
+       ufsino_t        if_ino;         /* Inode number. */
+       ufsino_t        if_parent;      /* Parent inode number. */
+       nlink_t         if_nlink;       /* nlink before addition. */
+       uint16_t        if_mode;        /* File mode, needed for IFMT. */
+};
+
+/*
+ * A "jaddref" structure tracks a new reference (link count) on an inode
+ * and prevents the link count increase and bitmap allocation until a
+ * journal entry can be written.  Once the journal entry is written,
+ * the inode is put on the pendinghd of the bmsafemap and a diradd or
+ * mkdir entry is placed on the bufwait list of the inode.  The DEPCOMPLETE
+ * flag is used to indicate that all of the required information for writing
+ * the journal entry is present.  MKDIR_BODY and MKDIR_PARENT are used to
+ * differentiate . and .. links from regular file names.  NEWBLOCK indicates
+ * a bitmap is still pending.  If a new reference is canceled by a delete
+ * prior to writing the journal the jaddref write is canceled and the
+ * structure persists to prevent any disk-visible changes until it is
+ * ultimately released when the file is freed or the link is dropped again.
+ */
+struct jaddref {
+       struct  inoref  ja_ref;         /* see inoref above. */
+#      define  ja_list ja_ref.if_list  /* Jrnl pending, id_inowait, dm_jwork.*/
+#      define  ja_state ja_ref.if_list.wk_state
+       LIST_ENTRY(jaddref) ja_bmdeps;  /* Links for bmsafemap. */
+       union {
+               struct  diradd  *jau_diradd;    /* Pending diradd. */
+               struct  mkdir   *jau_mkdir;     /* MKDIR_{PARENT,BODY} */
+       } ja_un;
+};
+#define        ja_diradd       ja_un.jau_diradd
+#define        ja_mkdir        ja_un.jau_mkdir
+#define        ja_diroff       ja_ref.if_diroff
+#define        ja_ino          ja_ref.if_ino
+#define        ja_parent       ja_ref.if_parent
+#define        ja_mode         ja_ref.if_mode
+
+/*
+ * A "jremref" structure tracks a removed reference (unlink) on an
+ * inode and prevents the directory remove from proceeding until the
+ * journal entry is written.  Once the journal has been written the remove
+ * may proceed as normal. 
+ */
+struct jremref {
+       struct  inoref  jr_ref;         /* see inoref above. */
+#      define  jr_list jr_ref.if_list  /* Linked to softdep_journal_pending. */
+#      define  jr_state jr_ref.if_list.wk_state
+       LIST_ENTRY(jremref) jr_deps;    /* Links for dirrem. */
+       struct  dirrem  *jr_dirrem;     /* Back pointer to dirrem. */
+};
+
+/*
+ * A "jmvref" structure tracks a name relocations within the same
+ * directory block that occur as a result of directory compaction.
+ * It prevents the updated directory entry from being written to disk
+ * until the journal entry is written. Once the journal has been
+ * written the compacted directory may be written to disk.
+ */
+struct jmvref {
+       struct  worklist jm_list;       /* Linked to softdep_journal_pending. */
+       LIST_ENTRY(jmvref) jm_deps;     /* Jmvref on pagedep. */
+       struct pagedep  *jm_pagedep;    /* Back pointer to pagedep. */
+       ufsino_t        jm_parent;      /* Containing directory inode number. */
+       ufsino_t        jm_ino;         /* Inode number of our entry. */
+       doff_t          jm_oldoff;      /* Our old offset in directory. */
+       doff_t          jm_newoff;      /* Our new offset in directory. */
+};
+
+/*
+ * A "jnewblk" structure tracks a newly allocated block or fragment and
+ * prevents the direct or indirect block pointer as well as the cg bitmap
+ * from being written until it is logged.  After it is logged the jsegdep
+ * is attached to the allocdirect or allocindir until the operation is
+ * completed or reverted.  If the operation is reverted prior to the journal
+ * write the jnewblk structure is maintained to prevent the bitmaps from
+ * reaching the disk.  Ultimately the jnewblk structure will be passed
+ * to the free routine as the in memory cg is modified back to the free
+ * state at which time it can be released. It may be held on any of the
+ * fx_jwork, fw_jwork, fb_jwork, ff_jwork, nb_jwork, or ir_jwork lists.
+ */
+struct jnewblk {
+       struct  worklist jn_list;       /* See lists above. */
+#      define  jn_state jn_list.wk_state
+       struct  jsegdep *jn_jsegdep;    /* Will track our journal record. */
+       LIST_ENTRY(jnewblk) jn_deps;    /* Jnewblks on sm_jnewblkhd. */
+       struct  worklist *jn_dep;       /* Dependency to ref completed seg. */
+       daddr_t         jn_lbn;         /* Lbn to which allocated. */
+       daddr_t         jn_blkno;       /* Blkno allocated */
+       ufsino_t        jn_ino;         /* Ino to which allocated. */
+       int             jn_oldfrags;    /* Previous fragments when extended. */
+       int             jn_frags;       /* Number of fragments. */
+};
+
+/*
+ * A "jblkdep" structure tracks jfreeblk and jtrunc records attached to a
+ * freeblks structure.
+ */
+struct jblkdep {
+       struct  worklist jb_list;       /* For softdep journal pending. */
+       struct  jsegdep *jb_jsegdep;    /* Reference to the jseg. */
+       struct  freeblks *jb_freeblks;  /* Back pointer to freeblks. */
+       LIST_ENTRY(jblkdep) jb_deps;    /* Dep list on freeblks. */
+
+};
+
+/*
+ * A "jfreeblk" structure tracks the journal write for freeing a block
+ * or tree of blocks.  The block pointer must not be cleared in the inode
+ * or indirect prior to the jfreeblk being written to the journal.
+ */
+struct jfreeblk {
+       struct  jblkdep jf_dep;         /* freeblks linkage. */
+       daddr_t         jf_lbn;         /* Lbn from which blocks freed. */
+       daddr_t         jf_blkno;       /* Blkno being freed. */
+       ufsino_t        jf_ino;         /* Ino from which blocks freed. */
+       int             jf_frags;       /* Number of frags being freed. */
+};
+
+/*
+ * A "jfreefrag" tracks the freeing of a single block when a fragment is
+ * extended or an indirect page is replaced.  It is not part of a larger
+ * freeblks operation.
+ */
+struct jfreefrag {
+       struct  worklist fr_list;       /* Linked to softdep_journal_pending. */
+#      define  fr_state fr_list.wk_state
+       struct  jsegdep *fr_jsegdep;    /* Will track our journal record. */
+       struct freefrag *fr_freefrag;   /* Back pointer to freefrag. */
+       daddr_t         fr_lbn;         /* Lbn from which frag freed. */
+       daddr_t         fr_blkno;       /* Blkno being freed. */
+       ufsino_t        fr_ino;         /* Ino from which frag freed. */
+       int             fr_frags;       /* Size of frag being freed. */
+};
+
+/*
+ * A "jtrunc" journals the intent to truncate an inode's data or extent area.
+ */
+struct jtrunc {
+       struct  jblkdep jt_dep;         /* freeblks linkage. */
+       off_t           jt_size;        /* Final file size. */
+       int             jt_extsize;     /* Final extent size. */
+       ufsino_t        jt_ino;         /* Ino being truncated. */
+};
+
+/*
+ * A "jfsync" journals the completion of an fsync which invalidates earlier
+ * jtrunc records in the journal.
+ */
+struct jfsync {
+       struct  worklist jfs_list;      /* For softdep journal pending. */
+       off_t           jfs_size;       /* Sync file size. */
+       int             jfs_extsize;    /* Sync extent size. */
+       ufsino_t        jfs_ino;        /* ino being synced. */
+};
+
+/*
+ * A "jsegdep" structure tracks a single reference to a written journal
+ * segment so the journal space can be reclaimed when all dependencies
+ * have been written. It can hang off of id_inowait, dm_jwork, da_jwork,
+ * nb_jwork, ff_jwork, or fb_jwork lists.
+ */
+struct jsegdep {
+       struct  worklist jd_list;       /* See above for lists. */
+#      define  jd_state jd_list.wk_state
+       struct  jseg    *jd_seg;        /* Our journal record. */
+};
+
+/*
+ * A "jseg" structure contains all of the journal records written in a
+ * single disk write.  The jaddref and jremref structures are linked into
+ * js_entries so thay may be completed when the write completes.  The
+ * js_entries also include the write dependency structures: jmvref,
+ * jnewblk, jfreeblk, jfreefrag, and jtrunc.  The js_refs field counts
+ * the number of entries on the js_entries list. Thus there is a single
+ * jseg entry to describe each journal write.
+ */
+struct jseg {
+       struct  worklist js_list;       /* b_deps link for journal */
+#      define  js_state js_list.wk_state
+       struct  workhead js_entries;    /* Entries awaiting write */
+       LIST_HEAD(, freework) js_indirs;/* List of indirects in this seg. */
+       TAILQ_ENTRY(jseg) js_next;      /* List of all unfinished segments. */
+       struct  jblocks *js_jblocks;    /* Back pointer to block/seg list */
+       struct  buf *js_buf;            /* Buffer while unwritten */
+       uint64_t js_seq;                /* Journal record sequence number. */
+       uint64_t js_oldseq;             /* Oldest valid sequence number. */
+       int     js_size;                /* Size of journal record in bytes. */
+       int     js_cnt;                 /* Total items allocated. */
+       int     js_refs;                /* Count of js_entries items. */
+};
+
+/*
+ * A 'sbdep' structure tracks the head of the free inode list and
+ * superblock writes.  This makes sure the superblock is always pointing at
+ * the first possible unlinked inode for the suj recovery process.  If a
+ * block write completes and we discover a new head is available the buf
+ * is dirtied and the dep is kept. See the description of the UNLINK*
+ * flags above for more details.
+ */
+struct sbdep {
+       struct  worklist sb_list;       /* b_dep linkage */
+       struct  fs      *sb_fs;         /* Filesystem pointer within buf. */
+       struct  ufsmount *sb_ump;       /* Our mount structure */
+};
+
+/*
+ * Private journaling structures.
+ */
+struct jblocks {
+       struct jseglst  jb_segs;        /* TAILQ of current segments. */
+       struct jseg     *jb_writeseg;   /* Next write to complete. */
+       struct jseg     *jb_oldestseg;  /* Oldest segment with valid entries. */
+       struct jextent  *jb_extent;     /* Extent array. */
+       uint64_t        jb_nextseq;     /* Next sequence number. */
+       uint64_t        jb_oldestwrseq; /* Oldest written sequence number. */
+       uint8_t         jb_needseg;     /* Need a forced segment. */
+       uint8_t         jb_suspended;   /* Did journal suspend writes? */
+       int             jb_avail;       /* Available extents. */
+       int             jb_used;        /* Last used extent. */
+       int             jb_head;        /* Allocator head. */
+       int             jb_off;         /* Allocator extent offset. */
+       int             jb_blocks;      /* Total disk blocks covered. */
+       int             jb_free;        /* Total disk blocks free. */
+       int             jb_min;         /* Minimum free space. */
+       int             jb_low;         /* Low on space. */
+       int             jb_age;         /* Insertion time of oldest rec. */
+};
+
+struct jextent {
+       daddr_t je_daddr;       /* Disk block address. */
+       int     je_blocks;      /* Disk block count. */
+};


Reply via email to