summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorSteven Johnson <[email protected]>2012-12-03 16:16:17 +0800
committerBrian Behlendorf <[email protected]>2012-12-12 09:04:11 -0800
commitca072ee70f7beccd33c0363dc7951a10492b4782 (patch)
tree7674d4dba669cf287aa3d4ab06f4eb7a51d1f595 /module
parent576ec6aac4a4a15754892824643cedb30d652c39 (diff)
splat linux:shrinker: Fix race condition
Ensure the test thread blocks until the shrinker has completed its work. This is done by putting the test thread to sleep and waking it each time the shrinker callback runs. Once the shrinker size drops to zero or we time out the test is allowed to proceed. Signed-off-by: Brian Behlendorf <[email protected]> Closes #96 Closes #125 Closes #182
Diffstat (limited to 'module')
-rw-r--r--module/splat/splat-linux.c28
1 files changed, 27 insertions, 1 deletions
diff --git a/module/splat/splat-linux.c b/module/splat/splat-linux.c
index 5303df4e0..6c89fc034 100644
--- a/module/splat/splat-linux.c
+++ b/module/splat/splat-linux.c
@@ -86,6 +86,12 @@ splat_linux_test2(struct file *file, void *arg)
return 0;
}
+/*
+ * Wait queue used to eliminate race between dropping of slab
+ * and execution of the shrinker callback
+ */
+DECLARE_WAIT_QUEUE_HEAD(shrinker_wait);
+
SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn);
SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1);
static unsigned long splat_linux_shrinker_size = 0;
@@ -116,6 +122,9 @@ __splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
return -1;
}
+ /* Shrinker has run, so signal back to test. */
+ wake_up(&shrinker_wait);
+
return (int)splat_linux_shrinker_size;
}
@@ -183,7 +192,24 @@ splat_linux_test3(struct file *file, void *arg)
if (rc)
goto out;
- if (splat_linux_shrinker_size != 0) {
+ /*
+ * By the time we get here, it is possible that the shrinker has not
+ * yet run. splat_linux_drop_slab sends a signal for it to run, but
+ * there is no guarantee of when it will actually run. We wait for it
+ * to run here, terminating when either the shrinker size is now 0 or
+ * we timeout after 1 second, which should be an eternity (error).
+ */
+ rc = wait_event_timeout(shrinker_wait, !splat_linux_shrinker_size, HZ);
+ if (!rc) {
+ splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
+ "Failed cache shrinking timed out, size now %lu",
+ splat_linux_shrinker_size);
+ rc = -ETIMEDOUT;
+ } else {
+ rc = 0;
+ }
+
+ if (!rc && splat_linux_shrinker_size != 0) {
splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
"Failed cache was not shrunk to 0, size now %lu",
splat_linux_shrinker_size);