Skip to content

Commit

Permalink
[MTD] mtdoops: Ensure sequential write to the buffer
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Richard Purdie authored and David Woodhouse committed Feb 3, 2008
1 parent 6ce0a85 commit 47c152b
Showing 1 changed file with 28 additions and 0 deletions.
28 changes: 28 additions & 0 deletions drivers/mtd/mtdoops.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/mtd/mtd.h>

#define OOPS_PAGE_SIZE 4096
Expand All @@ -42,6 +43,9 @@ struct mtdoops_context {
int nextcount;

void *oops_buf;

/* writecount and disabling ready are spin lock protected */
spinlock_t writecount_lock;
int ready;
int writecount;
} oops_cxt;
Expand Down Expand Up @@ -290,11 +294,22 @@ static void mtdoops_console_sync(void)
{
struct mtdoops_context *cxt = &oops_cxt;
struct mtd_info *mtd = cxt->mtd;
unsigned long flags;

if (!cxt->ready || !mtd || cxt->writecount == 0)
return;

/*
* Once ready is 0 and we've held the lock no further writes to the
* buffer will happen
*/
spin_lock_irqsave(&cxt->writecount_lock, flags);
if (!cxt->ready) {
spin_unlock_irqrestore(&cxt->writecount_lock, flags);
return;
}
cxt->ready = 0;
spin_unlock_irqrestore(&cxt->writecount_lock, flags);

schedule_work(&cxt->work_write);
}
Expand All @@ -304,6 +319,7 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
{
struct mtdoops_context *cxt = co->data;
struct mtd_info *mtd = cxt->mtd;
unsigned long flags;

if (!oops_in_progress) {
mtdoops_console_sync();
Expand All @@ -313,6 +329,13 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)
if (!cxt->ready || !mtd)
return;

/* Locking on writecount ensures sequential writes to the buffer */
spin_lock_irqsave(&cxt->writecount_lock, flags);

/* Check ready status didn't change whilst waiting for the lock */
if (!cxt->ready)
return;

if (cxt->writecount == 0) {
u32 *stamp = cxt->oops_buf;
*stamp = cxt->nextcount;
Expand All @@ -324,6 +347,11 @@ mtdoops_console_write(struct console *co, const char *s, unsigned int count)

memcpy(cxt->oops_buf + cxt->writecount, s, count);
cxt->writecount += count;

spin_unlock_irqrestore(&cxt->writecount_lock, flags);

if (cxt->writecount == OOPS_PAGE_SIZE)
mtdoops_console_sync();
}

static int __init mtdoops_console_setup(struct console *co, char *options)
Expand Down

0 comments on commit 47c152b

Please sign in to comment.