summaryrefslogtreecommitdiff
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
authorConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1998-08-29 00:02:52 +0000
committerConstantine Sapuntzakis <csapuntz@cvs.openbsd.org>1998-08-29 00:02:52 +0000
commitb5dff1689d8ea7ea96c3d63d15396191745985ae (patch)
treeb68682114201d0ac9bb19a284aff98d3e857965e /sys/ufs/ffs
parent5b07739fd599e083b91b99fa8ac605fa448954af (diff)
Integrate changes from Kirk McKusick
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c117
1 files changed, 74 insertions, 43 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 599e9743743..abf7f8d6944 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -52,7 +52,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)ffs_softdep.c 9.23 (McKusick) 2/20/98
+ * @(#)ffs_softdep.c 9.27 (McKusick) 6/12/98
*/
#ifdef FFS_SOFTUPDATES
@@ -2305,27 +2305,37 @@ newdirrem(bp, dp, ip, isrmdir)
if (pagedep_lookup(dp, lbn, DEPALLOC, &pagedep) == 0)
WORKLIST_INSERT(&bp->b_dep, &pagedep->pd_list);
dirrem->dm_pagedep = pagedep;
+ /*
+ * Check for a diradd dependency for the same directory entry.
+ * If present, then both dependencies become obsolete and can
+ * be de-allocated. Check for an entry on both the pd_dirraddhd
+ * list and the pd_pendinghd list.
+ */
for (dap = LIST_FIRST(&pagedep->pd_diraddhd[DIRADDHASH(offset)]);
- dap; dap = LIST_NEXT(dap, da_pdlist)) {
- /*
- * Check for a diradd dependency for the same directory entry.
- * If present, then both dependencies become obsolete and can
- * be de-allocated.
- */
- if (dap->da_offset != offset)
- continue;
- /*
- * Must be ATTACHED at this point, so just delete it.
- */
- if ((dap->da_state & ATTACHED) == 0)
- panic("newdirrem: not ATTACHED");
- if (dap->da_newinum != ip->i_number)
- panic("newdirrem: inum %d should be %d",
- ip->i_number, dap->da_newinum);
- free_diradd(dap);
- dirrem->dm_state |= COMPLETE;
- break;
+ dap; dap = LIST_NEXT(dap, da_pdlist))
+ if (dap->da_offset == offset)
+ break;
+
+ if (dap == NULL) {
+ for (dap = LIST_FIRST(&pagedep->pd_pendinghd);
+ dap; dap = LIST_NEXT(dap, da_pdlist))
+ if (dap->da_offset == offset)
+ break;
+ if (dap == NULL)
+ return (dirrem);
}
+
+ /*
+ * Must be ATTACHED at this point, so just delete it.
+ */
+ if ((dap->da_state & ATTACHED) == 0)
+ panic("newdirrem: not ATTACHED");
+ if (dap->da_newinum != ip->i_number)
+ panic("newdirrem: inum %d should be %d",
+ ip->i_number, dap->da_newinum);
+ free_diradd(dap);
+ dirrem->dm_state |= COMPLETE;
+
return (dirrem);
}
@@ -2357,16 +2367,15 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir)
int offset;
struct diradd *dap;
struct dirrem *dirrem;
+ struct pagedep *pagedep;
struct inodedep *inodedep;
offset = blkoff(dp->i_fs, dp->i_offset);
/*
- * Whiteouts have no addition dependencies.
+ * Whiteouts do not need addition dependencies.
*/
- if (newinum == WINO) {
- dap = NULL;
- } else {
+ if (newinum != WINO) {
MALLOC(dap, struct diradd *, sizeof(struct diradd),
M_DIRADD, M_WAITOK);
bzero(dap, sizeof(struct diradd));
@@ -2377,34 +2386,56 @@ softdep_setup_directory_change(bp, dp, ip, newinum, isrmdir)
}
/*
- * Allocate a new dirrem if appropriate and ACQUIRE_LOCK.
+ * Allocate a new dirrem and ACQUIRE_LOCK.
*/
dirrem = newdirrem(bp, dp, ip, isrmdir);
+ pagedep = dirrem->dm_pagedep;
/*
- * If the inode has already been written, then no addition
- * dependency needs to be created.
+ * Whiteouts have no additional dependencies,
+ * so just put the dirrem on the correct list.
*/
- if (inodedep_lookup(dp->i_fs, newinum, 0, &inodedep) == 0 ||
- (inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) {
- WORKITEM_FREE(dap, D_DIRADD);
- dap = NULL;
- }
+ if (newinum == WINO) {
+ if ((dirrem->dm_state & COMPLETE) == 0) {
+ LIST_INSERT_HEAD(&pagedep->pd_dirremhd, dirrem,
+ dm_next);
+ } else {
+ dirrem->dm_dirinum = pagedep->pd_ino;
+ add_to_worklist(&dirrem->dm_list);
+ }
+ FREE_LOCK(&lk);
+ return;
+ }
- if (dap) {
- dap->da_previous = dirrem;
- LIST_INSERT_HEAD(
- &dirrem->dm_pagedep->pd_diraddhd[DIRADDHASH(offset)],
+ /*
+ * Link into its inodedep. Put it on the id_bufwait list if the inode
+ * is not yet written. If it is written, do the post-inode write
+ * processing to put it on the id_pendinghd list.
+ */
+ dap->da_previous = dirrem;
+ if (inodedep_lookup(dp->i_fs, newinum, DEPALLOC, &inodedep) == 0 ||
+ (inodedep->id_state & ALLCOMPLETE) == ALLCOMPLETE) {
+ dap->da_state |= COMPLETE;
+ LIST_INSERT_HEAD(&pagedep->pd_pendinghd, dap, da_pdlist);
+ WORKLIST_INSERT(&inodedep->id_pendinghd, &dap->da_list);
+ } else {
+ LIST_INSERT_HEAD(&pagedep->pd_diraddhd[DIRADDHASH(offset)],
dap, da_pdlist);
WORKLIST_INSERT(&inodedep->id_bufwait, &dap->da_list);
- } else if ((dirrem->dm_state & COMPLETE) == 0) {
- LIST_INSERT_HEAD(&dirrem->dm_pagedep->pd_dirremhd, dirrem,
- dm_next);
- } else {
- dirrem->dm_dirinum = dirrem->dm_pagedep->pd_ino;
- add_to_worklist(&dirrem->dm_list);
}
- FREE_LOCK(&lk);
+ /*
+ * If the previous inode was never written or its previous directory
+ * entry was never written, then we do not want to roll back to this
+ * previous value. Instead we want to roll back to zero and immediately
+ * free the unwritten or unreferenced inode.
+ */
+ if (dirrem->dm_state & COMPLETE) {
+ dap->da_state &= ~DIRCHG;
+ dap->da_pagedep = pagedep;
+ dirrem->dm_dirinum = pagedep->pd_ino;
+ add_to_worklist(&dirrem->dm_list);
+ }
+ FREE_LOCK(&lk);
}
/*