aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorDon Zickus <dzickus@redhat.com>2011-08-12 13:54:51 -0400
committerTony Luck <tony.luck@intel.com>2011-08-16 14:55:58 -0400
commitabd4d5587be911f63592537284dad78766d97d62 (patch)
tree50d88b64ded1189d6c816a1f90124a05354914ba /fs
parent6dda9266913ad57e09afc1a10d6473f10c806a63 (diff)
pstore: change mutex locking to spin_locks
pstore was using mutex locking to protect read/write access to the backend plug-ins. This causes problems when pstore is executed in an NMI context through panic() -> kmsg_dump(). This patch changes the mutex to a spin_lock_irqsave then also checks to see if we are in an NMI context. If we are in an NMI and can't get the lock, just print a message stating that and blow by the locking. All this is probably a hack around the bigger locking problem but it solves my current situation of trying to sleep in an NMI context. Tested by loading the lkdtm module and executing a HARDLOCKUP which will cause the machine to panic inside the nmi handler. Signed-off-by: Don Zickus <dzickus@redhat.com> Acked-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/pstore/platform.c28
1 files changed, 21 insertions, 7 deletions
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}