From 6507d38544a4108a5ca00ddb9132fff736e01fbb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 21 Oct 2004 03:05:56 +0100 Subject: [PATCH] JFFS2 updates - Reduce memory use by merging adjacent obsolete raw_node_refs - Error handling fixes - Respect kmalloc size limit in scan - NAND ECC updates Signed-Off-By: David Woodhouse --- fs/jffs2/dir.c | 3 +-- fs/jffs2/erase.c | 2 +- fs/jffs2/gc.c | 16 ++++++++----- fs/jffs2/nodelist.h | 13 +++++++---- fs/jffs2/nodemgmt.c | 55 ++++++++++++++++++++++++++++++++++++++++++++- fs/jffs2/scan.c | 8 +++++-- fs/jffs2/super.c | 2 +- fs/jffs2/wbuf.c | 8 +++---- 8 files changed, 86 insertions(+), 21 deletions(-) diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 561e37f3d6440..0ec0be3f0bbae 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: dir.c,v 1.82 2003/10/11 11:47:23 dwmw2 Exp $ + * $Id: dir.c,v 1.83 2004/10/19 07:48:44 havasi Exp $ * */ @@ -217,7 +217,6 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, dentry->d_name.name, dentry->d_name.len); if (ret) { - jffs2_clear_inode(inode); make_bad_inode(inode); iput(inode); jffs2_free_raw_inode(ri); diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index f6efdbabbf3e2..724e7ee0e82ee 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.60 2004/06/30 17:26:15 dbrown Exp $ + * $Id: erase.c,v 1.61 2004/10/20 23:59:49 dwmw2 Exp $ * */ diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index dc25d812a3c0f..93f6b27239c7c 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.136 2004/05/27 19:06:09 gleixner Exp $ + * $Id: gc.c,v 1.137 2004/07/20 13:44:55 dwmw2 Exp $ * */ @@ -359,10 +359,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) spin_unlock(&c->inocache_lock); f = jffs2_gc_fetch_inode(c, inum, nlink); - if (IS_ERR(f)) - return PTR_ERR(f); - if (!f) - return 0; + if (IS_ERR(f)) { + ret = PTR_ERR(f); + goto release_sem; + } + if (!f) { + ret = 0; + goto release_sem; + } ret = jffs2_garbage_collect_live(c, jeb, raw, f); @@ -824,7 +828,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct continue; } if (retlen != rawlen) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %u) reading header from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n", retlen, rawlen, ref_offset(raw)); continue; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index cea0c13901849..7b5f8822b7e47 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.119 2004/05/26 12:28:12 gleixner Exp $ + * $Id: nodelist.h,v 1.120 2004/10/07 15:11:54 havasi Exp $ * */ @@ -281,9 +281,14 @@ static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb) else if (!ref_obsolete(ref2)) \ my_used_size += ref_totlen(c, jeb, ref2); \ if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \ - printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ - ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ - jeb->last_node, ref_offset(jeb->last_node)); \ + if (!ref2->next_phys) \ + printk("ref for node at %p (phys %08x) has next_phys->%p (----), last_node->%p (phys %08x)\n", \ + ref2, ref_offset(ref2), ref2->next_phys, \ + jeb->last_node, ref_offset(jeb->last_node)); \ + else \ + printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ + ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ + jeb->last_node, ref_offset(jeb->last_node)); \ paranoia_failed_dump(jeb); \ BUG(); \ } \ diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 5043d1a6f3d16..322395b81ffe1 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.107 2003/11/26 15:30:58 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.109 2004/10/07 15:08:47 havasi Exp $ * */ @@ -549,6 +549,59 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } + + /* Nodes which have been marked obsolete no longer need to be + associated with any inode. Remove them from the per-inode list */ + if (ref->next_in_ino) { + struct jffs2_inode_cache *ic; + struct jffs2_raw_node_ref **p; + + ic = jffs2_raw_ref_to_ic(ref); + for (p = &ic->nodes; (*p) != ref; p = &((*p)->next_in_ino)) + ; + + *p = ref->next_in_ino; + ref->next_in_ino = NULL; + } + + + /* Merge with the next node in the physical list, if there is one + and if it's also obsolete. */ + if (ref->next_phys && ref_obsolete(ref->next_phys) ) { + struct jffs2_raw_node_ref *n = ref->next_phys; + + ref->__totlen += n->__totlen; + ref->next_phys = n->next_phys; + if (jeb->last_node == n) jeb->last_node = ref; + if (jeb->gc_node == n) { + /* gc will be happy continuing gc on this node */ + jeb->gc_node=ref; + } + BUG_ON(n->next_in_ino); + jffs2_free_raw_node_ref(n); + } + + /* 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; + + while (p->next_phys != ref) + p = p->next_phys; + + if (ref_obsolete(p) ) { + p->__totlen += ref->__totlen; + 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_phys; + jffs2_free_raw_node_ref(ref); + } + } } #if CONFIG_JFFS2_FS_DEBUG > 0 diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 67a1d1bce71d8..1ddd6bf1a3c9c 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.110 2004/06/17 17:15:31 gleixner Exp $ + * $Id: scan.c,v 1.112 2004/09/12 09:56:13 gleixner Exp $ * */ #include @@ -104,6 +104,10 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) else buf_size = PAGE_SIZE; + /* Respect kmalloc limitations */ + if (buf_size > 128*1024) + buf_size = 128*1024; + D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size)); flashbuf = kmalloc(buf_size, GFP_KERNEL); if (!flashbuf) @@ -237,7 +241,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) } #endif if (c->nr_erasing_blocks) { - if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { + if ( !c->used_size && ((c->nr_free_blocks+empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); ret = -EIO; diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 257a06ea0b3a8..30cc15eed7dd1 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.99 2004/08/24 07:59:57 dwmw2 Exp $ + * $Id: super.c,v 1.100 2004/10/21 00:03:50 dwmw2 Exp $ * */ diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 2470eef95ae5a..254f441647afa 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.70 2004/07/13 08:58:25 dwmw2 Exp $ + * $Id: wbuf.c,v 1.72 2004/09/11 19:22:43 gleixner Exp $ * */ @@ -225,7 +225,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) /* Do the read... */ ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); - if (ret == -EIO && retlen == c->wbuf_ofs - start) { + if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { /* ECC recovered */ ret = 0; } @@ -791,7 +791,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re if (!jffs2_can_mark_obsolete(c)) { ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); - if ( (ret == -EIO) && (*retlen == len) ) { + if ( (ret == -EBADMSG) && (*retlen == len) ) { printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", len, ofs); /* @@ -1047,7 +1047,7 @@ int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) { D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n")); /* Get the position of the free bytes */ - if (!oinfo->oobfree[0][0]) { + if (!oinfo->oobfree[0][1]) { printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep. Autoplacement selected and no empty space in oob\n"); return -ENOSPC; } -- 2.53.0