summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2020-03-09 16:49:13 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2020-03-09 16:49:13 +0000
commit84a19adafcee9b72538c9922fe560ca993619f6e (patch)
treeba5049ce06c5db3f6614beda50d0198db14387f5
parent8809a3d0d3a00b23e7e68438809b3e4561b02dfd (diff)
Avoid a tight CPU loop when no unlocked worklist items can be processed.
If process_worklist_item() is unable to process locked vnodes, num_on_worklist will still be non-zero, preventing the loop in softdep_process_worklist() from exiting. This can result in a kernel hang. To fix this, process_worklist_item() now returns non-zero if it was able to process a worklist item (regardless of whether it matched the mountpoint) and takes a pointer to matchcnt as a function argument. We now break out of the loop in softdep_process_worklist() if process_worklist_item() is unable to make progress. OK beck@ bluhm@
-rw-r--r--sys/ufs/ffs/ffs_softdep.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index ed4f309ff18..52895599c62 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ffs_softdep.c,v 1.148 2020/02/04 04:09:11 bket Exp $ */
+/* $OpenBSD: ffs_softdep.c,v 1.149 2020/03/09 16:49:12 millert Exp $ */
/*
* Copyright 1998, 2000 Marshall Kirk McKusick. All Rights Reserved.
@@ -163,7 +163,7 @@ STATIC int inodedep_lookup(struct fs *, ufsino_t, int, struct inodedep **);
STATIC int pagedep_lookup(struct inode *, daddr_t, int, struct pagedep **);
STATIC void pause_timer(void *);
STATIC int request_cleanup(int, int);
-STATIC int process_worklist_item(struct mount *, int);
+STATIC int process_worklist_item(struct mount *, int *, int);
STATIC void add_to_worklist(struct worklist *);
/*
@@ -639,7 +639,8 @@ softdep_process_worklist(struct mount *matchmnt)
loopcount = 1;
getmicrouptime(&starttime);
while (num_on_worklist > 0) {
- matchcnt += process_worklist_item(matchmnt, LK_NOWAIT);
+ if (process_worklist_item(matchmnt, &matchcnt, LK_NOWAIT) == 0)
+ break;
/*
* If a umount operation wants to run the worklist
@@ -707,13 +708,12 @@ softdep_process_worklist(struct mount *matchmnt)
* Process one item on the worklist.
*/
STATIC int
-process_worklist_item(struct mount *matchmnt, int flags)
+process_worklist_item(struct mount *matchmnt, int *matchcnt, int flags)
{
struct worklist *wk, *wkend;
struct dirrem *dirrem;
struct mount *mp;
struct vnode *vp;
- int matchcnt = 0;
ACQUIRE_LOCK(&lk);
/*
@@ -761,8 +761,8 @@ process_worklist_item(struct mount *matchmnt, int flags)
panic("%s: dirrem on suspended filesystem",
"process_worklist_item");
#endif
- if (mp == matchmnt)
- matchcnt += 1;
+ if (matchmnt != NULL && mp == matchmnt)
+ *matchcnt += 1;
handle_workitem_remove(WK_DIRREM(wk));
break;
@@ -774,8 +774,8 @@ process_worklist_item(struct mount *matchmnt, int flags)
panic("%s: freeblks on suspended filesystem",
"process_worklist_item");
#endif
- if (mp == matchmnt)
- matchcnt += 1;
+ if (matchmnt != NULL && mp == matchmnt)
+ *matchcnt += 1;
handle_workitem_freeblocks(WK_FREEBLKS(wk));
break;
@@ -787,8 +787,8 @@ process_worklist_item(struct mount *matchmnt, int flags)
panic("%s: freefrag on suspended filesystem",
"process_worklist_item");
#endif
- if (mp == matchmnt)
- matchcnt += 1;
+ if (matchmnt != NULL && mp == matchmnt)
+ *matchcnt += 1;
handle_workitem_freefrag(WK_FREEFRAG(wk));
break;
@@ -800,8 +800,8 @@ process_worklist_item(struct mount *matchmnt, int flags)
panic("%s: freefile on suspended filesystem",
"process_worklist_item");
#endif
- if (mp == matchmnt)
- matchcnt += 1;
+ if (matchmnt != NULL && mp == matchmnt)
+ *matchcnt += 1;
handle_workitem_freefile(WK_FREEFILE(wk));
break;
@@ -810,7 +810,7 @@ process_worklist_item(struct mount *matchmnt, int flags)
"softdep", TYPENAME(wk->wk_type));
/* NOTREACHED */
}
- return (matchcnt);
+ return (1);
}
/*
@@ -5253,8 +5253,8 @@ request_cleanup(int resource, int islocked)
atomic_setbits_int(&p->p_flag, P_SOFTDEP);
if (islocked)
FREE_LOCK(&lk);
- process_worklist_item(NULL, LK_NOWAIT);
- process_worklist_item(NULL, LK_NOWAIT);
+ process_worklist_item(NULL, NULL, LK_NOWAIT);
+ process_worklist_item(NULL, NULL, LK_NOWAIT);
atomic_clearbits_int(&p->p_flag, P_SOFTDEP);
stat_worklist_push += 2;
if (islocked)