summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordas <das@FreeBSD.org>2005-03-25 17:30:31 +0000
committerdas <das@FreeBSD.org>2005-03-25 17:30:31 +0000
commit3b88b0f403c14a37086d6bc0f64e2727d63455e0 (patch)
treee7de0cbd9c448a0e41a872102dc8e0d123f49608
parentea5af1c34abf6a5a5427daad4842337cfc7392b9 (diff)
downloadFreeBSD-src-3b88b0f403c14a37086d6bc0f64e2727d63455e0.zip
FreeBSD-src-3b88b0f403c14a37086d6bc0f64e2727d63455e0.tar.gz
When the softupdates worklist gets too long, threads that attempt to
add more work are forced to process two worklist items first. However, processing an item may generate additional work, causing the unlucky thread to recursively process the worklist. Add a per-thread flag to detect this situation and avoid the recursion. This should fix the stack overflows that could occur while removing large directory trees. Tested by: kris Reviewed by: mckusick
-rw-r--r--sys/sys/proc.h1
-rw-r--r--sys/ufs/ffs/ffs_softdep.c7
2 files changed, 6 insertions, 2 deletions
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index e6875e1..5f95865 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -375,6 +375,7 @@ struct thread {
#define TDP_SCHED3 0x00004000 /* Reserved for scheduler private use */
#define TDP_SCHED4 0x00008000 /* Reserved for scheduler private use */
#define TDP_GEOM 0x00010000 /* Settle GEOM before finishing syscall */
+#define TDP_SOFTDEP 0x00020000 /* Stuck processing softdep worklist */
/*
* Reasons that the current thread can not be run yet.
diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c
index 3169475..1d0cd15 100644
--- a/sys/ufs/ffs/ffs_softdep.c
+++ b/sys/ufs/ffs/ffs_softdep.c
@@ -5528,18 +5528,21 @@ request_cleanup(resource)
/*
* We never hold up the filesystem syncer process.
*/
- if (td == filesys_syncer)
+ if (td == filesys_syncer || (td->td_pflags & TDP_SOFTDEP))
return (0);
/*
* First check to see if the work list has gotten backlogged.
* If it has, co-opt this process to help clean up two entries.
* Because this process may hold inodes locked, we cannot
* handle any remove requests that might block on a locked
- * inode as that could lead to deadlock.
+ * inode as that could lead to deadlock. We set TDP_SOFTDEP
+ * to avoid recursively processing the worklist.
*/
if (num_on_worklist > max_softdeps / 10) {
+ td->td_pflags |= TDP_SOFTDEP;
process_worklist_item(NULL, LK_NOWAIT);
process_worklist_item(NULL, LK_NOWAIT);
+ td->td_pflags &= ~TDP_SOFTDEP;
stat_worklist_push += 2;
return(1);
}
OpenPOWER on IntegriCloud