Skip to content

Commit 8126b1c

Browse files
thejhkees
authored andcommitted
pstore: Don't use semaphores in always-atomic-context code
pstore_dump() is *always* invoked in atomic context (nowadays in an RCU read-side critical section, before that under a spinlock). It doesn't make sense to try to use semaphores here. This is mostly a revert of commit ea84b58 ("pstore: Convert buf_lock to semaphore"), except that two parts aren't restored back exactly as they were: - keep the lock initialization in pstore_register - in efi_pstore_write(), always set the "block" flag to false - omit "is_locked", that was unnecessary since commit 959217c ("pstore: Actually give up during locking failure") - fix the bailout message The actual problem that the buggy commit was trying to address may have been that the use of preemptible() in efi_pstore_write() was wrong - it only looks at preempt_count() and the state of IRQs, but __rcu_read_lock() doesn't touch either of those under CONFIG_PREEMPT_RCU. (Sidenote: CONFIG_PREEMPT_RCU means that the scheduler can preempt tasks in RCU read-side critical sections, but you're not allowed to actively block/reschedule.) Lockdep probably never caught the problem because it's very rare that you actually hit the contended case, so lockdep always just sees the down_trylock(), not the down_interruptible(), and so it can't tell that there's a problem. Fixes: ea84b58 ("pstore: Convert buf_lock to semaphore") Cc: stable@vger.kernel.org Acked-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Jann Horn <jannh@google.com> Signed-off-by: Kees Cook <keescook@chromium.org> Link: https://lore.kernel.org/r/20220314185953.2068993-1-jannh@google.com
1 parent 023bbde commit 8126b1c

3 files changed

Lines changed: 22 additions & 24 deletions

File tree

drivers/firmware/efi/efi-pstore.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ static int efi_pstore_write(struct pstore_record *record)
266266
efi_name[i] = name[i];
267267

268268
ret = efivar_entry_set_safe(efi_name, vendor, PSTORE_EFI_ATTRIBUTES,
269-
preemptible(), record->size, record->psi->buf);
269+
false, record->size, record->psi->buf);
270270

271271
if (record->reason == KMSG_DUMP_OOPS && try_module_get(THIS_MODULE))
272272
if (!schedule_work(&efivar_work))

fs/pstore/platform.c

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,22 @@ static void pstore_timer_kick(void)
143143
mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
144144
}
145145

146-
/*
147-
* Should pstore_dump() wait for a concurrent pstore_dump()? If
148-
* not, the current pstore_dump() will report a failure to dump
149-
* and return.
150-
*/
151-
static bool pstore_cannot_wait(enum kmsg_dump_reason reason)
146+
static bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
152147
{
153-
/* In NMI path, pstore shouldn't block regardless of reason. */
148+
/*
149+
* In case of NMI path, pstore shouldn't be blocked
150+
* regardless of reason.
151+
*/
154152
if (in_nmi())
155153
return true;
156154

157155
switch (reason) {
158156
/* In panic case, other cpus are stopped by smp_send_stop(). */
159157
case KMSG_DUMP_PANIC:
160-
/* Emergency restart shouldn't be blocked. */
158+
/*
159+
* Emergency restart shouldn't be blocked by spinning on
160+
* pstore_info::buf_lock.
161+
*/
161162
case KMSG_DUMP_EMERG:
162163
return true;
163164
default:
@@ -389,21 +390,19 @@ static void pstore_dump(struct kmsg_dumper *dumper,
389390
unsigned long total = 0;
390391
const char *why;
391392
unsigned int part = 1;
393+
unsigned long flags = 0;
392394
int ret;
393395

394396
why = kmsg_dump_reason_str(reason);
395397

396-
if (down_trylock(&psinfo->buf_lock)) {
397-
/* Failed to acquire lock: give up if we cannot wait. */
398-
if (pstore_cannot_wait(reason)) {
399-
pr_err("dump skipped in %s path: may corrupt error record\n",
400-
in_nmi() ? "NMI" : why);
401-
return;
402-
}
403-
if (down_interruptible(&psinfo->buf_lock)) {
404-
pr_err("could not grab semaphore?!\n");
398+
if (pstore_cannot_block_path(reason)) {
399+
if (!spin_trylock_irqsave(&psinfo->buf_lock, flags)) {
400+
pr_err("dump skipped in %s path because of concurrent dump\n",
401+
in_nmi() ? "NMI" : why);
405402
return;
406403
}
404+
} else {
405+
spin_lock_irqsave(&psinfo->buf_lock, flags);
407406
}
408407

409408
kmsg_dump_rewind(&iter);
@@ -467,8 +466,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
467466
total += record.size;
468467
part++;
469468
}
470-
471-
up(&psinfo->buf_lock);
469+
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
472470
}
473471

474472
static struct kmsg_dumper pstore_dumper = {
@@ -594,7 +592,7 @@ int pstore_register(struct pstore_info *psi)
594592
psi->write_user = pstore_write_user_compat;
595593
psinfo = psi;
596594
mutex_init(&psinfo->read_mutex);
597-
sema_init(&psinfo->buf_lock, 1);
595+
spin_lock_init(&psinfo->buf_lock);
598596

599597
if (psi->flags & PSTORE_FLAGS_DMESG)
600598
allocate_buf_for_compression();

include/linux/pstore.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#include <linux/errno.h>
1515
#include <linux/kmsg_dump.h>
1616
#include <linux/mutex.h>
17-
#include <linux/semaphore.h>
17+
#include <linux/spinlock.h>
1818
#include <linux/time.h>
1919
#include <linux/types.h>
2020

@@ -87,7 +87,7 @@ struct pstore_record {
8787
* @owner: module which is responsible for this backend driver
8888
* @name: name of the backend driver
8989
*
90-
* @buf_lock: semaphore to serialize access to @buf
90+
* @buf_lock: spinlock to serialize access to @buf
9191
* @buf: preallocated crash dump buffer
9292
* @bufsize: size of @buf available for crash dump bytes (must match
9393
* smallest number of bytes available for writing to a
@@ -178,7 +178,7 @@ struct pstore_info {
178178
struct module *owner;
179179
const char *name;
180180

181-
struct semaphore buf_lock;
181+
spinlock_t buf_lock;
182182
char *buf;
183183
size_t bufsize;
184184

0 commit comments

Comments
 (0)