Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755311AbdDDXDb (ORCPT ); Tue, 4 Apr 2017 19:03:31 -0400 Received: from mx0a-00082601.pphosted.com ([67.231.145.42]:44743 "EHLO mx0a-00082601.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755242AbdDDXD3 (ORCPT ); Tue, 4 Apr 2017 19:03:29 -0400 Smtp-Origin-Hostprefix: devbig From: Calvin Owens Smtp-Origin-Hostname: devbig337.prn1.facebook.com To: Petr Mladek , Sergey Senozhatsky , Steven Rostedt CC: Greg Kroah-Hartman , Jiri Slaby , Andrew Morton , Calvin Owens , =?UTF-8?q?Manuel=20Sch=C3=B6lling?= , Hans de Goede , Paul Burton , , Smtp-Origin-Cluster: prn1c29 Subject: [RFC][PATCH 2/2] printk: Add /sys/consoles/${con}/ and maxlevel attribute Date: Tue, 4 Apr 2017 16:03:20 -0700 Message-ID: <8d144e1ec0c18761c4a6e14353e49e81a81bc924.1491345440.git.calvinowens@fb.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: References: X-FB-Internal: Safe MIME-Version: 1.0 Content-Type: text/plain X-Proofpoint-Spam-Reason: safe X-FB-Internal: Safe X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-04-04_21:,, signatures=0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4148 Lines: 156 This does the simplest possible thing: add a directory at the root of sysfs that allows setting the "maxlevel" parameter for each console. We can let kobject destruction race with console removal: if it does, maxlevel_{show,store}() will safely fail with -ENODEV. This is a little weird, but avoids embedding the kobject and therefore needing to totally refactor the way we handle console struct lifetime. Signed-off-by: Calvin Owens --- include/linux/console.h | 1 + kernel/printk/printk.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/include/linux/console.h b/include/linux/console.h index 764a2c0..c76fde0 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -148,6 +148,7 @@ struct console { void *data; struct console *next; int maxlevel; + struct kobject *kobj; }; /* diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 5393928..e9d036b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -105,6 +105,8 @@ enum devkmsg_log_masks { static unsigned int __read_mostly devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT; +static struct kobject *consoles_dir_kobj; + static int __control_devkmsg(char *str) { if (!str) @@ -2386,6 +2388,76 @@ static int __init keep_bootcon_setup(char *str) early_param("keep_bootcon", keep_bootcon_setup); +static ssize_t maxlevel_show(struct kobject *kobj, struct kobj_attribute *attr, + char *buf) +{ + struct console *con; + ssize_t ret = -ENODEV; + + console_lock(); + for_each_console(con) { + if (con->kobj == kobj) { + ret = sprintf(buf, "%d\n", con->maxlevel); + break; + } + } + console_unlock(); + + return ret; +} + +static ssize_t maxlevel_store(struct kobject *kobj, struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct console *con; + ssize_t ret; + int tmp; + + ret = kstrtoint(buf, 10, &tmp); + if (ret < 0) + return ret; + + if (tmp < 0 || tmp > LOGLEVEL_DEBUG) + return -ERANGE; + + ret = -ENODEV; + console_lock(); + for_each_console(con) { + if (con->kobj == kobj) { + con->maxlevel = tmp; + ret = count; + break; + } + } + console_unlock(); + + return ret; +} + +static const struct kobj_attribute console_level_attr = + __ATTR(maxlevel, 0644, maxlevel_show, maxlevel_store); + +static void console_register_sysfs(struct console *newcon) +{ + /* + * We might be called very early from register_console(): in that case, + * printk_late_init() will take care of this later. + */ + if (!consoles_dir_kobj) + return; + + newcon->kobj = kobject_create_and_add(newcon->name, consoles_dir_kobj); + if (WARN_ON(!newcon->kobj)) + return; + + WARN_ON(sysfs_create_file(newcon->kobj, &console_level_attr.attr)); +} + +static void console_unregister_sysfs(struct console *oldcon) +{ + kobject_put(oldcon->kobj); +} + /* * The console driver calls this routine during kernel initialization * to register the console printing procedure with printk() and to @@ -2509,6 +2581,7 @@ void register_console(struct console *newcon) * By default, the per-console loglevel filter permits all messages. */ newcon->maxlevel = LOGLEVEL_DEBUG; + newcon->kobj = NULL; /* * Put this console in the list - keep the @@ -2545,6 +2618,7 @@ void register_console(struct console *newcon) */ exclusive_console = newcon; } + console_register_sysfs(newcon); console_unlock(); console_sysfs_notify(); @@ -2611,6 +2685,7 @@ int unregister_console(struct console *console) console_drivers->flags |= CON_CONSDEV; console->flags &= ~CON_ENABLED; + console_unregister_sysfs(console); console_unlock(); console_sysfs_notify(); return res; @@ -2656,6 +2731,13 @@ static int __init printk_late_init(void) ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN, "printk:online", console_cpu_notify, NULL); WARN_ON(ret < 0); + + consoles_dir_kobj = kobject_create_and_add("consoles", NULL); + WARN_ON(!consoles_dir_kobj); + + for_each_console(con) + console_register_sysfs(con); + return 0; } late_initcall(printk_late_init); -- 2.9.3