summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs/softdep.h
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ufs/ffs/softdep.h')
-rw-r--r--sys/ufs/ffs/softdep.h446
1 files changed, 367 insertions, 79 deletions
diff --git a/sys/ufs/ffs/softdep.h b/sys/ufs/ffs/softdep.h
index b00183b..5d8a869 100644
--- a/sys/ufs/ffs/softdep.h
+++ b/sys/ufs/ffs/softdep.h
@@ -94,22 +94,29 @@
* The ONWORKLIST flag shows whether the structure is currently linked
* onto a worklist.
*/
-#define ATTACHED 0x0001
-#define UNDONE 0x0002
-#define COMPLETE 0x0004
-#define DEPCOMPLETE 0x0008
-#define MKDIR_PARENT 0x0010 /* diradd & mkdir only */
-#define MKDIR_BODY 0x0020 /* diradd & mkdir only */
-#define RMDIR 0x0040 /* dirrem only */
-#define DIRCHG 0x0080 /* diradd & dirrem only */
-#define GOINGAWAY 0x0100 /* indirdep only */
-#define IOSTARTED 0x0200 /* inodedep & pagedep only */
-#define SPACECOUNTED 0x0400 /* inodedep only */
-#define NEWBLOCK 0x0800 /* pagedep only */
-#define INPROGRESS 0x1000 /* dirrem, freeblks, freefrag, freefile only */
-#define UFS1FMT 0x2000 /* indirdep only */
-#define EXTDATA 0x4000 /* allocdirect only */
-#define ONWORKLIST 0x8000
+#define ATTACHED 0x000001
+#define UNDONE 0x000002
+#define COMPLETE 0x000004
+#define DEPCOMPLETE 0x000008
+#define MKDIR_PARENT 0x000010 /* diradd, mkdir, jaddref, jsegdep only */
+#define MKDIR_BODY 0x000020 /* diradd, mkdir, jaddref only */
+#define RMDIR 0x000040 /* dirrem only */
+#define DIRCHG 0x000080 /* diradd, dirrem only */
+#define GOINGAWAY 0x000100 /* indirdep, jremref only */
+#define IOSTARTED 0x000200 /* inodedep, pagedep, bmsafemap only */
+#define SPACECOUNTED 0x000400 /* inodedep only */
+#define NEWBLOCK 0x000800 /* pagedep, jaddref only */
+#define INPROGRESS 0x001000 /* dirrem, freeblks, freefrag, freefile only */
+#define UFS1FMT 0x002000 /* indirdep only */
+#define EXTDATA 0x004000 /* allocdirect only */
+#define ONWORKLIST 0x008000
+#define IOWAITING 0x010000 /* Thread is waiting for IO to complete. */
+#define ONDEPLIST 0x020000 /* Structure is on a dependency list. */
+#define UNLINKED 0x040000 /* inodedep has been unlinked. */
+#define UNLINKNEXT 0x080000 /* inodedep has valid di_freelink */
+#define UNLINKPREV 0x100000 /* inodedep is pointed at in the unlink list */
+#define UNLINKONLIST 0x200000 /* inodedep is in the unlinked list on disk */
+#define UNLINKLINKS (UNLINKNEXT | UNLINKPREV)
#define ALLCOMPLETE (ATTACHED | COMPLETE | DEPCOMPLETE)
@@ -135,25 +142,38 @@
* and the macros below changed to use it.
*/
struct worklist {
- struct mount *wk_mp; /* Mount we live in */
LIST_ENTRY(worklist) wk_list; /* list of work requests */
- unsigned short wk_type; /* type of request */
- unsigned short wk_state; /* state flags */
+ struct mount *wk_mp; /* Mount we live in */
+ unsigned int wk_type:8, /* type of request */
+ wk_state:24; /* state flags */
};
#define WK_DATA(wk) ((void *)(wk))
#define WK_PAGEDEP(wk) ((struct pagedep *)(wk))
#define WK_INODEDEP(wk) ((struct inodedep *)(wk))
#define WK_BMSAFEMAP(wk) ((struct bmsafemap *)(wk))
+#define WK_NEWBLK(wk) ((struct newblk *)(wk))
#define WK_ALLOCDIRECT(wk) ((struct allocdirect *)(wk))
#define WK_INDIRDEP(wk) ((struct indirdep *)(wk))
#define WK_ALLOCINDIR(wk) ((struct allocindir *)(wk))
#define WK_FREEFRAG(wk) ((struct freefrag *)(wk))
#define WK_FREEBLKS(wk) ((struct freeblks *)(wk))
+#define WK_FREEWORK(wk) ((struct freework *)(wk))
#define WK_FREEFILE(wk) ((struct freefile *)(wk))
#define WK_DIRADD(wk) ((struct diradd *)(wk))
#define WK_MKDIR(wk) ((struct mkdir *)(wk))
#define WK_DIRREM(wk) ((struct dirrem *)(wk))
#define WK_NEWDIRBLK(wk) ((struct newdirblk *)(wk))
+#define WK_JADDREF(wk) ((struct jaddref *)(wk))
+#define WK_JREMREF(wk) ((struct jremref *)(wk))
+#define WK_JMVREF(wk) ((struct jmvref *)(wk))
+#define WK_JSEGDEP(wk) ((struct jsegdep *)(wk))
+#define WK_JSEG(wk) ((struct jseg *)(wk))
+#define WK_JNEWBLK(wk) ((struct jnewblk *)(wk))
+#define WK_JFREEBLK(wk) ((struct jfreeblk *)(wk))
+#define WK_FREEDEP(wk) ((struct freedep *)(wk))
+#define WK_JFREEFRAG(wk) ((struct jfreefrag *)(wk))
+#define WK_SBDEP(wk) ((struct sbdep *)wk)
+#define WK_JTRUNC(wk) ((struct jtrunc *)(wk))
/*
* Various types of lists
@@ -165,6 +185,15 @@ LIST_HEAD(inodedephd, inodedep);
LIST_HEAD(allocindirhd, allocindir);
LIST_HEAD(allocdirecthd, allocdirect);
TAILQ_HEAD(allocdirectlst, allocdirect);
+LIST_HEAD(indirdephd, indirdep);
+LIST_HEAD(jaddrefhd, jaddref);
+LIST_HEAD(jremrefhd, jremref);
+LIST_HEAD(jmvrefhd, jmvref);
+LIST_HEAD(jnewblkhd, jnewblk);
+LIST_HEAD(jfreeblkhd, jfreeblk);
+LIST_HEAD(freeworkhd, freework);
+TAILQ_HEAD(jseglst, jseg);
+TAILQ_HEAD(inoreflst, inoref);
/*
* The "pagedep" structure tracks the various dependencies related to
@@ -192,9 +221,11 @@ struct pagedep {
LIST_ENTRY(pagedep) pd_hash; /* hashed lookup */
ino_t pd_ino; /* associated file */
ufs_lbn_t pd_lbn; /* block within file */
+ struct newdirblk *pd_newdirblk; /* associated newdirblk if NEWBLOCK */
struct dirremhd pd_dirremhd; /* dirrem's waiting for page */
struct diraddhd pd_diraddhd[DAHASHSZ]; /* diradd dir entry updates */
struct diraddhd pd_pendinghd; /* directory entries awaiting write */
+ struct jmvrefhd pd_jmvrefhd; /* Dependent journal writes. */
};
/*
@@ -248,13 +279,18 @@ struct inodedep {
struct worklist id_list; /* buffer holding inode block */
# define id_state id_list.wk_state /* inode dependency state */
LIST_ENTRY(inodedep) id_hash; /* hashed lookup */
+ TAILQ_ENTRY(inodedep) id_unlinked; /* Unlinked but ref'd inodes */
struct fs *id_fs; /* associated filesystem */
ino_t id_ino; /* dependent inode */
nlink_t id_nlinkdelta; /* saved effective link count */
+ nlink_t id_savednlink; /* Link saved during rollback */
LIST_ENTRY(inodedep) id_deps; /* bmsafemap's list of inodedep's */
- struct buf *id_buf; /* related bmsafemap (if pending) */
+ struct bmsafemap *id_bmsafemap; /* related bmsafemap (if pending) */
+ struct diradd *id_mkdiradd; /* diradd for a mkdir. */
+ struct inoreflst id_inoreflst; /* Inode reference adjustments. */
long id_savedextsize; /* ext size saved during rollback */
off_t id_savedsize; /* file size saved during rollback */
+ struct dirremhd id_dirremhd; /* Removals pending. */
struct workhead id_pendinghd; /* entries awaiting directory write */
struct workhead id_bufwait; /* operations after inode written */
struct workhead id_inowait; /* operations waiting inode update */
@@ -271,23 +307,6 @@ struct inodedep {
#define id_savedino2 id_un.idu_savedino2
/*
- * A "newblk" structure is attached to a bmsafemap structure when a block
- * or fragment is allocated from a cylinder group. Its state is set to
- * DEPCOMPLETE when its cylinder group map is written. It is consumed by
- * an associated allocdirect or allocindir allocation which will attach
- * themselves to the bmsafemap structure if the newblk's DEPCOMPLETE flag
- * is not set (i.e., its cylinder group map has not been written).
- */
-struct newblk {
- LIST_ENTRY(newblk) nb_hash; /* hashed lookup */
- struct fs *nb_fs; /* associated filesystem */
- int nb_state; /* state of bitmap dependency */
- ufs2_daddr_t nb_newblkno; /* allocated block number */
- LIST_ENTRY(newblk) nb_deps; /* bmsafemap's list of newblk's */
- struct bmsafemap *nb_bmsafemap; /* associated bmsafemap */
-};
-
-/*
* A "bmsafemap" structure maintains a list of dependency structures
* that depend on the update of a particular cylinder group map.
* It has lists for newblks, allocdirects, allocindirs, and inodedeps.
@@ -299,11 +318,41 @@ struct newblk {
*/
struct bmsafemap {
struct worklist sm_list; /* cylgrp buffer */
+# define sm_state sm_list.wk_state
+ int sm_cg;
+ LIST_ENTRY(bmsafemap) sm_hash; /* Hash links. */
struct buf *sm_buf; /* associated buffer */
struct allocdirecthd sm_allocdirecthd; /* allocdirect deps */
+ struct allocdirecthd sm_allocdirectwr; /* writing allocdirect deps */
struct allocindirhd sm_allocindirhd; /* allocindir deps */
+ struct allocindirhd sm_allocindirwr; /* writing allocindir deps */
struct inodedephd sm_inodedephd; /* inodedep deps */
+ struct inodedephd sm_inodedepwr; /* writing inodedep deps */
struct newblkhd sm_newblkhd; /* newblk deps */
+ struct newblkhd sm_newblkwr; /* writing newblk deps */
+ struct jaddrefhd sm_jaddrefhd; /* Pending inode allocations. */
+ struct jnewblkhd sm_jnewblkhd; /* Pending block allocations. */
+};
+
+/*
+ * A "newblk" structure is attached to a bmsafemap structure when a block
+ * or fragment is allocated from a cylinder group. Its state is set to
+ * DEPCOMPLETE when its cylinder group map is written. It is converted to
+ * an allocdirect or allocindir allocation once the allocator calls the
+ * appropriate setup function.
+ */
+struct newblk {
+ struct worklist nb_list;
+# define nb_state nb_list.wk_state
+ LIST_ENTRY(newblk) nb_hash; /* hashed lookup */
+ LIST_ENTRY(newblk) nb_deps; /* bmsafemap's list of newblks */
+ struct jnewblk *nb_jnewblk; /* New block journal entry. */
+ struct bmsafemap *nb_bmsafemap;/* cylgrp dep (if pending) */
+ struct freefrag *nb_freefrag; /* fragment to be freed (if any) */
+ struct indirdephd nb_indirdeps; /* Children indirect blocks. */
+ struct workhead nb_newdirblk; /* dir block to notify when written */
+ struct workhead nb_jwork; /* Journal work pending. */
+ ufs2_daddr_t nb_newblkno; /* new value of block pointer */
};
/*
@@ -334,20 +383,18 @@ struct bmsafemap {
* and inodedep->id_pendinghd lists.
*/
struct allocdirect {
- struct worklist ad_list; /* buffer holding block */
-# define ad_state ad_list.wk_state /* block pointer state */
+ struct newblk ad_block; /* Common block logic */
+# define ad_state ad_block.nb_list.wk_state /* block pointer state */
TAILQ_ENTRY(allocdirect) ad_next; /* inodedep's list of allocdirect's */
- ufs_lbn_t ad_lbn; /* block within file */
- ufs2_daddr_t ad_newblkno; /* new value of block pointer */
- ufs2_daddr_t ad_oldblkno; /* old value of block pointer */
- long ad_newsize; /* size of new block */
- long ad_oldsize; /* size of old block */
- LIST_ENTRY(allocdirect) ad_deps; /* bmsafemap's list of allocdirect's */
- struct buf *ad_buf; /* cylgrp buffer (if pending) */
struct inodedep *ad_inodedep; /* associated inodedep */
- struct freefrag *ad_freefrag; /* fragment to be freed (if any) */
- struct workhead ad_newdirblk; /* dir block to notify when written */
+ ufs2_daddr_t ad_oldblkno; /* old value of block pointer */
+ int ad_offset; /* Pointer offset in parent. */
+ long ad_newsize; /* size of new block */
+ long ad_oldsize; /* size of old block */
};
+#define ad_newblkno ad_block.nb_newblkno
+#define ad_freefrag ad_block.nb_freefrag
+#define ad_newdirblk ad_block.nb_newdirblk
/*
* A single "indirdep" structure manages all allocation dependencies for
@@ -369,10 +416,14 @@ struct allocdirect {
struct indirdep {
struct worklist ir_list; /* buffer holding indirect block */
# define ir_state ir_list.wk_state /* indirect block pointer state */
- caddr_t ir_saveddata; /* buffer cache contents */
+ LIST_ENTRY(indirdep) ir_next; /* alloc{direct,indir} list */
+ caddr_t ir_saveddata; /* buffer cache contents */
struct buf *ir_savebp; /* buffer holding safe copy */
+ struct allocindirhd ir_completehd; /* waiting for indirdep complete */
+ struct allocindirhd ir_writehd; /* Waiting for the pointer write. */
struct allocindirhd ir_donehd; /* done waiting to update safecopy */
struct allocindirhd ir_deplisthd; /* allocindir deps for this block */
+ struct workhead ir_jwork; /* Journal work pending. */
};
/*
@@ -389,16 +440,25 @@ struct indirdep {
* can then be freed as it is no longer applicable.
*/
struct allocindir {
- struct worklist ai_list; /* buffer holding indirect block */
-# define ai_state ai_list.wk_state /* indirect block pointer state */
+ struct newblk ai_block; /* Common block area */
+# define ai_state ai_block.nb_list.wk_state /* indirect pointer state */
LIST_ENTRY(allocindir) ai_next; /* indirdep's list of allocindir's */
- int ai_offset; /* pointer offset in indirect block */
- ufs2_daddr_t ai_newblkno; /* new block pointer value */
- ufs2_daddr_t ai_oldblkno; /* old block pointer value */
- struct freefrag *ai_freefrag; /* block to be freed when complete */
struct indirdep *ai_indirdep; /* address of associated indirdep */
- LIST_ENTRY(allocindir) ai_deps; /* bmsafemap's list of allocindir's */
- struct buf *ai_buf; /* cylgrp buffer (if pending) */
+ ufs2_daddr_t ai_oldblkno; /* old value of block pointer */
+ int ai_offset; /* Pointer offset in parent. */
+};
+#define ai_newblkno ai_block.nb_newblkno
+#define ai_freefrag ai_block.nb_freefrag
+#define ai_newdirblk ai_block.nb_newdirblk
+
+/*
+ * The allblk union is used to size the newblk structure on allocation so
+ * that it may be any one of three types.
+ */
+union allblk {
+ struct allocindir ab_allocindir;
+ struct allocdirect ab_allocdirect;
+ struct newblk ab_newblk;
};
/*
@@ -406,14 +466,13 @@ struct allocindir {
* allocated fragment is replaced with a larger fragment, rather than extended.
* The "freefrag" structure is constructed and attached when the replacement
* block is first allocated. It is processed after the inode claiming the
- * bigger block that replaces it has been written to disk. Note that the
- * ff_state field is is used to store the uid, so may lose data. However,
- * the uid is used only in printing an error message, so is not critical.
- * Keeping it in a short keeps the data structure down to 32 bytes.
+ * bigger block that replaces it has been written to disk.
*/
struct freefrag {
struct worklist ff_list; /* id_inowait or delayed worklist */
-# define ff_state ff_list.wk_state /* owning user; should be uid_t */
+# define ff_state ff_list.wk_state
+ struct jfreefrag *ff_jfreefrag; /* Associated journal entry. */
+ struct workhead ff_jwork; /* Journal work pending. */
ufs2_daddr_t ff_blkno; /* fragment physical block number */
long ff_fragsize; /* size of fragment being deleted */
ino_t ff_inum; /* owning inode number */
@@ -423,20 +482,57 @@ struct freefrag {
* A "freeblks" structure is attached to an "inodedep" when the
* corresponding file's length is reduced to zero. It records all
* the information needed to free the blocks of a file after its
- * zero'ed inode has been written to disk.
+ * zero'ed inode has been written to disk. The actual work is done
+ * by child freework structures which are responsible for individual
+ * inode pointers while freeblks is responsible for retiring the
+ * entire operation when it is complete and holding common members.
*/
struct freeblks {
struct worklist fb_list; /* id_inowait or delayed worklist */
# define fb_state fb_list.wk_state /* inode and dirty block state */
+ struct jfreeblkhd fb_jfreeblkhd; /* Journal entries pending */
+ struct workhead fb_freeworkhd; /* Work items pending */
+ struct workhead fb_jwork; /* Journal work pending */
ino_t fb_previousinum; /* inode of previous owner of blocks */
uid_t fb_uid; /* uid of previous owner of blocks */
struct vnode *fb_devvp; /* filesystem device vnode */
- long fb_oldextsize; /* previous ext data size */
- off_t fb_oldsize; /* previous file size */
ufs2_daddr_t fb_chkcnt; /* used to check cnt of blks released */
- ufs2_daddr_t fb_dblks[NDADDR]; /* direct blk ptrs to deallocate */
- ufs2_daddr_t fb_iblks[NIADDR]; /* indirect blk ptrs to deallocate */
- ufs2_daddr_t fb_eblks[NXADDR]; /* indirect blk ptrs to deallocate */
+ int fb_ref; /* Children outstanding. */
+};
+
+/*
+ * A "freework" structure handles the release of a tree of blocks or a single
+ * block. Each indirect block in a tree is allocated its own freework
+ * structure so that the indrect block may be freed only when all of its
+ * children are freed. In this way we enforce the rule that an allocated
+ * block must have a valid path to a root that is journaled. Each child
+ * block acquires a reference and when the ref hits zero the parent ref
+ * is decremented. If there is no parent the freeblks ref is decremented.
+ */
+struct freework {
+ struct worklist fw_list;
+# define fw_state fw_list.wk_state
+ LIST_ENTRY(freework) fw_next; /* Queue for freeblksk. */
+ struct freeblks *fw_freeblks; /* Root of operation. */
+ struct freework *fw_parent; /* Parent indirect. */
+ ufs2_daddr_t fw_blkno; /* Our block #. */
+ ufs_lbn_t fw_lbn; /* Original lbn before free. */
+ int fw_frags; /* Number of frags. */
+ int fw_ref; /* Number of children out. */
+ int fw_off; /* Current working position. */
+ struct workhead fw_jwork; /* Journal work pending. */
+};
+
+/*
+ * A "freedep" structure is allocated to track the completion of a bitmap
+ * write for a freework. One freedep may cover many freed blocks so long
+ * as they reside in the same cylinder group. When the cg is written
+ * the freedep decrements the ref on the freework which may permit it
+ * to be freed as well.
+ */
+struct freedep {
+ struct worklist fd_list;
+ struct freework *fd_freework; /* Parent freework. */
};
/*
@@ -450,6 +546,7 @@ struct freefile {
mode_t fx_mode; /* mode of inode */
ino_t fx_oldinum; /* inum of the unlinked file */
struct vnode *fx_devvp; /* filesystem device vnode */
+ struct workhead fx_jwork; /* journal work pending. */
};
/*
@@ -482,12 +579,11 @@ struct freefile {
* than zero.
*
* The overlaying of da_pagedep and da_previous is done to keep the
- * structure down to 32 bytes in size on a 32-bit machine. If a
- * da_previous entry is present, the pointer to its pagedep is available
- * in the associated dirrem entry. If the DIRCHG flag is set, the
- * da_previous entry is valid; if not set the da_pagedep entry is valid.
- * The DIRCHG flag never changes; it is set when the structure is created
- * if appropriate and is never cleared.
+ * structure down. If a da_previous entry is present, the pointer to its
+ * pagedep is available in the associated dirrem entry. If the DIRCHG flag
+ * is set, the da_previous entry is valid; if not set the da_pagedep entry
+ * is valid. The DIRCHG flag never changes; it is set when the structure
+ * is created if appropriate and is never cleared.
*/
struct diradd {
struct worklist da_list; /* id_inowait or id_pendinghd list */
@@ -499,6 +595,7 @@ struct diradd {
struct dirrem *dau_previous; /* entry being replaced in dir change */
struct pagedep *dau_pagedep; /* pagedep dependency for addition */
} da_un;
+ struct workhead da_jwork; /* Journal work awaiting completion. */
};
#define da_previous da_un.dau_previous
#define da_pagedep da_un.dau_pagedep
@@ -525,12 +622,13 @@ struct diradd {
* mkdir structures that reference it. The deletion would be faster if the
* diradd structure were simply augmented to have two pointers that referenced
* the associated mkdir's. However, this would increase the size of the diradd
- * structure from 32 to 64-bits to speed a very infrequent operation.
+ * structure to speed a very infrequent operation.
*/
struct mkdir {
struct worklist md_list; /* id_inowait or buffer holding dir */
# define md_state md_list.wk_state /* type: MKDIR_PARENT or MKDIR_BODY */
struct diradd *md_diradd; /* associated diradd */
+ struct jaddref *md_jaddref; /* dependent jaddref. */
struct buf *md_buf; /* MKDIR_BODY: buffer holding dir */
LIST_ENTRY(mkdir) md_mkdirs; /* list of all mkdirs */
};
@@ -542,20 +640,19 @@ LIST_HEAD(mkdirlist, mkdir) mkdirlisthd;
* list of the pagedep for the directory page that contains the entry.
* It is processed after the directory page with the deleted entry has
* been written to disk.
- *
- * The overlaying of dm_pagedep and dm_dirinum is done to keep the
- * structure down to 32 bytes in size on a 32-bit machine. It works
- * because they are never used concurrently.
*/
struct dirrem {
struct worklist dm_list; /* delayed worklist */
# define dm_state dm_list.wk_state /* state of the old directory entry */
LIST_ENTRY(dirrem) dm_next; /* pagedep's list of dirrem's */
+ LIST_ENTRY(dirrem) dm_inonext; /* inodedep's list of dirrem's */
+ struct jremrefhd dm_jremrefhd; /* Pending remove reference deps. */
ino_t dm_oldinum; /* inum of the removed dir entry */
union {
struct pagedep *dmu_pagedep; /* pagedep dependency for remove */
ino_t dmu_dirinum; /* parent inode number (for rmdir) */
} dm_un;
+ struct workhead dm_jwork; /* Journal work awaiting completion. */
};
#define dm_pagedep dm_un.dmu_pagedep
#define dm_dirinum dm_un.dmu_dirinum
@@ -577,9 +674,200 @@ struct dirrem {
* blocks using a similar scheme with the allocindir structures. Rather
* than adding this level of complexity, we simply write those newly
* allocated indirect blocks synchronously as such allocations are rare.
+ * In the case of a new directory the . and .. links are tracked with
+ * a mkdir rather than a pagedep. In this case we track the mkdir
+ * so it can be released when it is written. A workhead is used
+ * to simplify canceling a mkdir that is removed by a subsequent dirrem.
*/
struct newdirblk {
struct worklist db_list; /* id_inowait or pg_newdirblk */
# define db_state db_list.wk_state /* unused */
struct pagedep *db_pagedep; /* associated pagedep */
+ struct workhead db_mkdir;
+};
+
+/*
+ * 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;
+# define if_state if_list.wk_state
+ TAILQ_ENTRY(inoref) if_deps; /* Links for inodedep. */
+ struct jsegdep *if_jsegdep;
+ off_t if_diroff; /* Directory offset. */
+ ino_t if_ino; /* Inode number. */
+ ino_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;
+# define ja_list ja_ref.if_list /* Journal pending or jseg entries. */
+# 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;
+# define jr_list jr_ref.if_list /* Journal pending or jseg entries. */
+# define jr_state jr_ref.if_list.wk_state
+ LIST_ENTRY(jremref) jr_deps; /* Links for pagdep. */
+ struct dirrem *jr_dirrem; /* Back pointer to dirrem. */
+};
+
+struct jmvref {
+ struct worklist jm_list;
+ LIST_ENTRY(jmvref) jm_deps;
+ struct pagedep *jm_pagedep;
+ ino_t jm_parent;
+ ino_t jm_ino;
+ off_t jm_oldoff;
+ off_t jm_newoff;
+};
+
+/*
+ * 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.
+ */
+struct jnewblk {
+ struct worklist jn_list;
+# define jn_state jn_list.wk_state
+ struct jsegdep *jn_jsegdep;
+ LIST_ENTRY(jnewblk) jn_deps; /* All jnewblks on bmsafemap */
+ struct newblk *jn_newblk;
+ ino_t jn_ino;
+ ufs_lbn_t jn_lbn;
+ ufs2_daddr_t jn_blkno;
+ int jn_oldfrags;
+ int jn_frags;
+};
+
+/*
+ * 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.
+ */
+struct jfreeblk {
+ struct worklist jf_list;
+# define jf_state jf_list.wk_state
+ struct jsegdep *jf_jsegdep;
+ struct freeblks *jf_freeblks;
+ LIST_ENTRY(jfreeblk) jf_deps;
+ ino_t jf_ino;
+ ufs_lbn_t jf_lbn;
+ ufs2_daddr_t jf_blkno;
+ int jf_frags;
+};
+
+/*
+ * 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;
+# define fr_state fr_list.wk_state
+ struct jsegdep *fr_jsegdep;
+ struct freefrag *fr_freefrag;
+ ino_t fr_ino;
+ ufs_lbn_t fr_lbn;
+ ufs2_daddr_t fr_blkno;
+ int fr_frags;
+};
+
+/*
+ * A "jtrunc" journals the intent to truncate an inode to a non-zero
+ * value. This is done synchronously prior to the synchronous partial
+ * truncation process. The jsegdep is not released until the truncation
+ * is complete and the truncated inode is fsync'd.
+ */
+struct jtrunc {
+ struct worklist jt_list;
+ struct jsegdep *jt_jsegdep;
+ ino_t jt_ino;
+ off_t jt_size;
+ int jt_extsize;
+};
+
+/*
+ * 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.
+ */
+struct jsegdep {
+ struct worklist jd_list;
+# define jd_state jd_list.wk_state
+ struct jseg *jd_seg;
+};
+
+/*
+ * A "jseg" structure contains all of the journal records written in a
+ * single disk write. jaddref and jremref structures are linked into
+ * js_entries so thay may be completed when the write completes. The
+ * js_deps array contains as many entries as there are ref counts to
+ * reduce the number of allocations required per journal write to one.
+ */
+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 */
+ TAILQ_ENTRY(jseg) js_next;
+ struct jblocks *js_jblocks; /* Back pointer to block/seg list */
+ struct buf *js_buf; /* Buffer while unwritten */
+ uint64_t js_seq;
+ int js_size; /* Allocated size in bytes */
+ int js_cnt; /* Total items allocated */
+ int js_refs; /* Count of items pending completion */
+};
+
+/*
+ * 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.
+ */
+struct sbdep {
+ struct worklist sb_list; /* b_dep linkage */
+ struct fs *sb_fs; /* Filesystem pointer within buf. */
+ struct ufsmount *sb_ump;
};
OpenPOWER on IntegriCloud