/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
* Copyright (C) 2004 Thomas Gleixner <tglx@linutronix.de>
*
* Created by David Woodhouse <dwmw2@infradead.org>
* Modified debugged and enhanced by Thomas Gleixner <tglx@linutronix.de>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mtd/mtd.h>
#include <linux/crc32.h>
#include <linux/mtd/nand.h>
#include <linux/jiffies.h>
#include "nodelist.h"
/* For testing write failures */
#undef BREAKME
#undef BREAKMEHEADER
#ifdef BREAKME
static unsigned char *brokenbuf;
#endif
#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
/* max. erase failures before we mark a block bad */
#define MAX_ERASE_FAILURES 2
struct jffs2_inodirty {
uint32_t ino;
struct jffs2_inodirty *next;
};
static struct jffs2_inodirty inodirty_nomem;
static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino)
{
struct jffs2_inodirty *this = c->wbuf_inodes;
/* If a malloc failed, consider _everything_ dirty */
if (this == &inodirty_nomem)
return 1;
/* If ino == 0, _any_ non-GC writes mean 'yes' */
if (this && !ino)
return 1;
/* Look to see if the inode in question is pending in the wbuf */
while (this) {
if (this->ino == ino)
return 1;
this = this->next;
}
return 0;
}
static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c)
{
struct jffs2_inodirty *this;
this = c->wbuf_inodes;
if (this != &inodirty_nomem) {
while (this) {
struct jffs2_inodirty *next = this->next;
kfree(this);
this = next;
}
}
c->wbuf_inodes = NULL;
}
static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
{
struct jffs2_inodirty *new;
/* Mark the superblock dirty so that kupdated will flush... */
jffs2_erase_pending_trigger(c);
if (jffs2_wbuf_pending_for_ino(c, ino))
return;
new = kmalloc(sizeof(*new), GFP_KERNEL);
if (!new) {
D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n"));
jffs2_clear_wbuf_ino_list(c);
c->wbuf_inodes = &inodirty_nomem;
return;
}
new->ino = ino;
new->next = c->wbuf_inodes;
c->wbuf_inodes = new;
return;
}
static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
{
struct list_head