diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-06 18:16:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-06 18:16:16 -0400 |
commit | 0fb3ca447ddabcfb8dc7e0f719955e500b170cbd (patch) | |
tree | 57e516541b7650149c468a9567152164b12c75e3 | |
parent | 3940ee36a0565ea7fb848e3c798afe22efd0b90a (diff) | |
parent | f88baf68ebe5b2efced64725fd98548af9b8f510 (diff) |
Merge tag 'pstore-v4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/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
-rw-r--r-- | drivers/acpi/apei/erst.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efi/efi-pstore.c | 2 | ||||
-rw-r--r-- | fs/pstore/platform.c | 53 | ||||
-rw-r--r-- | fs/pstore/pmsg.c | 35 | ||||
-rw-r--r-- | fs/pstore/ram.c | 46 | ||||
-rw-r--r-- | fs/pstore/ram_core.c | 96 | ||||
-rw-r--r-- | include/linux/pstore.h | 17 | ||||
-rw-r--r-- | include/linux/pstore_ram.h | 7 |
8 files changed, 162 insertions, 96 deletions
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index f096ab3cb54d..ec4f507b524f 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c | |||
@@ -938,7 +938,7 @@ static int erst_clearer(enum pstore_type_id type, u64 id, int count, | |||
938 | static struct pstore_info erst_info = { | 938 | static struct pstore_info erst_info = { |
939 | .owner = THIS_MODULE, | 939 | .owner = THIS_MODULE, |
940 | .name = "erst", | 940 | .name = "erst", |
941 | .flags = PSTORE_FLAGS_FRAGILE, | 941 | .flags = PSTORE_FLAGS_DMESG, |
942 | .open = erst_open_pstore, | 942 | .open = erst_open_pstore, |
943 | .close = erst_close_pstore, | 943 | .close = erst_close_pstore, |
944 | .read = erst_reader, | 944 | .read = erst_reader, |
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c index 1c33d7469e4a..f402ba2eed46 100644 --- a/drivers/firmware/efi/efi-pstore.c +++ b/drivers/firmware/efi/efi-pstore.c | |||
@@ -380,7 +380,7 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
380 | static struct pstore_info efi_pstore_info = { | 380 | static struct pstore_info efi_pstore_info = { |
381 | .owner = THIS_MODULE, | 381 | .owner = THIS_MODULE, |
382 | .name = "efi", | 382 | .name = "efi", |
383 | .flags = PSTORE_FLAGS_FRAGILE, | 383 | .flags = PSTORE_FLAGS_DMESG, |
384 | .open = efi_pstore_open, | 384 | .open = efi_pstore_open, |
385 | .close = efi_pstore_close, | 385 | .close = efi_pstore_close, |
386 | .read = efi_pstore_read, | 386 | .read = efi_pstore_read, |
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c index 16ecca5b72d8..14984d902a99 100644 --- a/fs/pstore/platform.c +++ b/fs/pstore/platform.c | |||
@@ -623,6 +623,40 @@ static int pstore_write_compat(enum pstore_type_id type, | |||
623 | size, psi); | 623 | size, psi); |
624 | } | 624 | } |
625 | 625 | ||
626 | static int pstore_write_buf_user_compat(enum pstore_type_id type, | ||
627 | enum kmsg_dump_reason reason, | ||
628 | u64 *id, unsigned int part, | ||
629 | const char __user *buf, | ||
630 | bool compressed, size_t size, | ||
631 | struct pstore_info *psi) | ||
632 | { | ||
633 | unsigned long flags = 0; | ||
634 | size_t i, bufsize = size; | ||
635 | long ret = 0; | ||
636 | |||
637 | if (unlikely(!access_ok(VERIFY_READ, buf, size))) | ||
638 | return -EFAULT; | ||
639 | if (bufsize > psinfo->bufsize) | ||
640 | bufsize = psinfo->bufsize; | ||
641 | spin_lock_irqsave(&psinfo->buf_lock, flags); | ||
642 | for (i = 0; i < size; ) { | ||
643 | size_t c = min(size - i, bufsize); | ||
644 | |||
645 | ret = __copy_from_user(psinfo->buf, buf + i, c); | ||
646 | if (unlikely(ret != 0)) { | ||
647 | ret = -EFAULT; | ||
648 | break; | ||
649 | } | ||
650 | ret = psi->write_buf(type, reason, id, part, psinfo->buf, | ||
651 | compressed, c, psi); | ||
652 | if (unlikely(ret < 0)) | ||
653 | break; | ||
654 | i += c; | ||
655 | } | ||
656 | spin_unlock_irqrestore(&psinfo->buf_lock, flags); | ||
657 | return unlikely(ret < 0) ? ret : size; | ||
658 | } | ||
659 | |||
626 | /* | 660 | /* |
627 | * platform specific persistent storage driver registers with | 661 | * platform specific persistent storage driver registers with |
628 | * us here. If pstore is already mounted, call the platform | 662 | * us here. If pstore is already mounted, call the platform |
@@ -645,6 +679,8 @@ int pstore_register(struct pstore_info *psi) | |||
645 | 679 | ||
646 | if (!psi->write) | 680 | if (!psi->write) |
647 | psi->write = pstore_write_compat; | 681 | psi->write = pstore_write_compat; |
682 | if (!psi->write_buf_user) | ||
683 | psi->write_buf_user = pstore_write_buf_user_compat; | ||
648 | psinfo = psi; | 684 | psinfo = psi; |
649 | mutex_init(&psinfo->read_mutex); | 685 | mutex_init(&psinfo->read_mutex); |
650 | spin_unlock(&pstore_lock); | 686 | spin_unlock(&pstore_lock); |
@@ -659,13 +695,14 @@ int pstore_register(struct pstore_info *psi) | |||
659 | if (pstore_is_mounted()) | 695 | if (pstore_is_mounted()) |
660 | pstore_get_records(0); | 696 | pstore_get_records(0); |
661 | 697 | ||
662 | pstore_register_kmsg(); | 698 | if (psi->flags & PSTORE_FLAGS_DMESG) |
663 | 699 | pstore_register_kmsg(); | |
664 | if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) { | 700 | if (psi->flags & PSTORE_FLAGS_CONSOLE) |
665 | pstore_register_console(); | 701 | pstore_register_console(); |
702 | if (psi->flags & PSTORE_FLAGS_FTRACE) | ||
666 | pstore_register_ftrace(); | 703 | pstore_register_ftrace(); |
704 | if (psi->flags & PSTORE_FLAGS_PMSG) | ||
667 | pstore_register_pmsg(); | 705 | pstore_register_pmsg(); |
668 | } | ||
669 | 706 | ||
670 | if (pstore_update_ms >= 0) { | 707 | if (pstore_update_ms >= 0) { |
671 | pstore_timer.expires = jiffies + | 708 | pstore_timer.expires = jiffies + |
@@ -689,12 +726,14 @@ EXPORT_SYMBOL_GPL(pstore_register); | |||
689 | 726 | ||
690 | void pstore_unregister(struct pstore_info *psi) | 727 | void pstore_unregister(struct pstore_info *psi) |
691 | { | 728 | { |
692 | if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) { | 729 | if (psi->flags & PSTORE_FLAGS_PMSG) |
693 | pstore_unregister_pmsg(); | 730 | pstore_unregister_pmsg(); |
731 | if (psi->flags & PSTORE_FLAGS_FTRACE) | ||
694 | pstore_unregister_ftrace(); | 732 | pstore_unregister_ftrace(); |
733 | if (psi->flags & PSTORE_FLAGS_CONSOLE) | ||
695 | pstore_unregister_console(); | 734 | pstore_unregister_console(); |
696 | } | 735 | if (psi->flags & PSTORE_FLAGS_DMESG) |
697 | pstore_unregister_kmsg(); | 736 | pstore_unregister_kmsg(); |
698 | 737 | ||
699 | free_buf_for_compression(); | 738 | free_buf_for_compression(); |
700 | 739 | ||
diff --git a/fs/pstore/pmsg.c b/fs/pstore/pmsg.c index 7de20cd3797f..78f6176c020f 100644 --- a/fs/pstore/pmsg.c +++ b/fs/pstore/pmsg.c | |||
@@ -19,48 +19,25 @@ | |||
19 | #include "internal.h" | 19 | #include "internal.h" |
20 | 20 | ||
21 | static DEFINE_MUTEX(pmsg_lock); | 21 | static DEFINE_MUTEX(pmsg_lock); |
22 | #define PMSG_MAX_BOUNCE_BUFFER_SIZE (2*PAGE_SIZE) | ||
23 | 22 | ||
24 | static ssize_t write_pmsg(struct file *file, const char __user *buf, | 23 | static ssize_t write_pmsg(struct file *file, const char __user *buf, |
25 | size_t count, loff_t *ppos) | 24 | size_t count, loff_t *ppos) |
26 | { | 25 | { |
27 | size_t i, buffer_size; | 26 | u64 id; |
28 | char *buffer; | 27 | int ret; |
29 | 28 | ||
30 | if (!count) | 29 | if (!count) |
31 | return 0; | 30 | return 0; |
32 | 31 | ||
32 | /* check outside lock, page in any data. write_buf_user also checks */ | ||
33 | if (!access_ok(VERIFY_READ, buf, count)) | 33 | if (!access_ok(VERIFY_READ, buf, count)) |
34 | return -EFAULT; | 34 | return -EFAULT; |
35 | 35 | ||
36 | buffer_size = count; | ||
37 | if (buffer_size > PMSG_MAX_BOUNCE_BUFFER_SIZE) | ||
38 | buffer_size = PMSG_MAX_BOUNCE_BUFFER_SIZE; | ||
39 | buffer = vmalloc(buffer_size); | ||
40 | if (!buffer) | ||
41 | return -ENOMEM; | ||
42 | |||
43 | mutex_lock(&pmsg_lock); | 36 | mutex_lock(&pmsg_lock); |
44 | for (i = 0; i < count; ) { | 37 | ret = psinfo->write_buf_user(PSTORE_TYPE_PMSG, 0, &id, 0, buf, 0, count, |
45 | size_t c = min(count - i, buffer_size); | 38 | psinfo); |
46 | u64 id; | ||
47 | long ret; | ||
48 | |||
49 | ret = __copy_from_user(buffer, buf + i, c); | ||
50 | if (unlikely(ret != 0)) { | ||
51 | mutex_unlock(&pmsg_lock); | ||
52 | vfree(buffer); | ||
53 | return -EFAULT; | ||
54 | } | ||
55 | psinfo->write_buf(PSTORE_TYPE_PMSG, 0, &id, 0, buffer, 0, c, | ||
56 | psinfo); | ||
57 | |||
58 | i += c; | ||
59 | } | ||
60 | |||
61 | mutex_unlock(&pmsg_lock); | 39 | mutex_unlock(&pmsg_lock); |
62 | vfree(buffer); | 40 | return ret ? ret : count; |
63 | return count; | ||
64 | } | 41 | } |
65 | 42 | ||
66 | static const struct file_operations pmsg_fops = { | 43 | static const struct file_operations pmsg_fops = { |
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c index 7a034d62cf8c..6ad831b9d1b8 100644 --- a/fs/pstore/ram.c +++ b/fs/pstore/ram.c | |||
@@ -331,6 +331,24 @@ static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, | |||
331 | return 0; | 331 | return 0; |
332 | } | 332 | } |
333 | 333 | ||
334 | static int notrace ramoops_pstore_write_buf_user(enum pstore_type_id type, | ||
335 | enum kmsg_dump_reason reason, | ||
336 | u64 *id, unsigned int part, | ||
337 | const char __user *buf, | ||
338 | bool compressed, size_t size, | ||
339 | struct pstore_info *psi) | ||
340 | { | ||
341 | if (type == PSTORE_TYPE_PMSG) { | ||
342 | struct ramoops_context *cxt = psi->data; | ||
343 | |||
344 | if (!cxt->mprz) | ||
345 | return -ENOMEM; | ||
346 | return persistent_ram_write_user(cxt->mprz, buf, size); | ||
347 | } | ||
348 | |||
349 | return -EINVAL; | ||
350 | } | ||
351 | |||
334 | static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, | 352 | static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, |
335 | struct timespec time, struct pstore_info *psi) | 353 | struct timespec time, struct pstore_info *psi) |
336 | { | 354 | { |
@@ -369,6 +387,7 @@ static struct ramoops_context oops_cxt = { | |||
369 | .open = ramoops_pstore_open, | 387 | .open = ramoops_pstore_open, |
370 | .read = ramoops_pstore_read, | 388 | .read = ramoops_pstore_read, |
371 | .write_buf = ramoops_pstore_write_buf, | 389 | .write_buf = ramoops_pstore_write_buf, |
390 | .write_buf_user = ramoops_pstore_write_buf_user, | ||
372 | .erase = ramoops_pstore_erase, | 391 | .erase = ramoops_pstore_erase, |
373 | }, | 392 | }, |
374 | }; | 393 | }; |
@@ -377,13 +396,14 @@ static void ramoops_free_przs(struct ramoops_context *cxt) | |||
377 | { | 396 | { |
378 | int i; | 397 | int i; |
379 | 398 | ||
380 | cxt->max_dump_cnt = 0; | ||
381 | if (!cxt->przs) | 399 | if (!cxt->przs) |
382 | return; | 400 | return; |
383 | 401 | ||
384 | for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++) | 402 | for (i = 0; i < cxt->max_dump_cnt; i++) |
385 | persistent_ram_free(cxt->przs[i]); | 403 | persistent_ram_free(cxt->przs[i]); |
404 | |||
386 | kfree(cxt->przs); | 405 | kfree(cxt->przs); |
406 | cxt->max_dump_cnt = 0; | ||
387 | } | 407 | } |
388 | 408 | ||
389 | static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | 409 | static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, |
@@ -408,7 +428,7 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | |||
408 | GFP_KERNEL); | 428 | GFP_KERNEL); |
409 | if (!cxt->przs) { | 429 | if (!cxt->przs) { |
410 | dev_err(dev, "failed to initialize a prz array for dumps\n"); | 430 | dev_err(dev, "failed to initialize a prz array for dumps\n"); |
411 | goto fail_prz; | 431 | goto fail_mem; |
412 | } | 432 | } |
413 | 433 | ||
414 | for (i = 0; i < cxt->max_dump_cnt; i++) { | 434 | for (i = 0; i < cxt->max_dump_cnt; i++) { |
@@ -419,6 +439,11 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | |||
419 | err = PTR_ERR(cxt->przs[i]); | 439 | err = PTR_ERR(cxt->przs[i]); |
420 | dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", | 440 | dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", |
421 | cxt->record_size, (unsigned long long)*paddr, err); | 441 | cxt->record_size, (unsigned long long)*paddr, err); |
442 | |||
443 | while (i > 0) { | ||
444 | i--; | ||
445 | persistent_ram_free(cxt->przs[i]); | ||
446 | } | ||
422 | goto fail_prz; | 447 | goto fail_prz; |
423 | } | 448 | } |
424 | *paddr += cxt->record_size; | 449 | *paddr += cxt->record_size; |
@@ -426,7 +451,9 @@ static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, | |||
426 | 451 | ||
427 | return 0; | 452 | return 0; |
428 | fail_prz: | 453 | fail_prz: |
429 | ramoops_free_przs(cxt); | 454 | kfree(cxt->przs); |
455 | fail_mem: | ||
456 | cxt->max_dump_cnt = 0; | ||
430 | return err; | 457 | return err; |
431 | } | 458 | } |
432 | 459 | ||
@@ -608,12 +635,20 @@ static int ramoops_probe(struct platform_device *pdev) | |||
608 | cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */ | 635 | cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */ |
609 | cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize); | 636 | cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize); |
610 | cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); | 637 | cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); |
611 | spin_lock_init(&cxt->pstore.buf_lock); | ||
612 | if (!cxt->pstore.buf) { | 638 | if (!cxt->pstore.buf) { |
613 | pr_err("cannot allocate pstore buffer\n"); | 639 | pr_err("cannot allocate pstore buffer\n"); |
614 | err = -ENOMEM; | 640 | err = -ENOMEM; |
615 | goto fail_clear; | 641 | goto fail_clear; |
616 | } | 642 | } |
643 | spin_lock_init(&cxt->pstore.buf_lock); | ||
644 | |||
645 | cxt->pstore.flags = PSTORE_FLAGS_DMESG; | ||
646 | if (cxt->console_size) | ||
647 | cxt->pstore.flags |= PSTORE_FLAGS_CONSOLE; | ||
648 | if (cxt->ftrace_size) | ||
649 | cxt->pstore.flags |= PSTORE_FLAGS_FTRACE; | ||
650 | if (cxt->pmsg_size) | ||
651 | cxt->pstore.flags |= PSTORE_FLAGS_PMSG; | ||
617 | 652 | ||
618 | err = pstore_register(&cxt->pstore); | 653 | err = pstore_register(&cxt->pstore); |
619 | if (err) { | 654 | if (err) { |
@@ -659,7 +694,6 @@ static int ramoops_remove(struct platform_device *pdev) | |||
659 | struct ramoops_context *cxt = &oops_cxt; | 694 | struct ramoops_context *cxt = &oops_cxt; |
660 | 695 | ||
661 | pstore_unregister(&cxt->pstore); | 696 | pstore_unregister(&cxt->pstore); |
662 | cxt->max_dump_cnt = 0; | ||
663 | 697 | ||
664 | kfree(cxt->pstore.buf); | 698 | kfree(cxt->pstore.buf); |
665 | cxt->pstore.bufsize = 0; | 699 | cxt->pstore.bufsize = 0; |
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c index 76c3f80efdfa..3975deec02f8 100644 --- a/fs/pstore/ram_core.c +++ b/fs/pstore/ram_core.c | |||
@@ -17,15 +17,16 @@ | |||
17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
18 | #include <linux/err.h> | 18 | #include <linux/err.h> |
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | 20 | #include <linux/init.h> |
22 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | #include <linux/kernel.h> | ||
23 | #include <linux/list.h> | 23 | #include <linux/list.h> |
24 | #include <linux/memblock.h> | 24 | #include <linux/memblock.h> |
25 | #include <linux/pstore_ram.h> | ||
25 | #include <linux/rslib.h> | 26 | #include <linux/rslib.h> |
26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/uaccess.h> | ||
27 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
28 | #include <linux/pstore_ram.h> | ||
29 | #include <asm/page.h> | 30 | #include <asm/page.h> |
30 | 31 | ||
31 | struct persistent_ram_buffer { | 32 | struct persistent_ram_buffer { |
@@ -47,43 +48,10 @@ static inline size_t buffer_start(struct persistent_ram_zone *prz) | |||
47 | return atomic_read(&prz->buffer->start); | 48 | return atomic_read(&prz->buffer->start); |
48 | } | 49 | } |
49 | 50 | ||
50 | /* increase and wrap the start pointer, returning the old value */ | ||
51 | static size_t buffer_start_add_atomic(struct persistent_ram_zone *prz, size_t a) | ||
52 | { | ||
53 | int old; | ||
54 | int new; | ||
55 | |||
56 | do { | ||
57 | old = atomic_read(&prz->buffer->start); | ||
58 | new = old + a; | ||
59 | while (unlikely(new >= prz->buffer_size)) | ||
60 | new -= prz->buffer_size; | ||
61 | } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old); | ||
62 | |||
63 | return old; | ||
64 | } | ||
65 | |||
66 | /* increase the size counter until it hits the max size */ | ||
67 | static void buffer_size_add_atomic(struct persistent_ram_zone *prz, size_t a) | ||
68 | { | ||
69 | size_t old; | ||
70 | size_t new; | ||
71 | |||
72 | if (atomic_read(&prz->buffer->size) == prz->buffer_size) | ||
73 | return; | ||
74 | |||
75 | do { | ||
76 | old = atomic_read(&prz->buffer->size); | ||
77 | new = old + a; | ||
78 | if (new > prz->buffer_size) | ||
79 | new = prz->buffer_size; | ||
80 | } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old); | ||
81 | } | ||
82 | |||
83 | static DEFINE_RAW_SPINLOCK(buffer_lock); | 51 | static DEFINE_RAW_SPINLOCK(buffer_lock); |
84 | 52 | ||
85 | /* increase and wrap the start pointer, returning the old value */ | 53 | /* increase and wrap the start pointer, returning the old value */ |
86 | static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a) | 54 | static size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a) |
87 | { | 55 | { |
88 | int old; | 56 | int old; |
89 | int new; | 57 | int new; |
@@ -103,7 +71,7 @@ static size_t buffer_start_add_locked(struct persistent_ram_zone *prz, size_t a) | |||
103 | } | 71 | } |
104 | 72 | ||
105 | /* increase the size counter until it hits the max size */ | 73 | /* increase the size counter until it hits the max size */ |
106 | static void buffer_size_add_locked(struct persistent_ram_zone *prz, size_t a) | 74 | static void buffer_size_add(struct persistent_ram_zone *prz, size_t a) |
107 | { | 75 | { |
108 | size_t old; | 76 | size_t old; |
109 | size_t new; | 77 | size_t new; |
@@ -124,9 +92,6 @@ exit: | |||
124 | raw_spin_unlock_irqrestore(&buffer_lock, flags); | 92 | raw_spin_unlock_irqrestore(&buffer_lock, flags); |
125 | } | 93 | } |
126 | 94 | ||
127 | static size_t (*buffer_start_add)(struct persistent_ram_zone *, size_t) = buffer_start_add_atomic; | ||
128 | static void (*buffer_size_add)(struct persistent_ram_zone *, size_t) = buffer_size_add_atomic; | ||
129 | |||
130 | static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, | 95 | static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, |
131 | uint8_t *data, size_t len, uint8_t *ecc) | 96 | uint8_t *data, size_t len, uint8_t *ecc) |
132 | { | 97 | { |
@@ -299,10 +264,20 @@ static void notrace persistent_ram_update(struct persistent_ram_zone *prz, | |||
299 | const void *s, unsigned int start, unsigned int count) | 264 | const void *s, unsigned int start, unsigned int count) |
300 | { | 265 | { |
301 | struct persistent_ram_buffer *buffer = prz->buffer; | 266 | struct persistent_ram_buffer *buffer = prz->buffer; |
302 | memcpy(buffer->data + start, s, count); | 267 | memcpy_toio(buffer->data + start, s, count); |
303 | persistent_ram_update_ecc(prz, start, count); | 268 | persistent_ram_update_ecc(prz, start, count); |
304 | } | 269 | } |
305 | 270 | ||
271 | static int notrace persistent_ram_update_user(struct persistent_ram_zone *prz, | ||
272 | const void __user *s, unsigned int start, unsigned int count) | ||
273 | { | ||
274 | struct persistent_ram_buffer *buffer = prz->buffer; | ||
275 | int ret = unlikely(__copy_from_user(buffer->data + start, s, count)) ? | ||
276 | -EFAULT : 0; | ||
277 | persistent_ram_update_ecc(prz, start, count); | ||
278 | return ret; | ||
279 | } | ||
280 | |||
306 | void persistent_ram_save_old(struct persistent_ram_zone *prz) | 281 | void persistent_ram_save_old(struct persistent_ram_zone *prz) |
307 | { | 282 | { |
308 | struct persistent_ram_buffer *buffer = prz->buffer; | 283 | struct persistent_ram_buffer *buffer = prz->buffer; |
@@ -322,8 +297,8 @@ void persistent_ram_save_old(struct persistent_ram_zone *prz) | |||
322 | } | 297 | } |
323 | 298 | ||
324 | prz->old_log_size = size; | 299 | prz->old_log_size = size; |
325 | memcpy(prz->old_log, &buffer->data[start], size - start); | 300 | memcpy_fromio(prz->old_log, &buffer->data[start], size - start); |
326 | memcpy(prz->old_log + size - start, &buffer->data[0], start); | 301 | memcpy_fromio(prz->old_log + size - start, &buffer->data[0], start); |
327 | } | 302 | } |
328 | 303 | ||
329 | int notrace persistent_ram_write(struct persistent_ram_zone *prz, | 304 | int notrace persistent_ram_write(struct persistent_ram_zone *prz, |
@@ -356,6 +331,38 @@ int notrace persistent_ram_write(struct persistent_ram_zone *prz, | |||
356 | return count; | 331 | return count; |
357 | } | 332 | } |
358 | 333 | ||
334 | int notrace persistent_ram_write_user(struct persistent_ram_zone *prz, | ||
335 | const void __user *s, unsigned int count) | ||
336 | { | ||
337 | int rem, ret = 0, c = count; | ||
338 | size_t start; | ||
339 | |||
340 | if (unlikely(!access_ok(VERIFY_READ, s, count))) | ||
341 | return -EFAULT; | ||
342 | if (unlikely(c > prz->buffer_size)) { | ||
343 | s += c - prz->buffer_size; | ||
344 | c = prz->buffer_size; | ||
345 | } | ||
346 | |||
347 | buffer_size_add(prz, c); | ||
348 | |||
349 | start = buffer_start_add(prz, c); | ||
350 | |||
351 | rem = prz->buffer_size - start; | ||
352 | if (unlikely(rem < c)) { | ||
353 | ret = persistent_ram_update_user(prz, s, start, rem); | ||
354 | s += rem; | ||
355 | c -= rem; | ||
356 | start = 0; | ||
357 | } | ||
358 | if (likely(!ret)) | ||
359 | ret = persistent_ram_update_user(prz, s, start, c); | ||
360 | |||
361 | persistent_ram_update_header_ecc(prz); | ||
362 | |||
363 | return unlikely(ret) ? ret : count; | ||
364 | } | ||
365 | |||
359 | size_t persistent_ram_old_size(struct persistent_ram_zone *prz) | 366 | size_t persistent_ram_old_size(struct persistent_ram_zone *prz) |
360 | { | 367 | { |
361 | return prz->old_log_size; | 368 | return prz->old_log_size; |
@@ -426,9 +433,6 @@ static void *persistent_ram_iomap(phys_addr_t start, size_t size, | |||
426 | return NULL; | 433 | return NULL; |
427 | } | 434 | } |
428 | 435 | ||
429 | buffer_start_add = buffer_start_add_locked; | ||
430 | buffer_size_add = buffer_size_add_locked; | ||
431 | |||
432 | if (memtype) | 436 | if (memtype) |
433 | va = ioremap(start, size); | 437 | va = ioremap(start, size); |
434 | else | 438 | else |
diff --git a/include/linux/pstore.h b/include/linux/pstore.h index 899e95e84400..92013cc9cc8c 100644 --- a/include/linux/pstore.h +++ b/include/linux/pstore.h | |||
@@ -22,12 +22,13 @@ | |||
22 | #ifndef _LINUX_PSTORE_H | 22 | #ifndef _LINUX_PSTORE_H |
23 | #define _LINUX_PSTORE_H | 23 | #define _LINUX_PSTORE_H |
24 | 24 | ||
25 | #include <linux/time.h> | 25 | #include <linux/compiler.h> |
26 | #include <linux/errno.h> | ||
26 | #include <linux/kmsg_dump.h> | 27 | #include <linux/kmsg_dump.h> |
27 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
28 | #include <linux/types.h> | ||
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/errno.h> | 30 | #include <linux/time.h> |
31 | #include <linux/types.h> | ||
31 | 32 | ||
32 | /* types */ | 33 | /* types */ |
33 | enum pstore_type_id { | 34 | enum pstore_type_id { |
@@ -68,13 +69,21 @@ struct pstore_info { | |||
68 | enum kmsg_dump_reason reason, u64 *id, | 69 | enum kmsg_dump_reason reason, u64 *id, |
69 | unsigned int part, const char *buf, bool compressed, | 70 | unsigned int part, const char *buf, bool compressed, |
70 | size_t size, struct pstore_info *psi); | 71 | size_t size, struct pstore_info *psi); |
72 | int (*write_buf_user)(enum pstore_type_id type, | ||
73 | enum kmsg_dump_reason reason, u64 *id, | ||
74 | unsigned int part, const char __user *buf, | ||
75 | bool compressed, size_t size, struct pstore_info *psi); | ||
71 | int (*erase)(enum pstore_type_id type, u64 id, | 76 | int (*erase)(enum pstore_type_id type, u64 id, |
72 | int count, struct timespec time, | 77 | int count, struct timespec time, |
73 | struct pstore_info *psi); | 78 | struct pstore_info *psi); |
74 | void *data; | 79 | void *data; |
75 | }; | 80 | }; |
76 | 81 | ||
77 | #define PSTORE_FLAGS_FRAGILE 1 | 82 | #define PSTORE_FLAGS_DMESG (1 << 0) |
83 | #define PSTORE_FLAGS_FRAGILE PSTORE_FLAGS_DMESG | ||
84 | #define PSTORE_FLAGS_CONSOLE (1 << 1) | ||
85 | #define PSTORE_FLAGS_FTRACE (1 << 2) | ||
86 | #define PSTORE_FLAGS_PMSG (1 << 3) | ||
78 | 87 | ||
79 | extern int pstore_register(struct pstore_info *); | 88 | extern int pstore_register(struct pstore_info *); |
80 | extern void pstore_unregister(struct pstore_info *); | 89 | extern void pstore_unregister(struct pstore_info *); |
diff --git a/include/linux/pstore_ram.h b/include/linux/pstore_ram.h index 4660aaa3195e..c668c861c96c 100644 --- a/include/linux/pstore_ram.h +++ b/include/linux/pstore_ram.h | |||
@@ -17,11 +17,12 @@ | |||
17 | #ifndef __LINUX_PSTORE_RAM_H__ | 17 | #ifndef __LINUX_PSTORE_RAM_H__ |
18 | #define __LINUX_PSTORE_RAM_H__ | 18 | #define __LINUX_PSTORE_RAM_H__ |
19 | 19 | ||
20 | #include <linux/compiler.h> | ||
20 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/init.h> | ||
21 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
22 | #include <linux/list.h> | 24 | #include <linux/list.h> |
23 | #include <linux/types.h> | 25 | #include <linux/types.h> |
24 | #include <linux/init.h> | ||
25 | 26 | ||
26 | struct persistent_ram_buffer; | 27 | struct persistent_ram_buffer; |
27 | struct rs_control; | 28 | struct rs_control; |
@@ -59,7 +60,9 @@ void persistent_ram_free(struct persistent_ram_zone *prz); | |||
59 | void persistent_ram_zap(struct persistent_ram_zone *prz); | 60 | void persistent_ram_zap(struct persistent_ram_zone *prz); |
60 | 61 | ||
61 | int persistent_ram_write(struct persistent_ram_zone *prz, const void *s, | 62 | int persistent_ram_write(struct persistent_ram_zone *prz, const void *s, |
62 | unsigned int count); | 63 | unsigned int count); |
64 | int persistent_ram_write_user(struct persistent_ram_zone *prz, | ||
65 | const void __user *s, unsigned int count); | ||
63 | 66 | ||
64 | void persistent_ram_save_old(struct persistent_ram_zone *prz); | 67 | void persistent_ram_save_old(struct persistent_ram_zone *prz); |
65 | size_t persistent_ram_old_size(struct persistent_ram_zone *prz); | 68 | size_t persistent_ram_old_size(struct persistent_ram_zone *prz); |