aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdoops.c
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@rpsys.net>2008-01-29 05:21:56 -0500
committerDavid Woodhouse <dwmw2@infradead.org>2008-02-03 02:18:58 -0500
commit47c152b88c185c7e97462a35893df6e552075a8c (patch)
tree406c19685ebb030af09384bf2b59559a52810c0b /drivers/mtd/mtdoops.c
parent6ce0a856c10c8ab8568764436864616efa88e908 (diff)
[MTD] mtdoops: Ensure sequential write to the buffer
Add a spinlock to ensure writes to the mtdoops buffer memory are sequential and don't race. Signed-off-by: Richard Purdie <rpurdie@rpsys.net> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd/mtdoops.c')
-rw-r--r--drivers/mtd/mtdoops.c28
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c
index 72c434c61b0a..1687521b4aa4 100644
--- a/drivers/mtd/mtdoops.c
+++ b/drivers/mtd/mtdoops.c
@@ -28,6 +28,7 @@
28#include <linux/workqueue.h> 28#include <linux/workqueue.h>
29#include <linux/sched.h> 29#include <linux/sched.h>
30#include <linux/wait.h> 30#include <linux/wait.h>
31#include <linux/spinlock.h>
31#include <linux/mtd/mtd.h> 32#include <linux/mtd/mtd.h>
32 33
33#define OOPS_PAGE_SIZE 4096 34#define OOPS_PAGE_SIZE 4096
@@ -42,6 +43,9 @@ struct mtdoops_context {
42 int nextcount; 43 int nextcount;
43 44
44 void *oops_buf; 45 void *oops_buf;
46
47 /* writecount and disabling ready are spin lock protected */
48 spinlock_t writecount_lock;
45 int ready; 49 int ready;
46 int writecount; 50 int writecount;
47} oops_cxt; 51} oops_cxt;
@@ -290,11 +294,22 @@ static void mtdoops_console_sync(void)
290{ 294{
291 struct mtdoops_context *cxt = &oops_cxt; 295 struct mtdoops_context *cxt = &oops_cxt;
292 struct mtd_info *mtd = cxt->mtd; 296 struct mtd_info *mtd = cxt->mtd;
297 unsigned long flags;
293 298
294 if (!cxt->ready || !mtd || cxt->writecount == 0) 299 if (!cxt->ready || !mtd || cxt->writecount == 0)
295 return; 300 return;
296 301
302 /*
303 * Once ready is 0 and we've held the lock no further writes to the
304 * buffer will happen
305 */
306 spin_lock_irqsave(&cxt->writecount_lock, flags);
307 if (!cxt->ready) {
308 spin_unlock_irqrestore(&cxt->writecount_lock, flags);
309 return;
310 }
297 cxt->ready = 0; 311 cxt->ready = 0;
312 spin_unlock_irqrestore(&cxt->writecount_lock, flags);
298 313
299 schedule_work(&cxt->work_write); 314 schedule_work(&cxt->work_write);
300} 315}
@@ -304,6 +319,7 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
304{ 319{
305 struct mtdoops_context *cxt = co->data; 320 struct mtdoops_context *cxt = co->data;
306 struct mtd_info *mtd = cxt->mtd; 321 struct mtd_info *mtd = cxt->mtd;
322 unsigned long flags;
307 323
308 if (!oops_in_progress) { 324 if (!oops_in_progress) {
309 mtdoops_console_sync(); 325 mtdoops_console_sync();
@@ -313,6 +329,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
313 if (!cxt->ready || !mtd) 329 if (!cxt->ready || !mtd)
314 return; 330 return;
315 331
332 /* Locking on writecount ensures sequential writes to the buffer */
333 spin_lock_irqsave(&cxt->writecount_lock, flags);
334
335 /* Check ready status didn't change whilst waiting for the lock */
336 if (!cxt->ready)
337 return;
338
316 if (cxt->writecount == 0) { 339 if (cxt->writecount == 0) {
317 u32 *stamp = cxt->oops_buf; 340 u32 *stamp = cxt->oops_buf;
318 *stamp = cxt->nextcount; 341 *stamp = cxt->nextcount;
@@ -324,6 +347,11 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
324 347
325 memcpy(cxt->oops_buf + cxt->writecount, s, count); 348 memcpy(cxt->oops_buf + cxt->writecount, s, count);
326 cxt->writecount += count; 349 cxt->writecount += count;
350
351 spin_unlock_irqrestore(&cxt->writecount_lock, flags);
352
353 if (cxt->writecount == OOPS_PAGE_SIZE)
354 mtdoops_console_sync();
327} 355}
328 356
329static int __init mtdoops_console_setup(struct console *co, char *options) 357static int __init mtdoops_console_setup(struct console *co, char *options)