diff options
-rw-r--r-- | drivers/acpi/apei/erst.c | 2 | ||||
-rw-r--r-- | drivers/firmware/efivars.c | 2 | ||||
-rw-r--r-- | fs/pstore/platform.c | 28 | ||||
-rw-r--r-- | include/linux/pstore.h | 2 |
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 | ||
129 | static struct kmsg_dumper pstore_dumper = { | 141 | static 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); |
207 | out: | 220 | out: |
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 | */ |
234 | int pstore_write(enum pstore_type_id type, char *buf, size_t size) | 247 | int 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 { | |||
32 | struct pstore_info { | 32 | struct 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); |