From nobody Mon Dec 1 22:03:56 2025 Received: from mail-pf1-f180.google.com (mail-pf1-f180.google.com [209.85.210.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7490F3081D3 for ; Thu, 27 Nov 2025 19:43:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.180 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764272621; cv=none; b=tt7qvmBmGCuImZqk+b7hHvmqqqOE1f6ogl00D4awuR7mC8LRUuJm2PY+Dvugi1at3DX6VMkl6m67ksIsiNyzQ2g639s8Xgjfg3hiO5l3TKoXU/66P4nEQ0qeEWblVUesJbWPfFF8FP03+5qYhtvFyHNC6RQVyuZWZI162J4xtUA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764272621; c=relaxed/simple; bh=OvJSycgZUCPBl+uZZw09dbTUkQR9AWuwc/FFBfnISpI=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=JjQ0sFMJEUZwQE2R/IURzIaIGeeK0wvjt+57ZdZTC2vsdOC9IKUswx5sSw/vwo43SZJ2IkY4dltdEW8lxHakz1dv8WxElP9JP4z0Wc3ENFxq1aEwlMqLXwld+cNYH2KfaNa4ke3NYvR4kbHYohY40UjheRn1CD/UuMkE837bqlE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=chrisdown.name; spf=pass smtp.mailfrom=chrisdown.name; dkim=pass (1024-bit key) header.d=chrisdown.name header.i=@chrisdown.name header.b=tr+wZClX; arc=none smtp.client-ip=209.85.210.180 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=chrisdown.name Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=chrisdown.name Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=chrisdown.name header.i=@chrisdown.name header.b="tr+wZClX" Received: by mail-pf1-f180.google.com with SMTP id d2e1a72fcca58-7a9c64dfa8aso940391b3a.3 for ; Thu, 27 Nov 2025 11:43:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chrisdown.name; s=google; t=1764272618; x=1764877418; darn=vger.kernel.org; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:from:to:cc:subject:date :message-id:reply-to; bh=LkOWcj3e+Jt7r3tNySIXYiC5E6MVflJ99RHKFwZ8Kko=; b=tr+wZClXDZHHIRnVVtl9xX4yx0k9MY7k8Kp17/ZAG+6nKeRtZEk0dgWZjrPmK/aiwq lrTj8wYgYiIwEGKmySXz8jTfhjCWmJUB4jxWxXbJhGWxfxqi/xZNh8QwGR/o399m/brK sSsO2ZVwNXLBbVmM2yaz0NQ2GJ5oN9FxPXyKQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764272618; x=1764877418; h=user-agent:in-reply-to:content-disposition:mime-version:references :message-id:subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=LkOWcj3e+Jt7r3tNySIXYiC5E6MVflJ99RHKFwZ8Kko=; b=m66aTgtVe7RCJ6NhriEa+rT6LtZ6HdvdhOOszyhjI4S0V3ivL9mTQJ0y4RJwO2Bfi5 hEU1C+ITjz93OyP9AN0PBQt7mJsnHyc8y2mpTf+vX8SB8nsWtR6EDt3THwrinm0bBiRk mkLofxjrhXscVYuPk95zSP8T7uyAVWoyNtPwvUj8ajwzLzeoCnrAdyaaXMZ755c01pFR hJ+W7qkEUCBr77maVGTxZg0Moufe6QhpQAQ+3xOrT3dU2XWWSoXdqKyQ/FTlBZaljgI0 5/iK/uXFNduZPgZGUzvOf22bvLABQa6zord/BSkKiRRC4qNTHhXR4jmvhJSmyRZffea3 UlLA== X-Gm-Message-State: AOJu0YwdbRu/R/4BE6ysLLe6hg2BCBYWPvGqA+np7HvgboyvLQIwi/K8 4deeVNh4boxBdeyTb29EvLYispjTJhcKlUbp3jnDwdZ1HDcLF/sNQ5lVldKm6i6TpT8= X-Gm-Gg: ASbGncskWWRUawx3TO8I7hgAgdXQJA17ljJXsZJbsTwOhAFziIYsAPUYvu7Ko3SudKd dA7pyZne3O+2zDR1UndZs6O34iGZTayFtraL12PNm275z+MuiNofBN/jw1zHZxYYPd9bXCah7zH YpFPBjPnzAIsmGteJUQbVtr60iixibGNeSCsDg3FZHlgcex5aaJn/oTvgQi3+8/+ilqildWffZU CJG5rhn4u831ZxgrLtWQXzySkZLvQslihOKYZTR6t58U0KSzpVOyewBPcPekhtXt5Jl6NVLxQOA Ml+oeP3B1AoJCoF6Mq2hvdj6OKJWXkJ7ke8QSyAw6EV8vGYsTvHXnM/wAQ2CrpdPm8Fwmkb3Qhr sV6u8ogXzH7GBw43vdIdn3tHP6Dt0nQwwoRGp2Lwgf1iV6TrFqii9vuTrKx+VJc968N6g0udMih QcCJBIqE04 X-Google-Smtp-Source: AGHT+IEOF1ylQ9DmHBNbC+Gy7+MpH++4GYDkWI6VBSZVq4NS4RWak6XSocqfJGF9ehjhnsvhD4KVZw== X-Received: by 2002:a05:6a00:1492:b0:781:4f0b:9c58 with SMTP id d2e1a72fcca58-7ca8aaf1a44mr13888079b3a.15.1764272618428; Thu, 27 Nov 2025 11:43:38 -0800 (PST) Received: from localhost ([116.86.198.140]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7d15e7db416sm2632557b3a.41.2025.11.27.11.43.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 27 Nov 2025 11:43:38 -0800 (PST) Date: Fri, 28 Nov 2025 03:43:36 +0800 From: Chris Down To: Petr Mladek Cc: linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Sergey Senozhatsky , Steven Rostedt , John Ogness , Geert Uytterhoeven , Tony Lindgren , kernel-team@fb.com Subject: [PATCH v8 07/21] printk: Introduce per-console loglevel support Message-ID: <662c8dbd954f8a52a099805299da93d4c5473a97.1764272407.git.chris@chrisdown.name> References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/2.2.15 (2b349c5e) (2025-10-02) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Implement the logic to determine which loglevel should be used for message filtering on each console. The effective loglevel for a console is determined by a hierarchy of controls: 1. ignore_loglevel (highest priority), which prints all messages regardless of level, overriding both global and per-console settings. 2. The per-console loglevel. If set to a valid value (> 0), the console uses this level instead of the global console_loglevel. 3. Global console_loglevel (fallback). This is used when per-console loglevel is not set (LOGLEVEL_DEFAULT, i.e. -1). Reviewed-by: Petr Mladek Signed-off-by: Chris Down --- kernel/printk/internal.h | 10 +++++ kernel/printk/nbcon.c | 10 +++-- kernel/printk/printk.c | 86 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h index 1ed86577896c..f2ebaa2a6aa2 100644 --- a/kernel/printk/internal.h +++ b/kernel/printk/internal.h @@ -15,6 +15,16 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *ta= ble, int write, #define printk_sysctl_init() do { } while (0) #endif =20 +enum loglevel_source { + LLS_GLOBAL, + LLS_LOCAL, + LLS_IGNORE_LOGLEVEL, +}; + +enum loglevel_source +console_effective_loglevel_source(int con_level); +int console_effective_loglevel(int con_level); + #define con_printk(lvl, con, fmt, ...) \ printk(lvl pr_fmt("%s%sconsole [%s%d] " fmt), \ (con->flags & CON_NBCON) ? "" : "legacy ", \ diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c index 493c9e8b2dd5..a61a607a5159 100644 --- a/kernel/printk/nbcon.c +++ b/kernel/printk/nbcon.c @@ -961,6 +961,7 @@ static bool nbcon_emit_next_record(struct nbcon_write_c= ontext *wctxt, bool use_a struct nbcon_context *ctxt =3D &ACCESS_PRIVATE(wctxt, ctxt); struct console *con =3D ctxt->console; bool is_extended =3D console_srcu_read_flags(con) & CON_EXTENDED; + int con_level =3D console_srcu_read_loglevel(con); struct printk_message pmsg =3D { .pbufs =3D ctxt->pbufs, }; @@ -993,7 +994,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_c= ontext *wctxt, bool use_a if (!nbcon_context_enter_unsafe(ctxt)) return false; =20 - ctxt->backlog =3D printk_get_next_message(&pmsg, ctxt->seq, is_extended, = console_loglevel); + ctxt->backlog =3D printk_get_next_message(&pmsg, ctxt->seq, is_extended, + console_effective_loglevel(con_level)); if (!ctxt->backlog) return nbcon_context_exit_unsafe(ctxt); =20 @@ -1509,9 +1511,9 @@ static int __nbcon_atomic_flush_pending_con(struct co= nsole *con, u64 stop_seq, =20 /* * Match the console_srcu_read_lock()/unlock expectation embedded in - * console_srcu_read_flags(), which is called from nbcon_emit_next_record= (). - * Without this, unregister_console() cannot synchronise against the - * atomic flusher. + * console_srcu_read_loglevel()/console_srcu_read_flags(), both of which + * are called from nbcon_emit_next_record(). Without this, + * unregister_console() cannot synchronise against the atomic flusher. */ cookie =3D console_srcu_read_lock(); =20 diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index c6b56f4d8072..d9c1bc4a32c4 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1280,6 +1280,89 @@ module_param(ignore_loglevel, bool, S_IRUGO | S_IWUS= R); MODULE_PARM_DESC(ignore_loglevel, "ignore loglevel setting (prints all kernel messages to the console)"); =20 +/** + * is_valid_per_console_loglevel - Check if a loglevel is valid for per-co= nsole + * + * @con_level: The loglevel to check + * + * Per-console loglevels must be strictly positive (> 0). Level 0 (KERN_EM= ERG) + * is reserved for emergency messages that should go to all consoles (and = so is + * disallowed), and -1 (LOGLEVEL_DEFAULT) means use the global console_log= level. + * + * Return: true if con_level is a valid per-console loglevel (> 0), false + * otherwise + */ +static bool is_valid_per_console_loglevel(int con_level) +{ + return (con_level > 0); +} + +/** + * console_effective_loglevel_source - Determine the source of effective l= oglevel + * + * @con_level: The console's per-console loglevel value + * + * This function determines which loglevel authority is in effect for a co= nsole, + * based on the hierarchy of controls: + * + * 1. ignore_loglevel (overrides everything - prints all messages) + * 2. per-console loglevel (if set and not ignored) + * 3. global console_loglevel (fallback) + * + * Return: The loglevel source (LLS_IGNORE_LOGLEVEL, LLS_LOCAL, or LLS_GLO= BAL) + */ +enum loglevel_source +console_effective_loglevel_source(int con_level) +{ + if (ignore_loglevel) + return LLS_IGNORE_LOGLEVEL; + + if (is_valid_per_console_loglevel(con_level)) + return LLS_LOCAL; + + return LLS_GLOBAL; +} + +/** + * console_effective_loglevel - Get the effective loglevel for a console + * + * @con_level: The console's per-console loglevel value + * + * This function returns the actual loglevel value that should be used for + * message filtering for a console, taking into account all loglevel contr= ols + * (global, per-console, and ignore_loglevel). + * + * The effective loglevel is used to determine which messages get printed = to + * the console. Messages with priority less than the effective level are p= rinted. + * + * Return: The effective loglevel value to use for filtering + */ +int console_effective_loglevel(int con_level) +{ + enum loglevel_source source; + int level; + + source =3D console_effective_loglevel_source(con_level); + + switch (source) { + case LLS_IGNORE_LOGLEVEL: + level =3D CONSOLE_LOGLEVEL_MOTORMOUTH; + break; + case LLS_LOCAL: + level =3D con_level; + break; + case LLS_GLOBAL: + level =3D console_loglevel; + break; + default: + pr_warn("Unhandled console loglevel source: %d", source); + level =3D console_loglevel; + break; + } + + return level; +} + static bool suppress_message_printing(int level, int con_eff_level) { return (level >=3D con_eff_level && !ignore_loglevel); @@ -3090,6 +3173,7 @@ struct printk_buffers printk_shared_pbufs; static bool console_emit_next_record(struct console *con, bool *handover, = int cookie) { bool is_extended =3D console_srcu_read_flags(con) & CON_EXTENDED; + int con_level =3D console_srcu_read_loglevel(con); char *outbuf =3D &printk_shared_pbufs.outbuf[0]; struct printk_message pmsg =3D { .pbufs =3D &printk_shared_pbufs, @@ -3099,7 +3183,7 @@ static bool console_emit_next_record(struct console *= con, bool *handover, int co *handover =3D false; =20 if (!printk_get_next_message(&pmsg, con->seq, is_extended, - console_loglevel)) + console_effective_loglevel(con_level))) return false; =20 con->dropped +=3D pmsg.dropped; --=20 2.51.2