diff options
| author | Richard Purdie <rpurdie@rpsys.net> | 2008-01-29 05:21:56 -0500 |
|---|---|---|
| committer | David Woodhouse <dwmw2@infradead.org> | 2008-02-03 02:18:58 -0500 |
| commit | 47c152b88c185c7e97462a35893df6e552075a8c (patch) | |
| tree | 406c19685ebb030af09384bf2b59559a52810c0b | |
| parent | 6ce0a856c10c8ab8568764436864616efa88e908 (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>
| -rw-r--r-- | drivers/mtd/mtdoops.c | 28 |
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 | ||
| 329 | static int __init mtdoops_console_setup(struct console *co, char *options) | 357 | static int __init mtdoops_console_setup(struct console *co, char *options) |
