From 034f1b331e2c152e8e8954d715fa9a84f7b48d64 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 18 Dec 2012 17:02:27 -0800 Subject: [PATCH] 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 Closes zfsonlinux/zfs#699 Closes zfsonlinux/zfs#859 --- include/linux/kallsyms_compat.h | 1 + module/spl/spl-generic.c | 19 +++++++++++++++++++ module/spl/spl-proc.c | 2 ++ 3 files changed, 22 insertions(+) diff --git a/include/linux/kallsyms_compat.h b/include/linux/kallsyms_compat.h index 34c45ea3..fbe33e8e 100644 --- a/include/linux/kallsyms_compat.h +++ b/include/linux/kallsyms_compat.h @@ -34,6 +34,7 @@ #else +extern wait_queue_head_t spl_kallsyms_lookup_name_waitq; typedef unsigned long (*kallsyms_lookup_name_t)(const char *); extern kallsyms_lookup_name_t spl_kallsyms_lookup_name_fn; #define spl_kallsyms_lookup_name(name) spl_kallsyms_lookup_name_fn(name) diff --git a/module/spl/spl-generic.c b/module/spl/spl-generic.c index cc276645..22ea5078 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); diff --git a/module/spl/spl-proc.c b/module/spl/spl-proc.c index 152abff7..2fb29543 100644 --- a/module/spl/spl-proc.c +++ b/module/spl/spl-proc.c @@ -546,6 +546,8 @@ SPL_PROC_HANDLER(proc_dokallsyms_lookup_name) spl_kallsyms_lookup_name_fn = (kallsyms_lookup_name_t)simple_strtoul(str, &end, 16); + wake_up(&spl_kallsyms_lookup_name_waitq); + if (str == end) SRETURN(-EINVAL);