diff options
author | mckusick <mckusick@FreeBSD.org> | 2003-02-24 07:28:41 +0000 |
---|---|---|
committer | mckusick <mckusick@FreeBSD.org> | 2003-02-24 07:28:41 +0000 |
commit | 46e9534a1104c1180ef23cf7a272df465cdc02ba (patch) | |
tree | 6fa5f2d03d3a2092d13debc05d4c283f59ae8d43 /sys/ufs | |
parent | 63f02c8ddb42f5855fe686b4aa47dd43e6aa5069 (diff) | |
download | FreeBSD-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.c | 17 |
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) { |