Message ID | 20221114162932.141883-39-john.ogness@linutronix.de |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp2241867wru; Mon, 14 Nov 2022 08:38:42 -0800 (PST) X-Google-Smtp-Source: AA0mqf6IwawNozUvoNgT7/4mlCEjttyC4IhBTjD4FDzunfnQRDtdhmADlvUbRSw4dOnypr1ADXtw X-Received: by 2002:aa7:cd13:0:b0:45d:2a5:2db8 with SMTP id b19-20020aa7cd13000000b0045d02a52db8mr11730326edw.105.1668443922615; Mon, 14 Nov 2022 08:38:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668443922; cv=none; d=google.com; s=arc-20160816; b=VhpeABbXpeoJqHa7Dxcg7RVgccTEMnzzQWmRSnlMrWBoJ4YvOVur8JD5B3LTJZPj6M aYJ6CvdMYwuUA6uKzfn+DfRIzmngWl3QsYGsouAIa3albbOZXtEIlTA+atkG+ck62y0h K5yalFEaQVm4n7pGttCjUKMD/wmeBMJxrLe7Bb7Ca+3QNLrXPJBDT85/bJjtRed693PS uk8lqfdWOZIoAx5/Wiiam9rR2xu0021RT5O+UOU8dvbyHXEbJorw/JvxmLWrGVjx9lgj JFs6qjkdnfPWbK07PoKmzvHiRJbwovdAYdenZWVJqLHRikBsoo41d+5w90rqO22qEjN9 qH8Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:dkim-signature :dkim-signature:from; bh=e8qnAfFTCJMXSmY0z9NbV6BFCys+Bgcrek19V+DaSP4=; b=gehV3kJp9Kc/UTximU+bd7hVK8nzO2C1Wz8sVPMRtlxddeD2XPgkigldyfGNnDVp8I UbVs+7EZ/Qvy8Uy6+NSVCF3Jd0knVzHrZNsRW03BX1NLsVtUfmphX2J13B7iK7zVXT3P zECv4taEhfQMrRUDKMISQAUCF7W11LeqNhNI7eir4sKkqFzKgVlym3i7ccnC8kqdtrcm UQ2WovOaXIO7bWDdPVXtan7qhEBDd4lhfGDfOnJ29LCFbtMQ/nhHd7TIagnSxa6NRJ60 598yGusKGmZzG44lpAmwPkcpa2m1Xsd0Z8I/QYL99R3BQp2to8wnKwdgoipg0+L34EA3 e6/g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=SVbG4PEK; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ht10-20020a170907608a00b0078e19e971b2si6519902ejc.915.2022.11.14.08.37.56; Mon, 14 Nov 2022 08:38:42 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linutronix.de header.s=2020 header.b=SVbG4PEK; dkim=neutral (no key) header.i=@linutronix.de; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=linutronix.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237636AbiKNQcW (ORCPT <rfc822;winker.wchi@gmail.com> + 99 others); Mon, 14 Nov 2022 11:32:22 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237724AbiKNQaw (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 14 Nov 2022 11:30:52 -0500 Received: from galois.linutronix.de (Galois.linutronix.de [IPv6:2a0a:51c0:0:12e:550::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D96BC2F642 for <linux-kernel@vger.kernel.org>; Mon, 14 Nov 2022 08:29:52 -0800 (PST) From: John Ogness <john.ogness@linutronix.de> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1668443391; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e8qnAfFTCJMXSmY0z9NbV6BFCys+Bgcrek19V+DaSP4=; b=SVbG4PEKxAfH1E92FMTtE9BRZSIjc27GBLM2VkhgVtSRrzxNzR+aTM/aj0phkPxO7Rt/yY kzAjig+wcjxC+AmDMHmPxDPYPwbNT0XvqlmF0++7F/c916y6Kn0O2jIJRkPfECvyhWECev dI9lj/FxcerEjNO07uBv8QSAMRStiDR9Qe5s1SER/kk11wr288ZPxVpA1vz5NZ+sGiiDcz nIp+xNOvK2zsK2ktiJuieYIiR+MhHHECfpwq8TRAoEomSR/OcP2tyhZq1cgIFpqzEA9JcG rZM7q7LrQX8UssNG4FpuEmHQoCSerkvbQ+PDbtTKhrk49rS/OiaS+n0A/092sA== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1668443391; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=e8qnAfFTCJMXSmY0z9NbV6BFCys+Bgcrek19V+DaSP4=; b=IdXS+nHY6Hxx42ohYDYs3dMXShPYMab1+9r7Y2/TXhfUnf3OSGQ3URpdqRepwgEn7592sy qruYH2a1Ng+xJyBA== To: Petr Mladek <pmladek@suse.com> Cc: Sergey Senozhatsky <senozhatsky@chromium.org>, Steven Rostedt <rostedt@goodmis.org>, Thomas Gleixner <tglx@linutronix.de>, linux-kernel@vger.kernel.org Subject: [PATCH printk v4 38/39] printk: relieve console_lock of list synchronization duties Date: Mon, 14 Nov 2022 17:35:31 +0106 Message-Id: <20221114162932.141883-39-john.ogness@linutronix.de> In-Reply-To: <20221114162932.141883-1-john.ogness@linutronix.de> References: <20221114162932.141883-1-john.ogness@linutronix.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,INVALID_DATE_TZ_ABSURD, RCVD_IN_DNSWL_MED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749490254661768419?= X-GMAIL-MSGID: =?utf-8?q?1749490254661768419?= |
Series |
reduce console_lock scope
|
|
Commit Message
John Ogness
Nov. 14, 2022, 4:29 p.m. UTC
The console_list_lock provides synchronization for console list and
console->flags updates. All call sites that were using the console_lock
for this synchronization have either switched to use the
console_list_lock or the SRCU list iterator.
Remove console_lock usage for console list updates and console->flags
updates.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
kernel/printk/printk.c | 42 ++++++++++++++++++------------------------
1 file changed, 18 insertions(+), 24 deletions(-)
Comments
On Mon 2022-11-14 17:35:31, John Ogness wrote: > The console_list_lock provides synchronization for console list and > console->flags updates. All call sites that were using the console_lock > for this synchronization have either switched to use the > console_list_lock or the SRCU list iterator. > > Remove console_lock usage for console list updates and console->flags > updates. > > Signed-off-by: John Ogness <john.ogness@linutronix.de> > --- a/kernel/printk/printk.c > +++ b/kernel/printk/printk.c > @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) > * boot console that is the furthest behind. > */ > if (bootcon_registered && !keep_bootcon) { > + /* > + * Hold the console_lock to guarantee safe access to > + * console->seq. > + */ > + console_lock(); > for_each_console(con) { > if ((con->flags & CON_BOOT) && > (con->flags & CON_ENABLED) && > @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) > newcon->seq = con->seq; > } > } > + console_unlock(); Thinking more about it. This console_unlock() will actually cause flushing the boot consoles. A solution would be to call console_flush_all() here. And we could/should solve this in a separate patch. This code was not locked before. It is a corner case. It could be solved later. > } > } > Best Regards, Petr
On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote: > On Mon 2022-11-14 17:35:31, John Ogness wrote: >> --- a/kernel/printk/printk.c >> +++ b/kernel/printk/printk.c >> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) >> * boot console that is the furthest behind. >> */ >> if (bootcon_registered && !keep_bootcon) { >> + /* >> + * Hold the console_lock to guarantee safe access to >> + * console->seq. >> + */ >> + console_lock(); >> for_each_console(con) { >> if ((con->flags & CON_BOOT) && >> (con->flags & CON_ENABLED) && >> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) >> newcon->seq = con->seq; >> } >> } >> + console_unlock(); > > Thinking more about it. This console_unlock() will actually cause > flushing the boot consoles. A solution would be to call > console_flush_all() here. console_flush_all() requires the console_lock, so I don't think it would be different. The correct solution would be to recognize if nextcon is taking over a bootcon. If yes, that bootcon could be unregistered right here with unregister_console_locked() and then seq for nextcon set appropriately to perfectly take over. But we will need to think about how we could recognize the same device. I was thinking about if consoles hat some attribute showing their io-membase or something so that it could be clear that the two are the same hardware. > And we could/should solve this in a separate patch. This code was not > locked before. It is a corner case. It could be solved later. Agreed. John
On Tue 2022-11-15 16:34:10, Petr Mladek wrote: > On Mon 2022-11-14 17:35:31, John Ogness wrote: > > The console_list_lock provides synchronization for console list and > > console->flags updates. All call sites that were using the console_lock > > for this synchronization have either switched to use the > > console_list_lock or the SRCU list iterator. > > > > Remove console_lock usage for console list updates and console->flags > > updates. > > > > Signed-off-by: John Ogness <john.ogness@linutronix.de> > > > --- a/kernel/printk/printk.c > > +++ b/kernel/printk/printk.c > > @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) > > * boot console that is the furthest behind. > > */ > > if (bootcon_registered && !keep_bootcon) { > > + /* > > + * Hold the console_lock to guarantee safe access to > > + * console->seq. > > + */ > > + console_lock(); > > for_each_console(con) { > > if ((con->flags & CON_BOOT) && > > (con->flags & CON_ENABLED) && > > @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) > > newcon->seq = con->seq; > > } > > } > > + console_unlock(); > > Thinking more about it. This console_unlock() will actually cause > flushing the boot consoles. A solution would be to call > console_flush_all() here. > > And we could/should solve this in a separate patch. This code was not locked > before. It is a corner case. It could be solved later. > > > } > > } > > The rest of the patch looks fine. I checked hopefully console_list walks and console flags manipulations and everything looks good. So, without the above two hunks: Reviewed-by: Petr Mladek <pmladek@suse.com> Best Regards, Petr
On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote: >>> --- a/kernel/printk/printk.c >>> +++ b/kernel/printk/printk.c >>> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) >>> * boot console that is the furthest behind. >>> */ >>> if (bootcon_registered && !keep_bootcon) { >>> + /* >>> + * Hold the console_lock to guarantee safe access to >>> + * console->seq. >>> + */ >>> + console_lock(); >>> for_each_console(con) { >>> if ((con->flags & CON_BOOT) && >>> (con->flags & CON_ENABLED) && >>> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) >>> newcon->seq = con->seq; >>> } >>> } >>> + console_unlock(); > > So, without the above two hunks: > > Reviewed-by: Petr Mladek <pmladek@suse.com> Note that we actually need those hunks to guarantee a consistent @seq value. The console_lock is the only synchronization mechanism available to read console->seq. John
On Tue 2022-11-15 17:47:12, John Ogness wrote: > On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote: > > On Mon 2022-11-14 17:35:31, John Ogness wrote: > >> --- a/kernel/printk/printk.c > >> +++ b/kernel/printk/printk.c > >> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) > >> * boot console that is the furthest behind. > >> */ > >> if (bootcon_registered && !keep_bootcon) { > >> + /* > >> + * Hold the console_lock to guarantee safe access to > >> + * console->seq. > >> + */ > >> + console_lock(); > >> for_each_console(con) { > >> if ((con->flags & CON_BOOT) && > >> (con->flags & CON_ENABLED) && > >> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) > >> newcon->seq = con->seq; > >> } > >> } > >> + console_unlock(); > > > > Thinking more about it. This console_unlock() will actually cause > > flushing the boot consoles. A solution would be to call > > console_flush_all() here. > > console_flush_all() requires the console_lock, so I don't think it would > be different. I meant to keep the console_lock(), something like: if (bootcon_registered && !keep_bootcon) { /* * Hold the console_lock to guarantee safe access to * console->seq. */ console_lock(); /* Try to sync all consoles. */ console_flush_all(); /* Check if some boot console is still behind. */ for_each_console(con) { if ((con->flags & CON_BOOT) && (con->flags & CON_ENABLED) && con->seq < newcon->seq) { newcon->seq = con->seq; } } console_unlock(); } It is not that easy because console_flush_all() might handover the console_lock(). Also some new messages might appear so that we should re-read prb_next_seq(). Maybe, the best solution would be to call pr_flush(): if (bootcon_registered && !keep_bootcon) { /* * Try to sync all consoles because we do not * know which one is going to be replaced */ pr_flush(); /* * Hold the console_lock to guarantee safe access to * console->seq. */ console_lock(); /* Check if some boot console is still behind. */ for_each_console(con) { if ((con->flags & CON_BOOT) && (con->flags & CON_ENABLED) && con->seq < newcon->seq) { newcon->seq = con->seq; } } console_unlock(); } It was always just the best effort. It does not need to be perfect. On the other hand, we should not make it much worse because people report duplicated messages from time to time. > The correct solution would be to recognize if nextcon is taking over a > bootcon. If yes, that bootcon could be unregistered right here with > unregister_console_locked() and then seq for nextcon set appropriately > to perfectly take over. > > But we will need to think about how we could recognize the same > device. I was thinking about if consoles hat some attribute showing > their io-membase or something so that it could be clear that the two are > the same hardware. Interesting idea. Well, it is out of scope of this patchset. Best Regards, Petr
On Tue 2022-11-15 18:21:34, John Ogness wrote: > On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote: > >>> --- a/kernel/printk/printk.c > >>> +++ b/kernel/printk/printk.c > >>> @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) > >>> * boot console that is the furthest behind. > >>> */ > >>> if (bootcon_registered && !keep_bootcon) { > >>> + /* > >>> + * Hold the console_lock to guarantee safe access to > >>> + * console->seq. > >>> + */ > >>> + console_lock(); > >>> for_each_console(con) { > >>> if ((con->flags & CON_BOOT) && > >>> (con->flags & CON_ENABLED) && > >>> @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) > >>> newcon->seq = con->seq; > >>> } > >>> } > >>> + console_unlock(); > > > > So, without the above two hunks: > > > > Reviewed-by: Petr Mladek <pmladek@suse.com> > > Note that we actually need those hunks to guarantee a consistent @seq > value. The console_lock is the only synchronization mechanism available > to read console->seq. Yes, we need a solution. But it does not need to be in this patch. This patch removes console_lock() on some locations. But this particular code was called without console_lock() even before this patch. Note that the regression was added in the 3rd patch that moved this code outside console_lock(). Maybe, the easiest solution would be to do in the 3rd patch [*]: } else { /* Begin with next message. */ newcon->seq = prb_next_seq(prb); /* * Try hard to show the pending messages on boot consoles. * so that the new console does not start too late. */ pr_flush(); } It should behave as good and as bad as the original code. [*] Or move the code and add this change before the 3rd patch to keep this questionable solution separated and avoid the regression. Best Regards, Petr
On 2022-11-15, Petr Mladek <pmladek@suse.com> wrote: > It is not that easy because console_flush_all() might handover the > console_lock(). Also some new messages might appear so that we > should re-read prb_next_seq(). OK. Taking all this into account, how about: if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) { /* Get a consistent copy of @syslog_seq. */ mutex_lock(&syslog_lock); newcon->seq = syslog_seq; mutex_unlock(&syslog_lock); } else { /* Begin with next message added to ringbuffer. */ newcon->seq = prb_next_seq(prb); /* * If any enabled boot consoles are due to be unregistered * shortly, some may not be caught up and may be the same * device as @newcon. Since it is not known which boot console * is the same device, flush all consoles and, if necessary, * start with the message of the enabled boot console that is * the furthest behind. */ if (bootcon_registered && !keep_bootcon) { bool handover; /* * Hold the console_lock to guarantee safe access to * console->seq. */ console_lock(); /* * Flush all consoles and set the console to start at * the next unprinted sequence number. */ if (!console_flush_all(true, &newcon->seq, &handover)) { /* * Flushing failed. Just choose the lowest * sequence of the enabled boot consoles. */ newcon->seq = prb_next_seq(prb); for_each_console(con) { if ((con->flags & CON_BOOT) && (con->flags & CON_ENABLED) && con->seq < newcon->seq) { newcon->seq = con->seq; } } } console_unlock(); } } John Ogness
Hi, I forgot to re-lock the console... See below. On 2022-11-16, John Ogness <john.ogness@linutronix.de> wrote: > if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) { > /* Get a consistent copy of @syslog_seq. */ > mutex_lock(&syslog_lock); > newcon->seq = syslog_seq; > mutex_unlock(&syslog_lock); > } else { > /* Begin with next message added to ringbuffer. */ > newcon->seq = prb_next_seq(prb); > > /* > * If any enabled boot consoles are due to be unregistered > * shortly, some may not be caught up and may be the same > * device as @newcon. Since it is not known which boot console > * is the same device, flush all consoles and, if necessary, > * start with the message of the enabled boot console that is > * the furthest behind. > */ > if (bootcon_registered && !keep_bootcon) { > bool handover; > > /* > * Hold the console_lock to guarantee safe access to > * console->seq. > */ > console_lock(); > > /* > * Flush all consoles and set the console to start at > * the next unprinted sequence number. > */ > if (!console_flush_all(true, &newcon->seq, &handover)) { > /* > * Flushing failed. Just choose the lowest > * sequence of the enabled boot consoles. > */ Sorry. Here we lost the console_lock. Another acquire is needed here. console_lock(); > newcon->seq = prb_next_seq(prb); > for_each_console(con) { > if ((con->flags & CON_BOOT) && > (con->flags & CON_ENABLED) && > con->seq < newcon->seq) { > newcon->seq = con->seq; > } > } > } > > console_unlock(); > } > } John Ogness
Hi Petr, Sorry, console_flush_all() only loses the console_lock if there was a handover. Here is a new complete suggestion from me. if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) { /* Get a consistent copy of @syslog_seq. */ mutex_lock(&syslog_lock); newcon->seq = syslog_seq; mutex_unlock(&syslog_lock); } else { /* Begin with next message added to ringbuffer. */ newcon->seq = prb_next_seq(prb); /* * If any enabled boot consoles are due to be unregistered * shortly, some may not be caught up and may be the same * device as @newcon. Since it is not known which boot console * is the same device, flush all consoles and, if necessary, * start with the message of the enabled boot console that is * the furthest behind. */ if (bootcon_registered && !keep_bootcon) { bool handover; /* * Hold the console_lock to guarantee safe access to * console->seq. */ console_lock(); /* * Flush all consoles and set the console to start at * the next unprinted sequence number. */ if (!console_flush_all(true, &newcon->seq, &handover)) { /* * Flushing failed. Just choose the lowest * sequence of the enabled boot consoles. */ /* * If there was a handover, this context no * longer holds the console_lock. */ if (handover) console_lock(); newcon->seq = prb_next_seq(prb); for_each_console(con) { if ((con->flags & CON_BOOT) && (con->flags & CON_ENABLED) && con->seq < newcon->seq) { newcon->seq = con->seq; } } } console_unlock(); } John Ogness
On Wed 2022-11-16 10:14:35, John Ogness wrote: > Hi Petr, > > Sorry, console_flush_all() only loses the console_lock if there was a > handover. Here is a new complete suggestion from me. > > if (newcon->flags & (CON_PRINTBUFFER | CON_BOOT)) { > /* Get a consistent copy of @syslog_seq. */ > mutex_lock(&syslog_lock); > newcon->seq = syslog_seq; > mutex_unlock(&syslog_lock); > } else { > /* Begin with next message added to ringbuffer. */ > newcon->seq = prb_next_seq(prb); > > /* > * If any enabled boot consoles are due to be unregistered > * shortly, some may not be caught up and may be the same > * device as @newcon. Since it is not known which boot console > * is the same device, flush all consoles and, if necessary, > * start with the message of the enabled boot console that is > * the furthest behind. > */ > if (bootcon_registered && !keep_bootcon) { > bool handover; > > /* > * Hold the console_lock to guarantee safe access to > * console->seq. > */ > console_lock(); > > /* > * Flush all consoles and set the console to start at > * the next unprinted sequence number. > */ > if (!console_flush_all(true, &newcon->seq, &handover)) { > /* > * Flushing failed. Just choose the lowest > * sequence of the enabled boot consoles. > */ > > /* > * If there was a handover, this context no > * longer holds the console_lock. > */ > if (handover) > console_lock(); > > newcon->seq = prb_next_seq(prb); > for_each_console(con) { > if ((con->flags & CON_BOOT) && > (con->flags & CON_ENABLED) && > con->seq < newcon->seq) { > newcon->seq = con->seq; > } > } > } > > console_unlock(); > } It looks good to me. Now, we just need to agree how to add this into the patchset. My proposal is to: 1. patch: hide the original code into a function, .e.g. console_init_seq() 2. patch: move console_init_seq() and add the above trickery Do both before the 3rd patch in this patchset. It moved the code outside console_lock() guarded section. Best Regards, Petr
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index dff76c1cef80..8d635467882f 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -86,8 +86,8 @@ EXPORT_SYMBOL(oops_in_progress); static DEFINE_MUTEX(console_mutex); /* - * console_sem protects console_list and console->flags updates, and also - * provides serialization for access to the entire console driver system. + * console_sem protects updates to console->seq and console_suspended, + * and also provides serialization for console printing. */ static DEFINE_SEMAPHORE(console_sem); HLIST_HEAD(console_list); @@ -2639,10 +2639,10 @@ static int console_cpu_notify(unsigned int cpu) } /** - * console_lock - lock the console system for exclusive use. + * console_lock - block the console subsystem from printing * - * Acquires a lock which guarantees that the caller has - * exclusive access to the console system and console_list. + * Acquires a lock which guarantees that no consoles will + * be in or enter their write() callback. * * Can sleep, returns nothing. */ @@ -2659,10 +2659,10 @@ void console_lock(void) EXPORT_SYMBOL(console_lock); /** - * console_trylock - try to lock the console system for exclusive use. + * console_trylock - try to block the console subsystem from printing * - * Try to acquire a lock which guarantees that the caller has exclusive - * access to the console system and console_list. + * Try to acquire a lock which guarantees that no consoles will + * be in or enter their write() callback. * * returns 1 on success, and 0 on failure to acquire the lock. */ @@ -2919,10 +2919,10 @@ static bool console_flush_all(bool do_cond_resched, u64 *next_seq, bool *handove } /** - * console_unlock - unlock the console system + * console_unlock - unblock the console subsystem from printing * - * Releases the console_lock which the caller holds on the console system - * and the console driver list. + * Releases the console_lock which the caller holds to block printing of + * the console subsystem. * * While the console_lock was held, console output may have been buffered * by printk(). If this is the case, console_unlock(); emits @@ -3109,9 +3109,7 @@ void console_stop(struct console *console) { __pr_flush(console, 1000, true); console_list_lock(); - console_lock(); console_srcu_write_flags(console, console->flags & ~CON_ENABLED); - console_unlock(); console_list_unlock(); /* @@ -3127,9 +3125,7 @@ EXPORT_SYMBOL(console_stop); void console_start(struct console *console) { console_list_lock(); - console_lock(); console_srcu_write_flags(console, console->flags | CON_ENABLED); - console_unlock(); console_list_unlock(); __pr_flush(console, 1000, true); } @@ -3334,6 +3330,11 @@ void register_console(struct console *newcon) * boot console that is the furthest behind. */ if (bootcon_registered && !keep_bootcon) { + /* + * Hold the console_lock to guarantee safe access to + * console->seq. + */ + console_lock(); for_each_console(con) { if ((con->flags & CON_BOOT) && (con->flags & CON_ENABLED) && @@ -3341,6 +3342,7 @@ void register_console(struct console *newcon) newcon->seq = con->seq; } } + console_unlock(); } } @@ -3348,7 +3350,6 @@ void register_console(struct console *newcon) * Put this console in the list - keep the * preferred driver at the head of the list. */ - console_lock(); if (hlist_empty(&console_list)) { /* Ensure CON_CONSDEV is always set for the head. */ newcon->flags |= CON_CONSDEV; @@ -3362,7 +3363,6 @@ void register_console(struct console *newcon) } else { hlist_add_behind_rcu(&newcon->node, console_list.first); } - console_unlock(); /* * No need to synchronize SRCU here! The caller does not rely @@ -3410,15 +3410,11 @@ static int unregister_console_locked(struct console *console) if (res > 0) return 0; - console_lock(); - /* Disable it unconditionally */ console_srcu_write_flags(console, console->flags & ~CON_ENABLED); - if (!console_is_registered_locked(console)) { - console_unlock(); + if (!console_is_registered_locked(console)) return -ENODEV; - } hlist_del_init_rcu(&console->node); @@ -3434,8 +3430,6 @@ static int unregister_console_locked(struct console *console) if (!hlist_empty(&console_list) && console->flags & CON_CONSDEV) console_srcu_write_flags(console_first(), console_first()->flags | CON_CONSDEV); - console_unlock(); - /* * Ensure that all SRCU list walks have completed. All contexts * must not be able to see this console in the list so that any