Commit 9bfeb691 authored by David Woodhouse's avatar David Woodhouse

[JFFS2] Switch to using an array of jffs2_raw_node_refs instead of a list.

This allows us to drop another pointer from the struct jffs2_raw_node_ref,
shrinking it to 8 bytes on 32-bit machines (if the TEST_TOTLEN) paranoia
check is turned off, which will be committed soon).
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent f75e5097
...@@ -285,20 +285,25 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, ...@@ -285,20 +285,25 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) void jffs2_free_jeb_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
{ {
struct jffs2_raw_node_ref *ref; struct jffs2_raw_node_ref *block, *ref;
D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset)); D1(printk(KERN_DEBUG "Freeing all node refs for eraseblock offset 0x%08x\n", jeb->offset));
while(jeb->first_node) {
ref = jeb->first_node;
jeb->first_node = ref->next_phys;
/* Remove from the inode-list */ block = ref = jeb->first_node;
if (ref->next_in_ino)
while (ref) {
if (ref->flash_offset == REF_LINK_NODE) {
ref = ref->next_in_ino;
jffs2_free_refblock(block);
block = ref;
continue;
}
if (ref->flash_offset != REF_EMPTY_NODE && ref->next_in_ino)
jffs2_remove_node_refs_from_ino_list(c, ref, jeb); jffs2_remove_node_refs_from_ino_list(c, ref, jeb);
/* else it was a non-inode node or already removed, so don't bother */ /* else it was a non-inode node or already removed, so don't bother */
__jffs2_free_raw_node_ref(ref); ref++;
} }
jeb->last_node = NULL; jeb->first_node = jeb->last_node = NULL;
} }
static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset) static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
......
...@@ -26,9 +26,6 @@ struct jffs2_inodirty; ...@@ -26,9 +26,6 @@ struct jffs2_inodirty;
struct jffs2_sb_info { struct jffs2_sb_info {
struct mtd_info *mtd; struct mtd_info *mtd;
struct jffs2_raw_node_ref *refs;
int reserved_refs;
uint32_t highest_ino; uint32_t highest_ino;
uint32_t checked_ino; uint32_t checked_ino;
......
...@@ -57,8 +57,8 @@ int __init jffs2_create_slab_caches(void) ...@@ -57,8 +57,8 @@ int __init jffs2_create_slab_caches(void)
if (!tmp_dnode_info_slab) if (!tmp_dnode_info_slab)
goto err; goto err;
raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", raw_node_ref_slab = kmem_cache_create("jffs2_refblock",
sizeof(struct jffs2_raw_node_ref), sizeof(struct jffs2_raw_node_ref) * (REFS_PER_BLOCK + 1),
0, 0, NULL, NULL); 0, 0, NULL, NULL);
if (!raw_node_ref_slab) if (!raw_node_ref_slab)
goto err; goto err;
...@@ -190,38 +190,65 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) ...@@ -190,38 +190,65 @@ void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x)
kmem_cache_free(tmp_dnode_info_slab, x); kmem_cache_free(tmp_dnode_info_slab, x);
} }
struct jffs2_raw_node_ref *jffs2_alloc_refblock(void)
{
struct jffs2_raw_node_ref *ret;
ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
if (ret) {
int i = 0;
for (i=0; i < REFS_PER_BLOCK; i++) {
ret[i].flash_offset = REF_EMPTY_NODE;
ret[i].next_in_ino = NULL;
}
ret[i].flash_offset = REF_LINK_NODE;
ret[i].next_in_ino = NULL;
}
return ret;
}
int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb, int nr) struct jffs2_eraseblock *jeb, int nr)
{ {
struct jffs2_raw_node_ref *p = c->refs; struct jffs2_raw_node_ref **p, *ref;
int i = nr;
dbg_memalloc("%d\n", nr); dbg_memalloc("%d\n", nr);
while (nr && p) { p = &jeb->last_node;
p = p->next_in_ino; ref = *p;
nr--;
} dbg_memalloc("Reserving %d refs for block @0x%08x\n", nr, jeb->offset);
while (nr) {
p = __jffs2_alloc_raw_node_ref(); /* If jeb->last_node is really a valid node then skip over it */
if (!p) if (ref && ref->flash_offset != REF_EMPTY_NODE)
return -ENOMEM; ref++;
p->next_in_ino = c->refs;
c->refs = p; while (i) {
nr--; if (!ref) {
dbg_memalloc("Allocating new refblock linked from %p\n", p);
ref = *p = jffs2_alloc_refblock();
if (!ref)
return -ENOMEM;
}
if (ref->flash_offset == REF_LINK_NODE) {
p = &ref->next_in_ino;
ref = *p;
continue;
}
i--;
ref++;
} }
c->reserved_refs = nr; jeb->allocated_refs = nr;
return 0;
}
struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void) dbg_memalloc("Reserved %d refs for block @0x%08x, last_node is %p (%08x,%p)\n",
{ nr, jeb->offset, jeb->last_node, jeb->last_node->flash_offset,
struct jffs2_raw_node_ref *ret; jeb->last_node->next_in_ino);
ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL);
dbg_memalloc("%p\n", ret); return 0;
return ret;
} }
void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) void jffs2_free_refblock(struct jffs2_raw_node_ref *x)
{ {
dbg_memalloc("%p\n", x); dbg_memalloc("%p\n", x);
kmem_cache_free(raw_node_ref_slab, x); kmem_cache_free(raw_node_ref_slab, x);
......
...@@ -954,18 +954,16 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) ...@@ -954,18 +954,16 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c)
for (i=0; i<c->nr_blocks; i++) { for (i=0; i<c->nr_blocks; i++) {
this = c->blocks[i].first_node; this = c->blocks[i].first_node;
while (this) { while (this) {
next = this->next_phys; if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE)
__jffs2_free_raw_node_ref(this); next = this[REFS_PER_BLOCK].next_in_ino;
else
next = NULL;
jffs2_free_refblock(this);
this = next; this = next;
} }
c->blocks[i].first_node = c->blocks[i].last_node = NULL; c->blocks[i].first_node = c->blocks[i].last_node = NULL;
} }
this = c->refs;
while (this) {
next = this->next_in_ino;
__jffs2_free_raw_node_ref(this);
this = next;
}
} }
struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset)
...@@ -1060,32 +1058,37 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, ...@@ -1060,32 +1058,37 @@ struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c,
{ {
struct jffs2_raw_node_ref *ref; struct jffs2_raw_node_ref *ref;
/* These will be preallocated _very_ shortly. */ BUG_ON(!jeb->allocated_refs);
ref = c->refs; jeb->allocated_refs--;
if (!c->refs) {
JFFS2_WARNING("Using non-preallocated refs!\n"); ref = jeb->last_node;
ref = __jffs2_alloc_raw_node_ref();
BUG_ON(!ref); dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset,
WARN_ON(1); ref->next_in_ino);
} else {
c->refs = ref->next_in_ino; while (ref->flash_offset != REF_EMPTY_NODE) {
if (ref->flash_offset == REF_LINK_NODE)
ref = ref->next_in_ino;
else
ref++;
} }
ref->next_phys = NULL; dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref,
ref->flash_offset, ofs, ref->next_in_ino, len);
ref->flash_offset = ofs; ref->flash_offset = ofs;
if (!jeb->first_node) if (!jeb->first_node) {
jeb->first_node = ref; jeb->first_node = ref;
if (jeb->last_node) { BUG_ON(ref_offset(ref) != jeb->offset);
jeb->last_node->next_phys = ref; } else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) {
#ifdef TEST_TOTLEN uint32_t last_len = ref_totlen(c, jeb, jeb->last_node);
if (ref_offset(jeb->last_node) + jeb->last_node->__totlen != ref_offset(ref)) {
printk(KERN_CRIT "Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n",
ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, ref, ref_offset(ref), ref_offset(ref)+len,
ref_offset(jeb->last_node), ref_offset(jeb->last_node)+jeb->last_node->__totlen); ref_offset(jeb->last_node),
WARN_ON(1); ref_offset(jeb->last_node)+last_len);
} BUG();
#endif
} }
jeb->last_node = ref; jeb->last_node = ref;
...@@ -1130,12 +1133,13 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ...@@ -1130,12 +1133,13 @@ int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
{ {
if (!size) if (!size)
return 0; return 0;
if (size > c->sector_size - jeb->used_size) { if (unlikely(size > jeb->free_size)) {
printk(KERN_CRIT "Dirty space 0x%x larger then used_size 0x%x (wasted 0x%x)\n", printk(KERN_CRIT "Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n",
size, jeb->used_size, jeb->wasted_size); size, jeb->free_size, jeb->wasted_size);
BUG(); BUG();
} }
if (jeb->last_node && ref_obsolete(jeb->last_node)) { /* REF_EMPTY_NODE is !obsolete, so that works OK */
if (ref_obsolete(jeb->last_node)) {
#ifdef TEST_TOTLEN #ifdef TEST_TOTLEN
jeb->last_node->__totlen += size; jeb->last_node->__totlen += size;
#endif #endif
...@@ -1168,7 +1172,7 @@ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, ...@@ -1168,7 +1172,7 @@ static inline uint32_t __ref_totlen(struct jffs2_sb_info *c,
jeb = &c->blocks[ref->flash_offset / c->sector_size]; jeb = &c->blocks[ref->flash_offset / c->sector_size];
/* Last node in block. Use free_space */ /* Last node in block. Use free_space */
if (ref != jeb->last_node) { if (unlikely(ref != jeb->last_node)) {
printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n", printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n",
ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0); ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0);
BUG(); BUG();
...@@ -1183,17 +1187,13 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je ...@@ -1183,17 +1187,13 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
{ {
uint32_t ret; uint32_t ret;
#if CONFIG_JFFS2_FS_DEBUG > 0
if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) {
printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n",
jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref));
BUG();
}
#endif
ret = __ref_totlen(c, jeb, ref); ret = __ref_totlen(c, jeb, ref);
#ifdef TEST_TOTLEN #ifdef TEST_TOTLEN
if (ret != ref->__totlen) { if (unlikely(ret != ref->__totlen)) {
if (!jeb)
jeb = &c->blocks[ref->flash_offset / c->sector_size];
printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n",
ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, ref, ref_offset(ref), ref_offset(ref)+ref->__totlen,
ret, ref->__totlen); ret, ref->__totlen);
...@@ -1204,13 +1204,14 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je ...@@ -1204,13 +1204,14 @@ uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node); printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node);
printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size); printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size);
ret = ref->__totlen;
if (!jeb)
jeb = &c->blocks[ref->flash_offset / c->sector_size];
#if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS)
__jffs2_dbg_dump_node_refs_nolock(c, jeb); __jffs2_dbg_dump_node_refs_nolock(c, jeb);
#endif #endif
WARN_ON(1); WARN_ON(1);
ret = ref->__totlen;
} }
#endif /* TEST_TOTLEN */ #endif /* TEST_TOTLEN */
return ret; return ret;
......
...@@ -80,7 +80,6 @@ struct jffs2_raw_node_ref ...@@ -80,7 +80,6 @@ struct jffs2_raw_node_ref
for this object. If this _is_ the last, it points to the inode_cache, for this object. If this _is_ the last, it points to the inode_cache,
xattr_ref or xattr_datum instead. The common part of those structures xattr_ref or xattr_datum instead. The common part of those structures
has NULL in the first word. See jffs2_raw_ref_to_ic() below */ has NULL in the first word. See jffs2_raw_ref_to_ic() below */
struct jffs2_raw_node_ref *next_phys;
uint32_t flash_offset; uint32_t flash_offset;
#define TEST_TOTLEN #define TEST_TOTLEN
#ifdef TEST_TOTLEN #ifdef TEST_TOTLEN
...@@ -88,7 +87,29 @@ struct jffs2_raw_node_ref ...@@ -88,7 +87,29 @@ struct jffs2_raw_node_ref
#endif #endif
}; };
#define ref_next(r) ((r)->next_phys) #define REF_LINK_NODE ((int32_t)-1)
#define REF_EMPTY_NODE ((int32_t)-2)
/* Use blocks of about 256 bytes */
#define REFS_PER_BLOCK ((255/sizeof(struct jffs2_raw_node_ref))-1)
static inline struct jffs2_raw_node_ref *ref_next(struct jffs2_raw_node_ref *ref)
{
ref++;
/* Link to another block of refs */
if (ref->flash_offset == REF_LINK_NODE) {
ref = ref->next_in_ino;
if (!ref)
return ref;
}
/* End of chain */
if (ref->flash_offset == REF_EMPTY_NODE)
return NULL;
return ref;
}
static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw) static inline struct jffs2_inode_cache *jffs2_raw_ref_to_ic(struct jffs2_raw_node_ref *raw)
{ {
...@@ -234,6 +255,7 @@ struct jffs2_eraseblock ...@@ -234,6 +255,7 @@ struct jffs2_eraseblock
uint32_t wasted_size; uint32_t wasted_size;
uint32_t free_size; /* Note that sector_size - free_size uint32_t free_size; /* Note that sector_size - free_size
is the address of the first free space */ is the address of the first free space */
uint32_t allocated_refs;
struct jffs2_raw_node_ref *first_node; struct jffs2_raw_node_ref *first_node;
struct jffs2_raw_node_ref *last_node; struct jffs2_raw_node_ref *last_node;
...@@ -378,10 +400,9 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void); ...@@ -378,10 +400,9 @@ struct jffs2_raw_inode *jffs2_alloc_raw_inode(void);
void jffs2_free_raw_inode(struct jffs2_raw_inode *); void jffs2_free_raw_inode(struct jffs2_raw_inode *);
struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void); struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void);
void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *); void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *);
int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c, int jffs2_prealloc_raw_node_refs(struct jffs2_sb_info *c,
struct jffs2_eraseblock *jeb, int nr); struct jffs2_eraseblock *jeb, int nr);
struct jffs2_raw_node_ref *__jffs2_alloc_raw_node_ref(void); void jffs2_free_refblock(struct jffs2_raw_node_ref *);
void __jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *);
struct jffs2_node_frag *jffs2_alloc_node_frag(void); struct jffs2_node_frag *jffs2_alloc_node_frag(void);
void jffs2_free_node_frag(struct jffs2_node_frag *); void jffs2_free_node_frag(struct jffs2_node_frag *);
struct jffs2_inode_cache *jffs2_alloc_inode_cache(void); struct jffs2_inode_cache *jffs2_alloc_inode_cache(void);
......
...@@ -458,14 +458,13 @@ static inline int on_list(struct list_head *obj, struct list_head *head) ...@@ -458,14 +458,13 @@ static inline int on_list(struct list_head *obj, struct list_head *head)
void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref)
{ {
struct jffs2_eraseblock *jeb; struct jffs2_eraseblock *jeb;
struct jffs2_raw_node_ref *next_ref;
int blocknr; int blocknr;
struct jffs2_unknown_node n; struct jffs2_unknown_node n;
int ret, addedsize; int ret, addedsize;
size_t retlen; size_t retlen;
uint32_t freed_len; uint32_t freed_len;
if(!ref) { if(unlikely(!ref)) {
printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n");
return; return;
} }
...@@ -683,54 +682,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref ...@@ -683,54 +682,6 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
spin_unlock(&c->erase_completion_lock); spin_unlock(&c->erase_completion_lock);
} }
/* Merge with the next node in the physical list, if there is one
and if it's also obsolete and if it doesn't belong to any inode */
next_ref = ref_next(ref);
if (next_ref && ref_obsolete(next_ref) && !next_ref->next_in_ino) {
spin_lock(&c->erase_completion_lock);
#ifdef TEST_TOTLEN
ref->__totlen += next_ref->__totlen;
#endif
ref->next_phys = ref_next(next_ref);
if (jeb->last_node == next_ref) jeb->last_node = ref;
if (jeb->gc_node == next_ref) {
/* gc will be happy continuing gc on this node */
jeb->gc_node=ref;
}
spin_unlock(&c->erase_completion_lock);
__jffs2_free_raw_node_ref(next_ref);
}
/* Also merge with the previous node in the list, if there is one
and that one is obsolete */
if (ref != jeb->first_node ) {
struct jffs2_raw_node_ref *p = jeb->first_node;
spin_lock(&c->erase_completion_lock);
while ((next_ref = ref_next(ref)) != ref)
p = next_ref;
if (ref_obsolete(p) && !ref->next_in_ino) {
#ifdef TEST_TOTLEN
p->__totlen += ref->__totlen;
#endif
if (jeb->last_node == ref) {
jeb->last_node = p;
}
if (jeb->gc_node == ref) {
/* gc will be happy continuing gc on this node */
jeb->gc_node=p;
}
p->next_phys = ref_next(ref);
__jffs2_free_raw_node_ref(ref);
}
spin_unlock(&c->erase_completion_lock);
}
out_erase_sem: out_erase_sem:
up(&c->erase_free_sem); up(&c->erase_free_sem);
} }
......
...@@ -95,6 +95,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) ...@@ -95,6 +95,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_dataflash(c) (0) #define jffs2_dataflash(c) (0)
#define jffs2_dataflash_setup(c) (0) #define jffs2_dataflash_setup(c) (0)
#define jffs2_dataflash_cleanup(c) do {} while (0) #define jffs2_dataflash_cleanup(c) do {} while (0)
#define jffs2_nor_wbuf_flash(c) (0)
#define jffs2_nor_wbuf_flash_setup(c) (0) #define jffs2_nor_wbuf_flash_setup(c) (0)
#define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0) #define jffs2_nor_wbuf_flash_cleanup(c) do {} while (0)
......
...@@ -511,7 +511,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -511,7 +511,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
spr = (struct jffs2_sum_xref_flash *)sp; spr = (struct jffs2_sum_xref_flash *)sp;
dbg_summary("xref at %#08x-%#08x\n", dbg_summary("xref at %#08x-%#08x\n",
jeb->offset + je32_to_cpu(spr->offset), jeb->offset + je32_to_cpu(spr->offset),
jeb->offset + je32_to_cpu(spr->offset) + PAD(sizeof(struct jffs2_raw_xref))); jeb->offset + je32_to_cpu(spr->offset) +
(uint32_t)PAD(sizeof(struct jffs2_raw_xref)));
ref = jffs2_alloc_xattr_ref(); ref = jffs2_alloc_xattr_ref();
if (!ref) { if (!ref) {
...@@ -787,10 +788,12 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock ...@@ -787,10 +788,12 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock
JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n",
infosize, sum_ofs, ret, retlen); infosize, sum_ofs, ret, retlen);
/* Waste remaining space */ if (retlen) {
spin_lock(&c->erase_completion_lock); /* Waste remaining space */
jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); spin_lock(&c->erase_completion_lock);
spin_unlock(&c->erase_completion_lock); jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL);
spin_unlock(&c->erase_completion_lock);
}
c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE;
...@@ -836,6 +839,7 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) ...@@ -836,6 +839,7 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c)
jffs2_sum_disable_collecting(c->summary); jffs2_sum_disable_collecting(c->summary);
JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize);
spin_lock(&c->erase_completion_lock);
return 0; return 0;
} }
......
...@@ -156,72 +156,126 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock ...@@ -156,72 +156,126 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
jffs2_erase_pending_trigger(c); jffs2_erase_pending_trigger(c);
} }
/* Adjust its size counts accordingly */ if (!jffs2_prealloc_raw_node_refs(c, jeb, 1)) {
c->wasted_size += jeb->free_size; uint32_t oldfree = jeb->free_size;
c->free_size -= jeb->free_size;
jeb->wasted_size += jeb->free_size; jffs2_link_node_ref(c, jeb,
jeb->free_size = 0; (jeb->offset+c->sector_size-oldfree) | REF_OBSOLETE,
oldfree, NULL);
/* convert to wasted */
c->wasted_size += oldfree;
jeb->wasted_size += oldfree;
c->dirty_size -= oldfree;
jeb->dirty_size -= oldfree;
}
jffs2_dbg_dump_block_lists_nolock(c); jffs2_dbg_dump_block_lists_nolock(c);
jffs2_dbg_acct_sanity_check_nolock(c,jeb); jffs2_dbg_acct_sanity_check_nolock(c,jeb);
jffs2_dbg_acct_paranoia_check_nolock(c, jeb); jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
} }
static struct jffs2_raw_node_ref **jffs2_incore_replace_raw(struct jffs2_sb_info *c,
struct jffs2_inode_info *f,
struct jffs2_raw_node_ref *raw,
union jffs2_node_union *node)
{
struct jffs2_node_frag *frag;
struct jffs2_full_dirent *fd;
dbg_noderef("incore_replace_raw: node at %p is {%04x,%04x}\n",
node, je16_to_cpu(node->u.magic), je16_to_cpu(node->u.nodetype));
BUG_ON(je16_to_cpu(node->u.magic) != 0x1985 &&
je16_to_cpu(node->u.magic) != 0);
switch (je16_to_cpu(node->u.nodetype)) {
case JFFS2_NODETYPE_INODE:
frag = jffs2_lookup_node_frag(&f->fragtree, je32_to_cpu(node->i.offset));
BUG_ON(!frag);
/* Find a frag which refers to the full_dnode we want to modify */
while (!frag->node || frag->node->raw != raw) {
frag = frag_next(frag);
BUG_ON(!frag);
}
dbg_noderef("Will replace ->raw in full_dnode at %p\n", frag->node);
return &frag->node->raw;
break;
case JFFS2_NODETYPE_DIRENT:
for (fd = f->dents; fd; fd = fd->next) {
if (fd->raw == raw) {
dbg_noderef("Will replace ->raw in full_dirent at %p\n", fd);
return &fd->raw;
}
}
BUG();
default:
dbg_noderef("Don't care about replacing raw for nodetype %x\n",
je16_to_cpu(node->u.nodetype));
break;
}
return NULL;
}
/* Recover from failure to write wbuf. Recover the nodes up to the /* Recover from failure to write wbuf. Recover the nodes up to the
* wbuf, not the one which we were starting to try to write. */ * wbuf, not the one which we were starting to try to write. */
static void jffs2_wbuf_recover(struct jffs2_sb_info *c) static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
{ {
struct jffs2_eraseblock *jeb, *new_jeb; struct jffs2_eraseblock *jeb, *new_jeb;
struct jffs2_raw_node_ref **first_raw, **raw; struct jffs2_raw_node_ref *raw, *next, *first_raw = NULL;
size_t retlen; size_t retlen;
int ret; int ret;
int nr_refile = 0;
unsigned char *buf; unsigned char *buf;
uint32_t start, end, ofs, len; uint32_t start, end, ofs, len;
jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
if (jffs2_prealloc_raw_node_refs(c, jeb, c->reserved_refs + 1))
return;
spin_lock(&c->erase_completion_lock); spin_lock(&c->erase_completion_lock);
jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
spin_unlock(&c->erase_completion_lock);
BUG_ON(!ref_obsolete(jeb->last_node));
/* Find the first node to be recovered, by skipping over every /* Find the first node to be recovered, by skipping over every
node which ends before the wbuf starts, or which is obsolete. */ node which ends before the wbuf starts, or which is obsolete. */
first_raw = &jeb->first_node; for (next = raw = jeb->first_node; next; raw = next) {
while (*first_raw && next = ref_next(raw);
(ref_obsolete(*first_raw) ||
(ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { if (ref_obsolete(raw) ||
D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", (next && ref_offset(next) <= c->wbuf_ofs)) {
ref_offset(*first_raw), ref_flags(*first_raw), dbg_noderef("Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n",
(ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)), ref_offset(raw), ref_flags(raw),
c->wbuf_ofs)); (ref_offset(raw) + ref_totlen(c, jeb, raw)),
first_raw = &(*first_raw)->next_phys; c->wbuf_ofs);
continue;
}
dbg_noderef("First node to be recovered is at 0x%08x(%d)-0x%08x\n",
ref_offset(raw), ref_flags(raw),
(ref_offset(raw) + ref_totlen(c, jeb, raw)));
first_raw = raw;
break;
} }
if (!*first_raw) { if (!first_raw) {
/* All nodes were obsolete. Nothing to recover. */ /* All nodes were obsolete. Nothing to recover. */
D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n"));
spin_unlock(&c->erase_completion_lock); c->wbuf_len = 0;
return; return;
} }
start = ref_offset(*first_raw); start = ref_offset(first_raw);
end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw); end = ref_offset(jeb->last_node);
nr_refile = 1;
/* Find the last node to be recovered */ /* Count the number of refs which need to be copied */
raw = first_raw; while ((raw = ref_next(raw)) != jeb->last_node)
while ((*raw)) { nr_refile++;
if (!ref_obsolete(*raw))
end = ref_offset(*raw) + ref_totlen(c, jeb, *raw);
raw = &(*raw)->next_phys; dbg_noderef("wbuf recover %08x-%08x (%d bytes in %d nodes)\n",
} start, end, end - start, nr_refile);
spin_unlock(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end));
buf = NULL; buf = NULL;
if (start < c->wbuf_ofs) { if (start < c->wbuf_ofs) {
...@@ -248,13 +302,24 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -248,13 +302,24 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
kfree(buf); kfree(buf);
buf = NULL; buf = NULL;
read_failed: read_failed:
first_raw = &(*first_raw)->next_phys; first_raw = ref_next(first_raw);
nr_refile--;
while (first_raw && ref_obsolete(first_raw)) {
first_raw = ref_next(first_raw);
nr_refile--;
}
/* If this was the only node to be recovered, give up */ /* If this was the only node to be recovered, give up */
if (!(*first_raw)) if (!first_raw) {
c->wbuf_len = 0;
return; return;
}
/* It wasn't. Go on and try to recover nodes complete in the wbuf */ /* It wasn't. Go on and try to recover nodes complete in the wbuf */
start = ref_offset(*first_raw); start = ref_offset(first_raw);
dbg_noderef("wbuf now recover %08x-%08x (%d bytes in %d nodes)\n",
start, end, end - start, nr_refile);
} else { } else {
/* Read succeeded. Copy the remaining data from the wbuf */ /* Read succeeded. Copy the remaining data from the wbuf */
memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs);
...@@ -263,7 +328,6 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -263,7 +328,6 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
/* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards.
Either 'buf' contains the data, or we find it in the wbuf */ Either 'buf' contains the data, or we find it in the wbuf */
/* ... and get an allocation of space from a shiny new block instead */ /* ... and get an allocation of space from a shiny new block instead */
ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE);
if (ret) { if (ret) {
...@@ -271,6 +335,14 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -271,6 +335,14 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
kfree(buf); kfree(buf);
return; return;
} }
ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, nr_refile);
if (ret) {
printk(KERN_WARNING "Failed to allocate node refs for wbuf recovery. Data loss ensues.\n");
kfree(buf);
return;
}
ofs = write_ofs(c); ofs = write_ofs(c);
if (end-start >= c->wbuf_pagesize) { if (end-start >= c->wbuf_pagesize) {
...@@ -304,7 +376,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -304,7 +376,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
kfree(buf); kfree(buf);
if (retlen) if (retlen)
jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, *first_raw), NULL); jffs2_add_physical_node_ref(c, ofs | REF_OBSOLETE, ref_totlen(c, jeb, first_raw), NULL);
return; return;
} }
...@@ -314,12 +386,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -314,12 +386,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
c->wbuf_ofs = ofs + towrite; c->wbuf_ofs = ofs + towrite;
memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len); memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
/* Don't muck about with c->wbuf_inodes. False positives are harmless. */ /* Don't muck about with c->wbuf_inodes. False positives are harmless. */
kfree(buf);
} else { } else {
/* OK, now we're left with the dregs in whichever buffer we're using */ /* OK, now we're left with the dregs in whichever buffer we're using */
if (buf) { if (buf) {
memcpy(c->wbuf, buf, end-start); memcpy(c->wbuf, buf, end-start);
kfree(buf);
} else { } else {
memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);
} }
...@@ -331,62 +401,111 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -331,62 +401,111 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
new_jeb = &c->blocks[ofs / c->sector_size]; new_jeb = &c->blocks[ofs / c->sector_size];
spin_lock(&c->erase_completion_lock); spin_lock(&c->erase_completion_lock);
if (new_jeb->first_node) { for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) {
/* Odd, but possible with ST flash later maybe */ uint32_t rawlen = ref_totlen(c, jeb, raw);
new_jeb->last_node->next_phys = *first_raw; struct jffs2_inode_cache *ic;
} else { struct jffs2_raw_node_ref *new_ref;
new_jeb->first_node = *first_raw; struct jffs2_raw_node_ref **adjust_ref = NULL;
} struct jffs2_inode_info *f = NULL;
raw = first_raw;
while (*raw) {
uint32_t rawlen = ref_totlen(c, jeb, *raw);
D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",
rawlen, ref_offset(*raw), ref_flags(*raw), ofs)); rawlen, ref_offset(raw), ref_flags(raw), ofs));
ic = jffs2_raw_ref_to_ic(raw);
/* Ick. This XATTR mess should be fixed shortly... */
if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) {
struct jffs2_xattr_datum *xd = (void *)ic;
BUG_ON(xd->node != raw);
adjust_ref = &xd->node;
raw->next_in_ino = NULL;
ic = NULL;
} else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) {
struct jffs2_xattr_datum *xr = (void *)ic;
BUG_ON(xr->node != raw);
adjust_ref = &xr->node;
raw->next_in_ino = NULL;
ic = NULL;
} else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) {
struct jffs2_raw_node_ref **p = &ic->nodes;
/* Remove the old node from the per-inode list */
while (*p && *p != (void *)ic) {
if (*p == raw) {
(*p) = (raw->next_in_ino);
raw->next_in_ino = NULL;
break;
}
p = &((*p)->next_in_ino);
}
if (ref_obsolete(*raw)) { if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) {
/* Shouldn't really happen much */ /* If it's an in-core inode, then we have to adjust any
new_jeb->dirty_size += rawlen; full_dirent or full_dnode structure to point to the
new_jeb->free_size -= rawlen; new version instead of the old */
c->dirty_size += rawlen; f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink);
} else { if (IS_ERR(f)) {
new_jeb->used_size += rawlen; /* Should never happen; it _must_ be present */
new_jeb->free_size -= rawlen; JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
ic->ino, PTR_ERR(f));
BUG();
}
/* We don't lock f->sem. There's a number of ways we could
end up in here with it already being locked, and nobody's
going to modify it on us anyway because we hold the
alloc_sem. We're only changing one ->raw pointer too,
which we can get away with without upsetting readers. */
adjust_ref = jffs2_incore_replace_raw(c, f, raw,
(void *)(buf?:c->wbuf) + (ref_offset(raw) - start));
} else if (unlikely(ic->state != INO_STATE_PRESENT &&
ic->state != INO_STATE_CHECKEDABSENT &&
ic->state != INO_STATE_GC)) {
JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state);
BUG();
}
}
new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic);
if (adjust_ref) {
BUG_ON(*adjust_ref != raw);
*adjust_ref = new_ref;
}
if (f)
jffs2_gc_release_inode(c, f);
if (!ref_obsolete(raw)) {
jeb->dirty_size += rawlen; jeb->dirty_size += rawlen;
jeb->used_size -= rawlen; jeb->used_size -= rawlen;
c->dirty_size += rawlen; c->dirty_size += rawlen;
c->used_size -= rawlen;
raw->flash_offset = ref_offset(raw) | REF_OBSOLETE;
BUG_ON(raw->next_in_ino);
} }
c->free_size -= rawlen;
(*raw)->flash_offset = ofs | ref_flags(*raw);
ofs += rawlen; ofs += rawlen;
new_jeb->last_node = *raw;
raw = &(*raw)->next_phys;
} }
kfree(buf);
/* Fix up the original jeb now it's on the bad_list */ /* Fix up the original jeb now it's on the bad_list */
*first_raw = NULL; if (first_raw == jeb->first_node) {
if (first_raw == &jeb->first_node) {
jeb->last_node = NULL;
D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));
list_del(&jeb->list); list_del(&jeb->list);
list_add(&jeb->list, &c->erase_pending_list); list_add(&jeb->list, &c->erase_pending_list);
c->nr_erasing_blocks++; c->nr_erasing_blocks++;
jffs2_erase_pending_trigger(c); jffs2_erase_pending_trigger(c);
} }
else
jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);
jffs2_dbg_acct_sanity_check_nolock(c, jeb); jffs2_dbg_acct_sanity_check_nolock(c, jeb);
jffs2_dbg_acct_paranoia_check_nolock(c, jeb); jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
jffs2_dbg_acct_sanity_check_nolock(c, new_jeb); jffs2_dbg_acct_sanity_check_nolock(c, new_jeb);
jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb); jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb);
spin_unlock(&c->erase_completion_lock); spin_unlock(&c->erase_completion_lock);
D1(printk(KERN_DEBUG "wbuf recovery completed OK\n")); D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len));
} }
/* Meaning of pad argument: /* Meaning of pad argument:
...@@ -400,6 +519,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ...@@ -400,6 +519,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
{ {
struct jffs2_eraseblock *wbuf_jeb;
int ret; int ret;
size_t retlen; size_t retlen;
...@@ -417,7 +537,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ...@@ -417,7 +537,8 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
if (!c->wbuf_len) /* already checked c->wbuf above */ if (!c->wbuf_len) /* already checked c->wbuf above */
return 0; return 0;
if (jffs2_prealloc_raw_node_refs(c, c->nextblock, c->reserved_refs + 1)) wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1))
return -ENOMEM; return -ENOMEM;
/* claim remaining space on the page /* claim remaining space on the page
...@@ -473,32 +594,29 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) ...@@ -473,32 +594,29 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
/* Adjust free size of the block if we padded. */ /* Adjust free size of the block if we padded. */
if (pad) { if (pad) {
struct jffs2_eraseblock *jeb;
uint32_t waste = c->wbuf_pagesize - c->wbuf_len; uint32_t waste = c->wbuf_pagesize - c->wbuf_len;
jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n", D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
(jeb==c->nextblock)?"next":"", jeb->offset)); (wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset));
/* wbuf_pagesize - wbuf_len is the amount of space that's to be /* wbuf_pagesize - wbuf_len is the amount of space that's to be
padded. If there is less free space in the block than that, padded. If there is less free space in the block than that,
something screwed up */ something screwed up */
if (jeb->free_size < waste) { if (wbuf_jeb->free_size < waste) {
printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
c->wbuf_ofs, c->wbuf_len, waste); c->wbuf_ofs, c->wbuf_len, waste);
printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
jeb->offset, jeb->free_size); wbuf_jeb->offset, wbuf_jeb->free_size);
BUG(); BUG();
} }
spin_lock(&c->erase_completion_lock); spin_lock(&c->erase_completion_lock);
jffs2_link_node_ref(c, jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL); jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL);
/* FIXME: that made it count as dirty. Convert to wasted */ /* FIXME: that made it count as dirty. Convert to wasted */
jeb->dirty_size -= waste; wbuf_jeb->dirty_size -= waste;
c->dirty_size -= waste; c->dirty_size -= waste;
jeb->wasted_size += waste; wbuf_jeb->wasted_size += waste;
c->wasted_size += waste; c->wasted_size += waste;
} else } else
spin_lock(&c->erase_completion_lock); spin_lock(&c->erase_completion_lock);
...@@ -758,7 +876,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, ...@@ -758,7 +876,8 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
* This is the entry for flash write. * This is the entry for flash write.
* Check, if we work on NAND FLASH, if so build an kvec and write it via vritev * Check, if we work on NAND FLASH, if so build an kvec and write it via vritev
*/ */
int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,
size_t *retlen, const u_char *buf)
{ {
struct kvec vecs[1]; struct kvec vecs[1];
...@@ -953,7 +1072,7 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -953,7 +1072,7 @@ int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblo
} }
D1(if (retval == 1) { D1(if (retval == 1) {
printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset);
printk(KERN_WARNING "OOB at %08x was ", offset); printk(KERN_WARNING "OOB at %08zx was ", offset);
for (i=0; i < oob_size; i++) { for (i=0; i < oob_size; i++) {
printk("%02x ", buf[i]); printk("%02x ", buf[i]);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment