Skip to content

Commit

Permalink
Merge tag 'pstore-v4.9-rc1' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/kees/linux

Pull pstore updates from Kees Cook:

 - Fix bug in module unloading

 - Switch to always using spinlock over cmpxchg

 - Explicitly define pstore backend's supported modes

 - Remove bounce buffer from pmsg

 - Switch to using memcpy_to/fromio()

 - Error checking improvements

* tag 'pstore-v4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  ramoops: move spin_lock_init after kmalloc error checking
  pstore/ram: Use memcpy_fromio() to save old buffer
  pstore/ram: Use memcpy_toio instead of memcpy
  pstore/pmsg: drop bounce buffer
  pstore/ram: Set pstore flags dynamically
  pstore: Split pstore fragile flags
  pstore/core: drop cmpxchg based updates
  pstore/ramoops: fixup driver removal
  • Loading branch information
Linus Torvalds committed Oct 6, 2016
2 parents 3940ee3 + f88baf6 commit 0fb3ca4
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 96 deletions.
2 changes: 1 addition & 1 deletion drivers/acpi/apei/erst.c
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,7 @@ static int erst_clearer(enum pstore_type_id type, u64 id, int count,
static struct pstore_info erst_info = {
.owner = THIS_MODULE,
.name = "erst",
.flags = PSTORE_FLAGS_FRAGILE,
.flags = PSTORE_FLAGS_DMESG,
.open = erst_open_pstore,
.close = erst_close_pstore,
.read = erst_reader,
Expand Down
2 changes: 1 addition & 1 deletion drivers/firmware/efi/efi-pstore.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
static struct pstore_info efi_pstore_info = {
.owner = THIS_MODULE,
.name = "efi",
.flags = PSTORE_FLAGS_FRAGILE,
.flags = PSTORE_FLAGS_DMESG,
.open = efi_pstore_open,
.close = efi_pstore_close,
.read = efi_pstore_read,
Expand Down
53 changes: 46 additions & 7 deletions fs/pstore/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,40 @@ static int pstore_write_compat(enum pstore_type_id type,
size, psi);
}

static int pstore_write_buf_user_compat(enum pstore_type_id type,
enum kmsg_dump_reason reason,
u64 *id, unsigned int part,
const char __user *buf,
bool compressed, size_t size,
struct pstore_info *psi)
{
unsigned long flags = 0;
size_t i, bufsize = size;
long ret = 0;

if (unlikely(!access_ok(VERIFY_READ, buf, size)))
return -EFAULT;
if (bufsize > psinfo->bufsize)
bufsize = psinfo->bufsize;
spin_lock_irqsave(&psinfo->buf_lock, flags);
for (i = 0; i < size; ) {
size_t c = min(size - i, bufsize);

ret = __copy_from_user(psinfo->buf, buf + i, c);
if (unlikely(ret != 0)) {
ret = -EFAULT;
break;
}
ret = psi->write_buf(type, reason, id, part, psinfo->buf,
compressed, c, psi);
if (unlikely(ret < 0))
break;
i += c;
}
spin_unlock_irqrestore(&psinfo->buf_lock, flags);
return unlikely(ret < 0) ? ret : size;
}

/*
* platform specific persistent storage driver registers with
* us here. If pstore is already mounted, call the platform
Expand All @@ -645,6 +679,8 @@ int pstore_register(struct pstore_info *psi)

if (!psi->write)
psi->write = pstore_write_compat;
if (!psi->write_buf_user)
psi->write_buf_user = pstore_write_buf_user_compat;
psinfo = psi;
mutex_init(&psinfo->read_mutex);
spin_unlock(&pstore_lock);
Expand All @@ -659,13 +695,14 @@ int pstore_register(struct pstore_info *psi)
if (pstore_is_mounted())
pstore_get_records(0);

pstore_register_kmsg();

if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) {
if (psi->flags & PSTORE_FLAGS_DMESG)
pstore_register_kmsg();
if (psi->flags & PSTORE_FLAGS_CONSOLE)
pstore_register_console();
if (psi->flags & PSTORE_FLAGS_FTRACE)
pstore_register_ftrace();
if (psi->flags & PSTORE_FLAGS_PMSG)
pstore_register_pmsg();
}

if (pstore_update_ms >= 0) {
pstore_timer.expires = jiffies +
Expand All @@ -689,12 +726,14 @@ EXPORT_SYMBOL_GPL(pstore_register);

void pstore_unregister(struct pstore_info *psi)
{
if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) {
if (psi->flags & PSTORE_FLAGS_PMSG)
pstore_unregister_pmsg();
if (psi->flags & PSTORE_FLAGS_FTRACE)
pstore_unregister_ftrace();
if (psi->flags & PSTORE_FLAGS_CONSOLE)
pstore_unregister_console();
}
pstore_unregister_kmsg();
if (psi->flags & PSTORE_FLAGS_DMESG)
pstore_unregister_kmsg();

free_buf_for_compression();

Expand Down
35 changes: 6 additions & 29 deletions fs/pstore/pmsg.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,25 @@
#include "internal.h"

static DEFINE_MUTEX(pmsg_lock);
#define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE)

static ssize_t write_pmsg(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
size_t i, buffer_size;
char *buffer;
u64 id;
int ret;

if (!count)
return 0;

/* check outside lock, page in any data. write_buf_user also checks */
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;

buffer_size = count;
if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE)
buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE;
buffer = vmalloc(buffer_size);
if (!buffer)
return -ENOMEM;

mutex_lock(&pmsg_lock);
for (i = 0; i < count; ) {
size_t c = min(count - i, buffer_size);
u64 id;
long ret;

ret = __copy_from_user(buffer, buf + i, c);
if (unlikely(ret != 0)) {
mutex_unlock(&pmsg_lock);
vfree(buffer);
return -EFAULT;
}
psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c,
psinfo);

i += c;
}

ret = psinfo->write_buf_user(PSTORE_TYPE_PMSG, 0, &id, 0, buf, 0, count,
psinfo);
mutex_unlock(&pmsg_lock);
vfree(buffer);
return count;
return ret ? ret : count;
}

static const struct file_operations pmsg_fops = {
Expand Down
46 changes: 40 additions & 6 deletions fs/pstore/ram.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,24 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
return 0;
}

static int notrace ramoops_pstore_write_buf_user(enum pstore_type_id type,
enum kmsg_dump_reason reason,
u64 *id, unsigned int part,
const char __user *buf,
bool compressed, size_t size,
struct pstore_info *psi)
{
if (type == PSTORE_TYPE_PMSG) {
struct ramoops_context *cxt = psi->data;

if (!cxt->mprz)
return -ENOMEM;
return persistent_ram_write_user(cxt->mprz, buf, size);
}

return -EINVAL;
}

static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
struct timespec time, struct pstore_info *psi)
{
Expand Down Expand Up @@ -369,6 +387,7 @@ static struct ramoops_context oops_cxt = {
.open = ramoops_pstore_open,
.read = ramoops_pstore_read,
.write_buf = ramoops_pstore_write_buf,
.write_buf_user = ramoops_pstore_write_buf_user,
.erase = ramoops_pstore_erase,
},
};
Expand All @@ -377,13 +396,14 @@ static void ramoops_free_przs(struct ramoops_context *cxt)
{
int i;

cxt->max_dump_cnt = 0;
if (!cxt->przs)
return;

for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
for (i = 0; i < cxt->max_dump_cnt; i++)
persistent_ram_free(cxt->przs[i]);

kfree(cxt->przs);
cxt->max_dump_cnt = 0;
}

static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
Expand All @@ -408,7 +428,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
GFP_KERNEL);
if (!cxt->przs) {
dev_err(dev, "failed to initialize a prz array for dumps\n");
goto fail_prz;
goto fail_mem;
}

for (i = 0; i < cxt->max_dump_cnt; i++) {
Expand All @@ -419,14 +439,21 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
err = PTR_ERR(cxt->przs[i]);
dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
cxt->record_size, (unsigned long long)*paddr, err);

while (i > 0) {
i--;
persistent_ram_free(cxt->przs[i]);
}
goto fail_prz;
}
*paddr += cxt->record_size;
}

return 0;
fail_prz:
ramoops_free_przs(cxt);
kfree(cxt->przs);
fail_mem:
cxt->max_dump_cnt = 0;
return err;
}

Expand Down Expand Up @@ -608,12 +635,20 @@ static int ramoops_probe(struct platform_device *pdev)
cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */
cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize);
cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
spin_lock_init(&cxt->pstore.buf_lock);
if (!cxt->pstore.buf) {
pr_err("cannot allocate pstore buffer\n");
err = -ENOMEM;
goto fail_clear;
}
spin_lock_init(&cxt->pstore.buf_lock);

cxt->pstore.flags = PSTORE_FLAGS_DMESG;
if (cxt->console_size)
cxt->pstore.flags |= PSTORE_FLAGS_CONSOLE;
if (cxt->ftrace_size)
cxt->pstore.flags |= PSTORE_FLAGS_FTRACE;
if (cxt->pmsg_size)
cxt->pstore.flags |= PSTORE_FLAGS_PMSG;

err = pstore_register(&cxt->pstore);
if (err) {
Expand Down Expand Up @@ -659,7 +694,6 @@ static int ramoops_remove(struct platform_device *pdev)
struct ramoops_context *cxt = &oops_cxt;

pstore_unregister(&cxt->pstore);
cxt->max_dump_cnt = 0;

kfree(cxt->pstore.buf);
cxt->pstore.bufsize = 0;
Expand Down
Loading

0 comments on commit 0fb3ca4

Please sign in to comment.