aboutsummaryrefslogtreecommitdiffstats
path: root/module/spl/spl-generic.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2012-12-18 17:02:27 -0800
committerBrian Behlendorf <[email protected]>2012-12-19 09:06:35 -0800
commit034f1b331e2c152e8e8954d715fa9a84f7b48d64 (patch)
treea7101b1b0e87624f60dc88ffa34c6993e6f31c23 /module/spl/spl-generic.c
parent30196bfd42567a9bc3fccac8650dc2cd9f0f7c0a (diff)
Fix spl_kmem_init_kallsyms_lookup() panic
Due to I/O buffering the helper may return successfully before the proc handler has a chance to execute. To catch this case wait up to 1 second to verify spl_kallsyms_lookup_name_fn was updated to a non SYMBOL_POISON value. Signed-off-by: Brian Behlendorf <[email protected]> Closes zfsonlinux/zfs#699 Closes zfsonlinux/zfs#859
Diffstat (limited to 'module/spl/spl-generic.c')
-rw-r--r--module/spl/spl-generic.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c
index cc2766452..22ea50781 100644
--- a/module/spl/spl-generic.c
+++ b/module/spl/spl-generic.c
@@ -64,6 +64,7 @@ proc_t p0 = { 0 };
EXPORT_SYMBOL(p0);
#ifndef HAVE_KALLSYMS_LOOKUP_NAME
+DECLARE_WAIT_QUEUE_HEAD(spl_kallsyms_lookup_name_waitq);
kallsyms_lookup_name_t spl_kallsyms_lookup_name_fn = SYMBOL_POISON;
#endif
@@ -607,6 +608,24 @@ set_kallsyms_lookup_name(void)
int rc;
rc = call_usermodehelper(argv[0], argv, envp, 1);
+
+ /*
+ * Due to I/O buffering the helper may return successfully before
+ * the proc handler has a chance to execute. To catch this case
+ * wait up to 1 second to verify spl_kallsyms_lookup_name_fn was
+ * updated to a non SYMBOL_POISON value.
+ */
+ if (rc == 0) {
+ rc = wait_event_timeout(spl_kallsyms_lookup_name_waitq,
+ spl_kallsyms_lookup_name_fn != SYMBOL_POISON, HZ);
+ if (rc == 0)
+ rc = -ETIMEDOUT;
+ else if (spl_kallsyms_lookup_name_fn == SYMBOL_POISON)
+ rc = -EFAULT;
+ else
+ rc = 0;
+ }
+
if (rc)
printk("SPL: Failed user helper '%s %s %s', rc = %d\n",
argv[0], argv[1], argv[2], rc);