summaryrefslogtreecommitdiffstats
path: root/sys/ufs
diff options
context:
space:
mode:
authormckusick <mckusick@FreeBSD.org>2003-02-24 07:28:41 +0000
committermckusick <mckusick@FreeBSD.org>2003-02-24 07:28:41 +0000
commit46e9534a1104c1180ef23cf7a272df465cdc02ba (patch)
tree6fa5f2d03d3a2092d13debc05d4c283f59ae8d43 /sys/ufs
parent63f02c8ddb42f5855fe686b4aa47dd43e6aa5069 (diff)
downloadFreeBSD-src-46e9534a1104c1180ef23cf7a272df465cdc02ba.zip
FreeBSD-src-46e9534a1104c1180ef23cf7a272df465cdc02ba.tar.gz
When removing the last item from a non-empty worklist, the worklist
tail pointer must be updated. Reported by: Kris Kennaway <kris@obsecurity.org> Sponsored by: DARPA & NAI Labs.
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_softdep.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 872433d..8d4b5de 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -495,6 +495,7 @@ workitem_free(item, type)
* Workitem queue management
*/
static struct workhead softdep_workitem_pending;
+static struct worklist *worklist_tail;
static int num_on_worklist; /* number of worklist items to be processed */
static int softdep_worklist_busy; /* 1 => trying to do unmount */
static int softdep_worklist_req; /* serialized waiters */
@@ -552,7 +553,6 @@ static void
add_to_worklist(wk)
struct worklist *wk;
{
- static struct worklist *worklist_tail;
if (wk->wk_state & ONWORKLIST) {
if (lk.lkt_held != NOHOLDER)
@@ -679,7 +679,7 @@ process_worklist_item(matchmnt, flags)
struct mount *matchmnt;
int flags;
{
- struct worklist *wk;
+ struct worklist *wk, *wkend;
struct mount *mp;
struct vnode *vp;
int matchcnt = 0;
@@ -717,7 +717,20 @@ process_worklist_item(matchmnt, flags)
FREE_LOCK(&lk);
return (-1);
}
+ /*
+ * Remove the item to be processed. If we are removing the last
+ * item on the list, we need to recalculate the tail pointer.
+ * As this happens rarely and usually when the list is short,
+ * we just run down the list to find it rather than tracking it
+ * in the above loop.
+ */
WORKLIST_REMOVE(wk);
+ if (wk == worklist_tail) {
+ LIST_FOREACH(wkend, &softdep_workitem_pending, wk_list)
+ if (LIST_NEXT(wkend, wk_list) == NULL)
+ break;
+ worklist_tail = wkend;
+ }
num_on_worklist -= 1;
FREE_LOCK(&lk);
switch (wk->wk_type) {
OpenPOWER on IntegriCloud