summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2005-09-05 22:14:33 +0000
committertegge <tegge@FreeBSD.org>2005-09-05 22:14:33 +0000
commitc6de1a745875dc3f71b0e969b4bc61caf81bdc77 (patch)
tree0363f876a7968a44ceb3000da000c528f5c86dfd /sys/ufs/ffs
parent9a432bff049ba902f912e16392a7224c8ba35bff (diff)
downloadFreeBSD-src-c6de1a745875dc3f71b0e969b4bc61caf81bdc77.zip
FreeBSD-src-c6de1a745875dc3f71b0e969b4bc61caf81bdc77.tar.gz
Retain generation count when writing zeroes instead of an inode to disk.
Don't free a struct inodedep if another process is allocating saved inode memory for the same struct inodedep in initiate_write_inodeblock_ufs[12](). Handle disappearing dependencies in softdep_disk_io_initiation(). Reviewed by: mckusick
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c46
1 files changed, 42 insertions, 4 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 9aa2313..3127150 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -2485,6 +2485,15 @@ check_inode_unwritten(inodedep)
TAILQ_FIRST(&inodedep->id_newextupdt) != NULL ||
inodedep->id_nlinkdelta != 0)
return (0);
+
+ /*
+ * Another process might be in initiate_write_inodeblock_ufs[12]
+ * trying to allocate memory without holding "Softdep Lock".
+ */
+ if ((inodedep->id_state & IOSTARTED) != 0 &&
+ inodedep->id_savedino1 == NULL)
+ return (0);
+
inodedep->id_state |= ALLCOMPLETE;
LIST_REMOVE(inodedep, id_deps);
inodedep->id_buf = NULL;
@@ -3512,6 +3521,21 @@ handle_workitem_freefile(freefile)
WORKITEM_FREE(freefile, D_FREEFILE);
}
+
+/*
+ * Helper function which unlinks marker element from work list and returns
+ * the next element on the list.
+ */
+static __inline struct worklist *
+markernext(struct worklist *marker)
+{
+ struct worklist *next;
+
+ next = LIST_NEXT(marker, wk_list);
+ LIST_REMOVE(marker, wk_list);
+ return next;
+}
+
/*
* Disk writes.
*
@@ -3538,7 +3562,8 @@ static void
softdep_disk_io_initiation(bp)
struct buf *bp; /* structure describing disk write to occur */
{
- struct worklist *wk, *nextwk;
+ struct worklist *wk;
+ struct worklist marker;
struct indirdep *indirdep;
struct inodedep *inodedep;
@@ -3548,11 +3573,17 @@ softdep_disk_io_initiation(bp)
*/
if (bp->b_iocmd != BIO_WRITE)
panic("softdep_disk_io_initiation: not write");
+
+ marker.wk_type = D_LAST + 1; /* Not a normal workitem */
+ PHOLD(curproc); /* Don't swap out kernel stack */
+
ACQUIRE_LOCK(&lk);
/*
* Do any necessary pre-I/O processing.
*/
- LIST_FOREACH_SAFE(wk, &bp->b_dep, wk_list, nextwk) {
+ for (wk = LIST_FIRST(&bp->b_dep); wk != NULL;
+ wk = markernext(&marker)) {
+ LIST_INSERT_AFTER(wk, &marker, wk_list);
switch (wk->wk_type) {
case D_PAGEDEP:
@@ -3617,6 +3648,7 @@ softdep_disk_io_initiation(bp)
}
}
FREE_LOCK(&lk);
+ PRELE(curproc); /* Allow swapout of kernel stack */
}
/*
@@ -3679,6 +3711,7 @@ initiate_write_inodeblock_ufs1(inodedep, bp)
{
struct allocdirect *adp, *lastadp;
struct ufs1_dinode *dp;
+ struct ufs1_dinode *sip;
struct fs *fs;
ufs_lbn_t i, prevlbn = 0;
int deplist;
@@ -3697,11 +3730,13 @@ initiate_write_inodeblock_ufs1(inodedep, bp)
if (inodedep->id_savedino1 != NULL)
panic("initiate_write_inodeblock_ufs1: I/O underway");
FREE_LOCK(&lk);
- MALLOC(inodedep->id_savedino1, struct ufs1_dinode *,
+ MALLOC(sip, struct ufs1_dinode *,
sizeof(struct ufs1_dinode), M_SAVEDINO, M_SOFTDEP_FLAGS);
ACQUIRE_LOCK(&lk);
+ inodedep->id_savedino1 = sip;
*inodedep->id_savedino1 = *dp;
bzero((caddr_t)dp, sizeof(struct ufs1_dinode));
+ dp->di_gen = inodedep->id_savedino1->di_gen;
return;
}
/*
@@ -3819,6 +3854,7 @@ initiate_write_inodeblock_ufs2(inodedep, bp)
{
struct allocdirect *adp, *lastadp;
struct ufs2_dinode *dp;
+ struct ufs2_dinode *sip;
struct fs *fs;
ufs_lbn_t i, prevlbn = 0;
int deplist;
@@ -3837,11 +3873,13 @@ initiate_write_inodeblock_ufs2(inodedep, bp)
if (inodedep->id_savedino2 != NULL)
panic("initiate_write_inodeblock_ufs2: I/O underway");
FREE_LOCK(&lk);
- MALLOC(inodedep->id_savedino2, struct ufs2_dinode *,
+ MALLOC(sip, struct ufs2_dinode *,
sizeof(struct ufs2_dinode), M_SAVEDINO, M_SOFTDEP_FLAGS);
ACQUIRE_LOCK(&lk);
+ inodedep->id_savedino2 = sip;
*inodedep->id_savedino2 = *dp;
bzero((caddr_t)dp, sizeof(struct ufs2_dinode));
+ dp->di_gen = inodedep->id_savedino2->di_gen;
return;
}
/*
OpenPOWER on IntegriCloud