aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/apei/erst.c2
-rw-r--r--drivers/firmware/efivars.c2
-rw-r--r--fs/pstore/platform.c28
-rw-r--r--include/linux/pstore.h2
4 files changed, 24 insertions, 10 deletions
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 2ca59dc69f7f..5e820ea35570 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -1165,7 +1165,7 @@ static int __init erst_init(void)
1165 goto err_release_erange; 1165 goto err_release_erange;
1166 1166
1167 buf = kmalloc(erst_erange.size, GFP_KERNEL); 1167 buf = kmalloc(erst_erange.size, GFP_KERNEL);
1168 mutex_init(&erst_info.buf_mutex); 1168 spin_lock_init(&erst_info.buf_lock);
1169 if (buf) { 1169 if (buf) {
1170 erst_info.buf = buf + sizeof(struct cper_pstore_record); 1170 erst_info.buf = buf + sizeof(struct cper_pstore_record);
1171 erst_info.bufsize = erst_erange.size - 1171 erst_info.bufsize = erst_erange.size -
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index eb80b549ed8d..be8bcb035e2a 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -978,7 +978,7 @@ int register_efivars(struct efivars *efivars,
978 if (efivars->efi_pstore_info.buf) { 978 if (efivars->efi_pstore_info.buf) {
979 efivars->efi_pstore_info.bufsize = 1024; 979 efivars->efi_pstore_info.bufsize = 1024;
980 efivars->efi_pstore_info.data = efivars; 980 efivars->efi_pstore_info.data = efivars;
981 mutex_init(&efivars->efi_pstore_info.buf_mutex); 981 spin_lock_init(&efivars->efi_pstore_info.buf_lock);
982 pstore_register(&efivars->efi_pstore_info); 982 pstore_register(&efivars->efi_pstore_info);
983 } 983 }
984 984
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index ca60ebcfb15f..0472924024cc 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -28,6 +28,7 @@
28#include <linux/timer.h> 28#include <linux/timer.h>
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/uaccess.h> 30#include <linux/uaccess.h>
31#include <linux/hardirq.h>
31#include <linux/workqueue.h> 32#include <linux/workqueue.h>
32 33
33#include "internal.h" 34#include "internal.h"
@@ -88,13 +89,20 @@ static void pstore_dump(struct kmsg_dumper *dumper,
88 u64 id; 89 u64 id;
89 int hsize; 90 int hsize;
90 unsigned int part = 1; 91 unsigned int part = 1;
92 unsigned long flags = 0;
93 int is_locked = 0;
91 94
92 if (reason < ARRAY_SIZE(reason_str)) 95 if (reason < ARRAY_SIZE(reason_str))
93 why = reason_str[reason]; 96 why = reason_str[reason];
94 else 97 else
95 why = "Unknown"; 98 why = "Unknown";
96 99
97 mutex_lock(&psinfo->buf_mutex); 100 if (in_nmi()) {
101 is_locked = spin_trylock(&psinfo->buf_lock);
102 if (!is_locked)
103 pr_err("pstore dump routine blocked in NMI, may corrupt error record\n");
104 } else
105 spin_lock_irqsave(&psinfo->buf_lock, flags);
98 oopscount++; 106 oopscount++;
99 while (total < kmsg_bytes) { 107 while (total < kmsg_bytes) {
100 dst = psinfo->buf; 108 dst = psinfo->buf;
@@ -123,7 +131,11 @@ static void pstore_dump(struct kmsg_dumper *dumper,
123 total += l1_cpy + l2_cpy; 131 total += l1_cpy + l2_cpy;
124 part++; 132 part++;
125 } 133 }
126 mutex_unlock(&psinfo->buf_mutex); 134 if (in_nmi()) {
135 if (is_locked)
136 spin_unlock(&psinfo->buf_lock);
137 } else
138 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
127} 139}
128 140
129static struct kmsg_dumper pstore_dumper = { 141static struct kmsg_dumper pstore_dumper = {
@@ -188,11 +200,12 @@ void pstore_get_records(int quiet)
188 enum pstore_type_id type; 200 enum pstore_type_id type;
189 struct timespec time; 201 struct timespec time;
190 int failed = 0, rc; 202 int failed = 0, rc;
203 unsigned long flags;
191 204
192 if (!psi) 205 if (!psi)
193 return; 206 return;
194 207
195 mutex_lock(&psinfo->buf_mutex); 208 spin_lock_irqsave(&psinfo->buf_lock, flags);
196 rc = psi->open(psi); 209 rc = psi->open(psi);
197 if (rc) 210 if (rc)
198 goto out; 211 goto out;
@@ -205,7 +218,7 @@ void pstore_get_records(int quiet)
205 } 218 }
206 psi->close(psi); 219 psi->close(psi);
207out: 220out:
208 mutex_unlock(&psinfo->buf_mutex); 221 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
209 222
210 if (failed) 223 if (failed)
211 printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n", 224 printk(KERN_WARNING "pstore: failed to load %d record(s) from '%s'\n",
@@ -233,7 +246,8 @@ static void pstore_timefunc(unsigned long dummy)
233 */ 246 */
234int pstore_write(enum pstore_type_id type, char *buf, size_t size) 247int pstore_write(enum pstore_type_id type, char *buf, size_t size)
235{ 248{
236 u64 id; 249 u64 id;
250 unsigned long flags;
237 251
238 if (!psinfo) 252 if (!psinfo)
239 return -ENODEV; 253 return -ENODEV;
@@ -241,13 +255,13 @@ int pstore_write(enum pstore_type_id type, char *buf, size_t size)
241 if (size > psinfo->bufsize) 255 if (size > psinfo->bufsize)
242 return -EFBIG; 256 return -EFBIG;
243 257
244 mutex_lock(&psinfo->buf_mutex); 258 spin_lock_irqsave(&psinfo->buf_lock, flags);
245 memcpy(psinfo->buf, buf, size); 259 memcpy(psinfo->buf, buf, size);
246 id = psinfo->write(type, 0, size, psinfo); 260 id = psinfo->write(type, 0, size, psinfo);
247 if (pstore_is_mounted()) 261 if (pstore_is_mounted())
248 pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf, 262 pstore_mkfile(PSTORE_TYPE_DMESG, psinfo->name, id, psinfo->buf,
249 size, CURRENT_TIME, psinfo); 263 size, CURRENT_TIME, psinfo);
250 mutex_unlock(&psinfo->buf_mutex); 264 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
251 265
252 return 0; 266 return 0;
253} 267}
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index cc03bbf5c4b8..b91440e64d6e 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -32,7 +32,7 @@ enum pstore_type_id {
32struct pstore_info { 32struct pstore_info {
33 struct module *owner; 33 struct module *owner;
34 char *name; 34 char *name;
35 struct mutex buf_mutex; /* serialize access to 'buf' */ 35 spinlock_t buf_lock; /* serialize access to 'buf' */
36 char *buf; 36 char *buf;
37 size_t bufsize; 37 size_t bufsize;
38 int (*open)(struct pstore_info *psi); 38 int (*open)(struct pstore_info *psi);