Commit 059c4a34 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pstore-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull pstore updates from Kees Cook:
 "A small collection of bug fixes, refactorings, and general
  improvements:

   - Reporting improvements and return path fixes (Guilherme G. Piccoli,
     Wang Yufen, Kees Cook)

   - Clean up kmsg_bytes module parameter usage (Guilherme G. Piccoli)

   - Add Guilherme to pstore MAINTAINERS entry

   - Choose friendlier allocation flags (Qiujun Huang, Stephen Boyd)"

* tag 'pstore-v6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  pstore: Avoid kcore oops by vmap()ing with VM_IOREMAP
  pstore/ram: Fix error return code in ramoops_probe()
  pstore: Alert on backend write error
  MAINTAINERS: Update pstore maintainers
  pstore/ram: Set freed addresses to NULL
  pstore/ram: Move internal definitions out of kernel-wide include
  pstore/ram: Move pmsg init earlier
  pstore/ram: Consolidate kfree() paths
  efi: pstore: Follow convention for the efi-pstore backend name
  pstore: Inform unregistered backend names as well
  pstore: Expose kmsg_bytes as a module parameter
  pstore: Improve error reporting in case of backend overlap
  pstore/zone: Use GFP_ATOMIC to allocate zone buffer
parents 3a28c2c8 e6b84274
......@@ -16661,10 +16661,10 @@ F: net/psample
PSTORE FILESYSTEM
M: Kees Cook <keescook@chromium.org>
M: Anton Vorontsov <anton@enomsg.org>
M: Colin Cross <ccross@android.com>
M: Tony Luck <tony.luck@intel.com>
S: Maintained
R: Tony Luck <tony.luck@intel.com>
R: Guilherme G. Piccoli <gpiccoli@igalia.com>
L: linux-hardening@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/pstore
F: Documentation/admin-guide/ramoops.rst
F: Documentation/admin-guide/pstore-blk.rst
......
......@@ -207,7 +207,7 @@ static int efi_pstore_erase(struct pstore_record *record)
static struct pstore_info efi_pstore_info = {
.owner = THIS_MODULE,
.name = "efi",
.name = KBUILD_MODNAME,
.flags = PSTORE_FLAGS_DMESG,
.open = efi_pstore_open,
.close = efi_pstore_close,
......
......@@ -89,6 +89,11 @@ static char *compress =
module_param(compress, charp, 0444);
MODULE_PARM_DESC(compress, "compression to use");
/* How much of the kernel log to snapshot */
unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
module_param(kmsg_bytes, ulong, 0444);
MODULE_PARM_DESC(kmsg_bytes, "amount of kernel log to snapshot (in bytes)");
/* Compression parameters */
static struct crypto_comp *tfm;
......@@ -100,9 +105,6 @@ struct pstore_zbackend {
static char *big_oops_buf;
static size_t big_oops_buf_sz;
/* How much of the console log to snapshot */
unsigned long kmsg_bytes = CONFIG_PSTORE_DEFAULT_KMSG_BYTES;
void pstore_set_kmsg_bytes(int bytes)
{
kmsg_bytes = bytes;
......@@ -391,6 +393,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
const char *why;
unsigned int part = 1;
unsigned long flags = 0;
int saved_ret = 0;
int ret;
why = kmsg_dump_reason_str(reason);
......@@ -461,12 +464,21 @@ static void pstore_dump(struct kmsg_dumper *dumper,
if (ret == 0 && reason == KMSG_DUMP_OOPS) {
pstore_new_entry = 1;
pstore_timer_kick();
} else {
/* Preserve only the first non-zero returned value. */
if (!saved_ret)
saved_ret = ret;
}
total += record.size;
part++;
}
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
if (saved_ret) {
pr_err_once("backend (%s) writing error (%d)\n", psinfo->name,
saved_ret);
}
}
static struct kmsg_dumper pstore_dumper = {
......@@ -562,8 +574,9 @@ static int pstore_write_user_compat(struct pstore_record *record,
int pstore_register(struct pstore_info *psi)
{
if (backend && strcmp(backend, psi->name)) {
pr_warn("ignoring unexpected backend '%s'\n", psi->name);
return -EPERM;
pr_warn("backend '%s' already in use: ignoring '%s'\n",
backend, psi->name);
return -EBUSY;
}
/* Sanity check flags. */
......@@ -662,6 +675,8 @@ void pstore_unregister(struct pstore_info *psi)
psinfo = NULL;
kfree(backend);
backend = NULL;
pr_info("Unregistered %s as persistent store backend\n", psi->name);
mutex_unlock(&psinfo_lock);
}
EXPORT_SYMBOL_GPL(pstore_unregister);
......
......@@ -18,10 +18,11 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/compiler.h>
#include <linux/pstore_ram.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include "internal.h"
#include "ram_internal.h"
#define RAMOOPS_KERNMSG_HDR "===="
#define MIN_MEM_SIZE 4096UL
......@@ -451,20 +452,28 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
{
int i;
/* Free pmsg PRZ */
persistent_ram_free(&cxt->mprz);
/* Free console PRZ */
persistent_ram_free(&cxt->cprz);
/* Free dump PRZs */
if (cxt->dprzs) {
for (i = 0; i < cxt->max_dump_cnt; i++)
persistent_ram_free(cxt->dprzs[i]);
persistent_ram_free(&cxt->dprzs[i]);
kfree(cxt->dprzs);
cxt->dprzs = NULL;
cxt->max_dump_cnt = 0;
}
/* Free ftrace PRZs */
if (cxt->fprzs) {
for (i = 0; i < cxt->max_ftrace_cnt; i++)
persistent_ram_free(cxt->fprzs[i]);
persistent_ram_free(&cxt->fprzs[i]);
kfree(cxt->fprzs);
cxt->fprzs = NULL;
cxt->max_ftrace_cnt = 0;
}
}
......@@ -548,9 +557,10 @@ static int ramoops_init_przs(const char *name,
while (i > 0) {
i--;
persistent_ram_free(prz_ar[i]);
persistent_ram_free(&prz_ar[i]);
}
kfree(prz_ar);
prz_ar = NULL;
goto fail;
}
*paddr += zone_sz;
......@@ -735,6 +745,7 @@ static int ramoops_probe(struct platform_device *pdev)
/* Make sure we didn't get bogus platform data pointer. */
if (!pdata) {
pr_err("NULL platform data\n");
err = -EINVAL;
goto fail_out;
}
......@@ -742,6 +753,7 @@ static int ramoops_probe(struct platform_device *pdev)
!pdata->ftrace_size && !pdata->pmsg_size)) {
pr_err("The memory size and the record/console size must be "
"non-zero\n");
err = -EINVAL;
goto fail_out;
}
......@@ -772,12 +784,17 @@ static int ramoops_probe(struct platform_device *pdev)
dump_mem_sz, cxt->record_size,
&cxt->max_dump_cnt, 0, 0);
if (err)
goto fail_out;
goto fail_init;
err = ramoops_init_prz("console", dev, cxt, &cxt->cprz, &paddr,
cxt->console_size, 0);
if (err)
goto fail_init_cprz;
goto fail_init;
err = ramoops_init_prz("pmsg", dev, cxt, &cxt->mprz, &paddr,
cxt->pmsg_size, 0);
if (err)
goto fail_init;
cxt->max_ftrace_cnt = (cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)
? nr_cpu_ids
......@@ -788,12 +805,7 @@ static int ramoops_probe(struct platform_device *pdev)
(cxt->flags & RAMOOPS_FLAG_FTRACE_PER_CPU)
? PRZ_FLAG_NO_LOCK : 0);
if (err)
goto fail_init_fprz;
err = ramoops_init_prz("pmsg", dev, cxt, &cxt->mprz, &paddr,
cxt->pmsg_size, 0);
if (err)
goto fail_init_mprz;
goto fail_init;
cxt->pstore.data = cxt;
/*
......@@ -857,11 +869,7 @@ static int ramoops_probe(struct platform_device *pdev)
kfree(cxt->pstore.buf);
fail_clear:
cxt->pstore.bufsize = 0;
persistent_ram_free(cxt->mprz);
fail_init_mprz:
fail_init_fprz:
persistent_ram_free(cxt->cprz);
fail_init_cprz:
fail_init:
ramoops_free_przs(cxt);
fail_out:
return err;
......@@ -876,8 +884,6 @@ static int ramoops_remove(struct platform_device *pdev)
kfree(cxt->pstore.buf);
cxt->pstore.bufsize = 0;
persistent_ram_free(cxt->mprz);
persistent_ram_free(cxt->cprz);
ramoops_free_przs(cxt);
return 0;
......
......@@ -13,13 +13,14 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/pstore_ram.h>
#include <linux/rslib.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <asm/page.h>
#include "ram_internal.h"
/**
* struct persistent_ram_buffer - persistent circular RAM buffer
*
......@@ -439,7 +440,11 @@ static void *persistent_ram_vmap(phys_addr_t start, size_t size,
phys_addr_t addr = page_start + i * PAGE_SIZE;
pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
}
vaddr = vmap(pages, page_count, VM_MAP, prot);
/*
* VM_IOREMAP used here to bypass this region during vread()
* and kmap_atomic() (i.e. kcore) to avoid __va() failures.
*/
vaddr = vmap(pages, page_count, VM_MAP | VM_IOREMAP, prot);
kfree(pages);
/*
......@@ -543,8 +548,14 @@ static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
return 0;
}
void persistent_ram_free(struct persistent_ram_zone *prz)
void persistent_ram_free(struct persistent_ram_zone **_prz)
{
struct persistent_ram_zone *prz;
if (!_prz)
return;
prz = *_prz;
if (!prz)
return;
......@@ -568,6 +579,7 @@ void persistent_ram_free(struct persistent_ram_zone *prz)
persistent_ram_free_old(prz);
kfree(prz->label);
kfree(prz);
*_prz = NULL;
}
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
......@@ -604,6 +616,6 @@ struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
return prz;
err:
persistent_ram_free(prz);
persistent_ram_free(&prz);
return ERR_PTR(ret);
}
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
* Copyright (C) 2011 Kees Cook <keescook@chromium.org>
* Copyright (C) 2011 Google, Inc.
*/
#include <linux/pstore_ram.h>
/*
* Choose whether access to the RAM zone requires locking or not. If a zone
* can be written to from different CPUs like with ftrace for example, then
* PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
*/
#define PRZ_FLAG_NO_LOCK BIT(0)
/*
* If a PRZ should only have a single-boot lifetime, this marks it as
* getting wiped after its contents get copied out after boot.
*/
#define PRZ_FLAG_ZAP_OLD BIT(1)
/**
* struct persistent_ram_zone - Details of a persistent RAM zone (PRZ)
* used as a pstore backend
*
* @paddr: physical address of the mapped RAM area
* @size: size of mapping
* @label: unique name of this PRZ
* @type: frontend type for this PRZ
* @flags: holds PRZ_FLAGS_* bits
*
* @buffer_lock:
* locks access to @buffer "size" bytes and "start" offset
* @buffer:
* pointer to actual RAM area managed by this PRZ
* @buffer_size:
* bytes in @buffer->data (not including any trailing ECC bytes)
*
* @par_buffer:
* pointer into @buffer->data containing ECC bytes for @buffer->data
* @par_header:
* pointer into @buffer->data containing ECC bytes for @buffer header
* (i.e. all fields up to @data)
* @rs_decoder:
* RSLIB instance for doing ECC calculations
* @corrected_bytes:
* ECC corrected bytes accounting since boot
* @bad_blocks:
* ECC uncorrectable bytes accounting since boot
* @ecc_info:
* ECC configuration details
*
* @old_log:
* saved copy of @buffer->data prior to most recent wipe
* @old_log_size:
* bytes contained in @old_log
*
*/
struct persistent_ram_zone {
phys_addr_t paddr;
size_t size;
void *vaddr;
char *label;
enum pstore_type_id type;
u32 flags;
raw_spinlock_t buffer_lock;
struct persistent_ram_buffer *buffer;
size_t buffer_size;
char *par_buffer;
char *par_header;
struct rs_control *rs_decoder;
int corrected_bytes;
int bad_blocks;
struct persistent_ram_ecc_info ecc_info;
char *old_log;
size_t old_log_size;
};
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
u32 sig, struct persistent_ram_ecc_info *ecc_info,
unsigned int memtype, u32 flags, char *label);
void persistent_ram_free(struct persistent_ram_zone **_prz);
void persistent_ram_zap(struct persistent_ram_zone *prz);
int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
unsigned int count);
int persistent_ram_write_user(struct persistent_ram_zone *prz,
const void __user *s, unsigned int count);
void persistent_ram_save_old(struct persistent_ram_zone *prz);
size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
void *persistent_ram_old(struct persistent_ram_zone *prz);
void persistent_ram_free_old(struct persistent_ram_zone *prz);
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len);
......@@ -761,7 +761,7 @@ static inline int notrace psz_kmsg_write_record(struct psz_context *cxt,
/* avoid destroying old data, allocate a new one */
len = zone->buffer_size + sizeof(*zone->buffer);
zone->oldbuf = zone->buffer;
zone->buffer = kzalloc(len, GFP_KERNEL);
zone->buffer = kzalloc(len, GFP_ATOMIC);
if (!zone->buffer) {
zone->buffer = zone->oldbuf;
return -ENOMEM;
......
......@@ -8,28 +8,7 @@
#ifndef __LINUX_PSTORE_RAM_H__
#define __LINUX_PSTORE_RAM_H__
#include <linux/compiler.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/pstore.h>
#include <linux/types.h>
/*
* Choose whether access to the RAM zone requires locking or not. If a zone
* can be written to from different CPUs like with ftrace for example, then
* PRZ_FLAG_NO_LOCK is used. For all other cases, locking is required.
*/
#define PRZ_FLAG_NO_LOCK BIT(0)
/*
* If a PRZ should only have a single-boot lifetime, this marks it as
* getting wiped after its contents get copied out after boot.
*/
#define PRZ_FLAG_ZAP_OLD BIT(1)
struct persistent_ram_buffer;
struct rs_control;
struct persistent_ram_ecc_info {
int block_size;
......@@ -39,84 +18,6 @@ struct persistent_ram_ecc_info {
uint16_t *par;
};
/**
* struct persistent_ram_zone - Details of a persistent RAM zone (PRZ)
* used as a pstore backend
*
* @paddr: physical address of the mapped RAM area
* @size: size of mapping
* @label: unique name of this PRZ
* @type: frontend type for this PRZ
* @flags: holds PRZ_FLAGS_* bits
*
* @buffer_lock:
* locks access to @buffer "size" bytes and "start" offset
* @buffer:
* pointer to actual RAM area managed by this PRZ
* @buffer_size:
* bytes in @buffer->data (not including any trailing ECC bytes)
*
* @par_buffer:
* pointer into @buffer->data containing ECC bytes for @buffer->data
* @par_header:
* pointer into @buffer->data containing ECC bytes for @buffer header
* (i.e. all fields up to @data)
* @rs_decoder:
* RSLIB instance for doing ECC calculations
* @corrected_bytes:
* ECC corrected bytes accounting since boot
* @bad_blocks:
* ECC uncorrectable bytes accounting since boot
* @ecc_info:
* ECC configuration details
*
* @old_log:
* saved copy of @buffer->data prior to most recent wipe
* @old_log_size:
* bytes contained in @old_log
*
*/
struct persistent_ram_zone {
phys_addr_t paddr;
size_t size;
void *vaddr;
char *label;
enum pstore_type_id type;
u32 flags;
raw_spinlock_t buffer_lock;
struct persistent_ram_buffer *buffer;
size_t buffer_size;
char *par_buffer;
char *par_header;
struct rs_control *rs_decoder;
int corrected_bytes;
int bad_blocks;
struct persistent_ram_ecc_info ecc_info;
char *old_log;
size_t old_log_size;
};
struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
u32 sig, struct persistent_ram_ecc_info *ecc_info,
unsigned int memtype, u32 flags, char *label);
void persistent_ram_free(struct persistent_ram_zone *prz);
void persistent_ram_zap(struct persistent_ram_zone *prz);
int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
unsigned int count);
int persistent_ram_write_user(struct persistent_ram_zone *prz,
const void __user *s, unsigned int count);
void persistent_ram_save_old(struct persistent_ram_zone *prz);
size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
void *persistent_ram_old(struct persistent_ram_zone *prz);
void persistent_ram_free_old(struct persistent_ram_zone *prz);
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len);
/*
* Ramoops platform data
* @mem_size memory size for ramoops
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment