From 8fabed4a0f78623236c035de0984beeacb8096d8 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Wed, 19 Jan 2005 19:22:04 +0000 Subject: [JFFS2] Avoid warning for empty filesystems Avoid "Eep. No valid nodes for ino #1" message for just-created filesystem. Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- fs/jffs2/nodelist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index cd6a8bd13e0..3c6d93c8ea0 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $ + * $Id: nodelist.c,v 1.92 2005/01/19 19:22:00 tpoynor Exp $ * */ @@ -127,7 +127,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, valid_ref = jffs2_first_valid_node(f->inocache->nodes); - if (!valid_ref) + if (!valid_ref && (f->inocache->ino != 1)) printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino); while (valid_ref) { -- cgit v1.2.3-18-g5258 From e4803c30d64391d84635061eaebfc7d66de9d6ab Mon Sep 17 00:00:00 2001 From: Estelle Hammache Date: Mon, 24 Jan 2005 21:13:42 +0000 Subject: [JFFS2] Fix write buffer retry case Correction of retry case to avoid silent failure of rmdir when jffs2_wbuf_recover GCs the previous entry (+ corresponding dnode case). Signed-off-by: Estelle Hammache Signed-off-by: Thomas Gleixner --- fs/jffs2/write.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 80a5db54262..32c1efaf6a0 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: write.c,v 1.88 2005/01/24 21:13:39 hammache Exp $ * */ @@ -136,6 +136,21 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 raw->__totlen = PAD(sizeof(*ri)+datalen); raw->next_phys = NULL; + if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) + { + if (! retried) + { + BUG(); + } + else + { + D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, highest version %d -> updating dnode\n", + je32_to_cpu(ri->version), f->highest_version)); + ri->version = cpu_to_je32(++f->highest_version); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); + } + } + ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, (alloc_mode==ALLOC_GC)?0:f->inocache->ino); @@ -280,6 +295,22 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff raw->__totlen = PAD(sizeof(*rd)+namelen); raw->next_phys = NULL; + if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) + { + if (! retried) + { + BUG(); + } + else + { + D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, highest version %d -> updating dirent\n", + je32_to_cpu(rd->version), f->highest_version)); + rd->version = cpu_to_je32(++f->highest_version); + fd->version = je32_to_cpu(rd->version); + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); + } + } + ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); if (ret || (retlen != sizeof(*rd) + namelen)) { -- cgit v1.2.3-18-g5258 From 7f716cf3f9cc9dd420b9c75071559017812df6d2 Mon Sep 17 00:00:00 2001 From: Estelle Hammache Date: Mon, 24 Jan 2005 21:24:18 +0000 Subject: [JFFS2] Fix block refiling - block refiling when writing directly to flash a buffer which is bigger than wbuf - retry cases for flushing wbuf Signed-off-by: Estelle Hammache Signed-off-by: Thomas Gleixner --- fs/jffs2/wbuf.c | 65 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 18 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index c8128069ecf..4e583bfecf6 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.82 2004/11/20 22:08:31 dwmw2 Exp $ + * $Id: wbuf.c,v 1.83 2005/01/24 21:24:15 hammache Exp $ * */ @@ -130,7 +130,10 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) } } -static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +#define REFILE_NOTEMPTY 0 +#define REFILE_ANYWAY 1 + +static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty) { D1(printk("About to refile bad block at %08x\n", jeb->offset)); @@ -144,7 +147,8 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); list_add(&jeb->list, &c->bad_used_list); } else { - BUG(); + if (allow_empty == REFILE_NOTEMPTY) + BUG(); /* It has to have had some nodes or we couldn't be here */ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); list_add(&jeb->list, &c->erase_pending_list); @@ -179,7 +183,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; - jffs2_block_refile(c, jeb); + jffs2_block_refile(c, jeb, REFILE_NOTEMPTY); /* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ @@ -269,12 +273,12 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) return; } if (end-start >= c->wbuf_pagesize) { - /* Need to do another write immediately. This, btw, - means that we'll be writing from 'buf' and not from - the wbuf. Since if we're writing from the wbuf there - won't be more than a wbuf full of data, now will - there? :) */ - + /* Need to do another write immediately, but it's possible + that this is just because the wbuf itself is completely + full, and there's nothing earlier read back from the + flash. Hence 'buf' isn't necessarily what we're writing + from. */ + unsigned char *rewrite_buf = buf?:c->wbuf; uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", @@ -292,14 +296,15 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) #endif if (jffs2_cleanmarker_oob(c)) ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, - buf, NULL, c->oobinfo); + rewrite_buf, NULL, c->oobinfo); else - ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf); + ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); if (ret || retlen != towrite) { /* Argh. We tried. Really we did. */ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); - kfree(buf); + if (buf) + kfree(buf); if (retlen) { struct jffs2_raw_node_ref *raw2; @@ -321,10 +326,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) c->wbuf_len = (end - start) - towrite; c->wbuf_ofs = ofs + towrite; - memcpy(c->wbuf, 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. */ - - kfree(buf); + if (buf) + kfree(buf); } else { /* OK, now we're left with the dregs in whichever buffer we're using */ if (buf) { @@ -547,6 +552,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + /* retry flushing wbuf in case jffs2_wbuf_recover + left some data in the wbuf */ + if (ret) + { + ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + } up_write(&c->wbuf_sem); } else while (old_wbuf_len && old_wbuf_ofs == c->wbuf_ofs) { @@ -561,6 +572,12 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) down(&c->alloc_sem); down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + /* retry flushing wbuf in case jffs2_wbuf_recover + left some data in the wbuf */ + if (ret) + { + ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); + } up_write(&c->wbuf_sem); break; } @@ -580,6 +597,9 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); + /* retry - maybe wbuf recover left some data in wbuf. */ + if (ret) + ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); up_write(&c->wbuf_sem); return ret; @@ -762,9 +782,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, - c->wbuf is empty. + c->wbuf is empty. However refile nextblock to avoid + writing again to same address. */ - *retlen = donelen; + struct jffs2_eraseblock *jeb; + + spin_lock(&c->erase_completion_lock); + + jeb = &c->blocks[outvec_to / c->sector_size]; + jffs2_block_refile(c, jeb, REFILE_ANYWAY); + + *retlen = 0; + spin_unlock(&c->erase_completion_lock); goto exit; } -- cgit v1.2.3-18-g5258 From 3118db3dfe7c16284d1d578e628fd87639b00731 Mon Sep 17 00:00:00 2001 From: Estelle Hammache Date: Mon, 24 Jan 2005 21:30:25 +0000 Subject: [JFFS2] Fix refile of blocks due to write failure. avoid segfault when nextblock was refiled because of a write failure - avoid filing blocks on the clean list when they have wasted space Signed-off-by: Estelle Hammache Signed-off-by: Thomas Gleixner --- fs/jffs2/nodemgmt.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 2651135bdf4..b2a53879d3b 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.115 2004/11/22 11:07:21 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.116 2005/01/24 21:30:22 hammache Exp $ * */ @@ -308,7 +308,10 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); #if 1 - if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { + /* we could get some obsolete nodes after nextblock was refiled + in wbuf.c */ + if ( (c->nextblock || !ref_obsolete(new)) + &&(jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size))) { printk(KERN_WARNING "argh. node added in wrong place\n"); jffs2_free_raw_node_ref(new); return -EINVAL; @@ -332,7 +335,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r c->used_size += len; } - if (!jeb->free_size && !jeb->dirty_size) { + if (!jeb->free_size && !jeb->dirty_size && !jeb->wasted_size) { /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); -- cgit v1.2.3-18-g5258 From 9b88f47390efb72540b050628ebc04202d91c6ec Mon Sep 17 00:00:00 2001 From: Estelle Hammache Date: Fri, 28 Jan 2005 18:53:05 +0000 Subject: [JFFS2] Code cleanup Code beautification and block filing correction for optimization. Signed-off-by: Estelle Hammache Signed-off-by: Thomas Gleixner --- fs/jffs2/nodemgmt.c | 8 ++++---- fs/jffs2/wbuf.c | 23 ++++++++--------------- fs/jffs2/write.c | 44 ++++++++++++++++---------------------------- 3 files changed, 28 insertions(+), 47 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index b2a53879d3b..5e1e8caf54e 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.116 2005/01/24 21:30:22 hammache Exp $ + * $Id: nodemgmt.c,v 1.117 2005/01/25 20:11:11 hammache Exp $ * */ @@ -310,8 +310,8 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r #if 1 /* we could get some obsolete nodes after nextblock was refiled in wbuf.c */ - if ( (c->nextblock || !ref_obsolete(new)) - &&(jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size))) { + if ((c->nextblock || !ref_obsolete(new)) + &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) { printk(KERN_WARNING "argh. node added in wrong place\n"); jffs2_free_raw_node_ref(new); return -EINVAL; @@ -335,7 +335,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r c->used_size += len; } - if (!jeb->free_size && !jeb->dirty_size && !jeb->wasted_size) { + if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) { /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 4e583bfecf6..b43aac7496a 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.83 2005/01/24 21:24:15 hammache Exp $ + * $Id: wbuf.c,v 1.84 2005/01/25 20:11:11 hammache Exp $ * */ @@ -147,8 +147,7 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); list_add(&jeb->list, &c->bad_used_list); } else { - if (allow_empty == REFILE_NOTEMPTY) - BUG(); + BUG_ON(allow_empty == REFILE_NOTEMPTY); /* It has to have had some nodes or we couldn't be here */ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); list_add(&jeb->list, &c->erase_pending_list); @@ -268,16 +267,15 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); if (ret) { printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); - if (buf) - kfree(buf); + kfree(buf); return; } if (end-start >= c->wbuf_pagesize) { /* Need to do another write immediately, but it's possible - that this is just because the wbuf itself is completely - full, and there's nothing earlier read back from the - flash. Hence 'buf' isn't necessarily what we're writing - from. */ + that this is just because the wbuf itself is completely + full, and there's nothing earlier read back from the + flash. Hence 'buf' isn't necessarily what we're writing + from. */ unsigned char *rewrite_buf = buf?:c->wbuf; uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); @@ -303,8 +301,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) if (ret || retlen != towrite) { /* Argh. We tried. Really we did. */ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); - if (buf) - kfree(buf); + kfree(buf); if (retlen) { struct jffs2_raw_node_ref *raw2; @@ -555,9 +552,7 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) /* retry flushing wbuf in case jffs2_wbuf_recover left some data in the wbuf */ if (ret) - { ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); - } up_write(&c->wbuf_sem); } else while (old_wbuf_len && old_wbuf_ofs == c->wbuf_ofs) { @@ -575,9 +570,7 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) /* retry flushing wbuf in case jffs2_wbuf_recover left some data in the wbuf */ if (ret) - { ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING); - } up_write(&c->wbuf_sem); break; } diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index 32c1efaf6a0..d6b4d55e70e 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.88 2005/01/24 21:13:39 hammache Exp $ + * $Id: write.c,v 1.90 2005/01/28 18:53:01 hammache Exp $ * */ @@ -136,19 +136,13 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2 raw->__totlen = PAD(sizeof(*ri)+datalen); raw->next_phys = NULL; - if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) - { - if (! retried) - { - BUG(); - } - else - { - D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, highest version %d -> updating dnode\n", - je32_to_cpu(ri->version), f->highest_version)); - ri->version = cpu_to_je32(++f->highest_version); - ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - } + if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) { + BUG_ON(!retried); + D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, " + "highest version %d -> updating dnode\n", + je32_to_cpu(ri->version), f->highest_version)); + ri->version = cpu_to_je32(++f->highest_version); + ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); } ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, @@ -295,20 +289,14 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff raw->__totlen = PAD(sizeof(*rd)+namelen); raw->next_phys = NULL; - if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) - { - if (! retried) - { - BUG(); - } - else - { - D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, highest version %d -> updating dirent\n", - je32_to_cpu(rd->version), f->highest_version)); - rd->version = cpu_to_je32(++f->highest_version); - fd->version = je32_to_cpu(rd->version); - rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); - } + if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) { + BUG_ON(!retried); + D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, " + "highest version %d -> updating dirent\n", + je32_to_cpu(rd->version), f->highest_version)); + rd->version = cpu_to_je32(++f->highest_version); + fd->version = je32_to_cpu(rd->version); + rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); } ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, -- cgit v1.2.3-18-g5258 From 8aee6ac1446d6e2cb69908facbaccc0dfb4f1145 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 2 Feb 2005 22:12:08 +0000 Subject: [JFFS2] Remove NAND dependencies for NOR FLASH make NAND code work on NOR flash again Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- fs/jffs2/wbuf.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index b43aac7496a..4346940b487 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.84 2005/01/25 20:11:11 hammache Exp $ + * $Id: wbuf.c,v 1.85 2005/02/02 22:12:04 dwmw2 Exp $ * */ @@ -534,6 +534,9 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino)); + if (!c->wbuf) + return 0; + down(&c->alloc_sem); if (!jffs2_wbuf_pending_for_ino(c, ino)) { D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); @@ -588,6 +591,9 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) { int ret; + if (!c->wbuf) + return 0; + down_write(&c->wbuf_sem); ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); /* retry - maybe wbuf recover left some data in wbuf. */ -- cgit v1.2.3-18-g5258 From 67d9e95c393d23c229836e28b262dc73d71da784 Mon Sep 17 00:00:00 2001 From: Estelle Hammache Date: Sat, 5 Feb 2005 18:23:40 +0000 Subject: [JFFS2] Prevent deadlock during write buffer recovery Prevent deadlock when checking erased block for space allocation during wbuf recovery. Signed-off-by: Estelle Hammache Signed-off-by: Thomas Gleixner --- fs/jffs2/wbuf.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 4346940b487..79414abadd5 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.85 2005/02/02 22:12:04 dwmw2 Exp $ + * $Id: wbuf.c,v 1.86 2005/02/05 18:23:37 hammache Exp $ * */ @@ -865,7 +865,6 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re /* Read flash */ if (!jffs2_can_mark_obsolete(c)) { - down_read(&c->wbuf_sem); if (jffs2_cleanmarker_oob(c)) ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); @@ -892,11 +891,16 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) - goto exit; + return ret;; /* if we read in a different block, return */ if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) - goto exit; + return ret; + + /* Lock only if we have reason to believe wbuf contains relevant data, + so that checking an erased block during wbuf recovery space allocation + does not deadlock. */ + down_read(&c->wbuf_sem); if (ofs >= c->wbuf_ofs) { owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ -- cgit v1.2.3-18-g5258 From 3be36675d41a30ed3b192f92684f1417aa0f8bfe Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Wed, 9 Feb 2005 09:09:05 +0000 Subject: [JFFS2] Core changes required to support JFFS2-on-Dataflash devices. DataFlash page-sizes are not a power of two (they're multiples of 528 bytes). There are a few places in JFFS2 code where sector_size is used as a bitmask. A new macro (SECTOR_ADDR) was defined to calculate these sector addresses. For non-DataFlash devices, the original (faster) bitmask operation is still used. In scan.c, the EMPTY_SCAN_SIZE was a constant of 1024. Since this could be larger than the sector size of the DataFlash, this is now basically set to MIN(sector_size, 1024). Addition of a jffs2_is_writebuffered() macro. Signed-off-by: Andrew Victor Signed-off-by: Thomas Gleixner --- fs/jffs2/erase.c | 4 ++-- fs/jffs2/gc.c | 5 ++--- fs/jffs2/os-linux.h | 5 ++++- fs/jffs2/scan.c | 20 ++++++++++++----- fs/jffs2/wbuf.c | 63 ++++++++++++++++++++++++++--------------------------- 5 files changed, 53 insertions(+), 44 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 41451e8bf36..ae858f87887 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.66 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $ * */ @@ -233,7 +233,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, continue; } - if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) { + if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) { /* It's in the block we're erasing */ struct jffs2_raw_node_ref *this; diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 87ec74ff593..61ae001eced 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.144 2004/12/21 11:18:50 dwmw2 Exp $ + * $Id: gc.c,v 1.145 2005/02/09 09:09:01 pavlov Exp $ * */ @@ -816,8 +816,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct /* Doesn't matter if there's one in the same erase block. We're going to delete it too at the same time. */ - if ((raw->flash_offset & ~(c->sector_size-1)) == - (fd->raw->flash_offset & ~(c->sector_size-1))) + if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset)) continue; D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 03b0acc37b7..0412416d1f2 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $ * */ @@ -97,7 +97,10 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #endif } +#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) + #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) +#define jffs2_is_writebuffered(c) (c->wbuf != NULL) #if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) #define jffs2_can_mark_obsolete(c) (1) diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index ded53584a89..76859ff5343 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.115 2004/11/17 12:59:08 dedekind Exp $ + * $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $ * */ #include @@ -19,7 +19,7 @@ #include #include "nodelist.h" -#define EMPTY_SCAN_SIZE 1024 +#define DEFAULT_EMPTY_SCAN_SIZE 1024 #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ c->free_size -= _x; c->dirty_size += _x; \ @@ -75,6 +75,14 @@ static inline int min_free(struct jffs2_sb_info *c) return min; } + +static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { + if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) + return sector_size; + else + return DEFAULT_EMPTY_SCAN_SIZE; +} + int jffs2_scan_medium(struct jffs2_sb_info *c) { int i, ret; @@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo if (!buf_size) { buf_len = c->sector_size; } else { - buf_len = EMPTY_SCAN_SIZE; + buf_len = EMPTY_SCAN_SIZE(c->sector_size); err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); if (err) return err; @@ -326,10 +334,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ofs = 0; /* Scan only 4KiB of 0xFF before declaring it's empty */ - while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) + while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) ofs += 4; - if (ofs == EMPTY_SCAN_SIZE) { + if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { #ifdef CONFIG_JFFS2_FS_NAND if (jffs2_cleanmarker_oob(c)) { /* scan oob, take care of cleanmarker */ @@ -423,7 +431,7 @@ scan_more: bail now */ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) { - D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE)); + D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); return BLK_STATE_CLEANMARKER; } diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 79414abadd5..894dea88678 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.86 2005/02/05 18:23:37 hammache Exp $ + * $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $ * */ @@ -415,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) int ret; size_t retlen; - /* Nothing to do if not NAND flash. In particular, we shouldn't + /* Nothing to do if not write-buffering the flash. In particular, we shouldn't del_timer() the timer we never initialised. */ - if (jffs2_can_mark_obsolete(c)) + if (!jffs2_is_writebuffered(c)) return 0; if (!down_trylock(&c->alloc_sem)) { @@ -426,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) BUG(); } - if(!c->wbuf || !c->wbuf_len) + if (!c->wbuf_len) /* already checked c->wbuf above */ return 0; /* claim remaining space on the page @@ -620,7 +620,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig uint32_t outvec_to = to; /* If not NAND flash, don't bother */ - if (!c->wbuf) + if (!jffs2_is_writebuffered(c)) return jffs2_flash_direct_writev(c, invecs, count, to, retlen); down_write(&c->wbuf_sem); @@ -649,7 +649,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig erase block. Anything else, and you die. New block starts at xxx000c (0-b = block header) */ - if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) { + if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { /* It's a write to a new block */ if (c->wbuf_len) { D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); @@ -847,7 +847,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r { struct kvec vecs[1]; - if (jffs2_can_mark_obsolete(c)) + if (!jffs2_is_writebuffered(c)) return c->mtd->write(c->mtd, ofs, len, retlen, buf); vecs[0].iov_base = (unsigned char *) buf; @@ -863,38 +863,37 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re loff_t orbf = 0, owbf = 0, lwbf = 0; int ret; - /* Read flash */ - if (!jffs2_can_mark_obsolete(c)) { - - if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); - else - ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); - - if ( (ret == -EBADMSG) && (*retlen == len) ) { - printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", - len, ofs); - /* - * We have the raw data without ECC correction in the buffer, maybe - * we are lucky and all data or parts are correct. We check the node. - * If data are corrupted node check will sort it out. - * We keep this block, it will fail on write or erase and the we - * mark it bad. Or should we do that now? But we should give him a chance. - * Maybe we had a system crash or power loss before the ecc write or - * a erase was completed. - * So we return success. :) - */ - ret = 0; - } - } else + if (!jffs2_is_writebuffered(c)) return c->mtd->read(c->mtd, ofs, len, retlen, buf); + /* Read flash */ + if (jffs2_cleanmarker_oob(c)) + ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); + else + ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); + + if ( (ret == -EBADMSG) && (*retlen == len) ) { + printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", + len, ofs); + /* + * We have the raw data without ECC correction in the buffer, maybe + * we are lucky and all data or parts are correct. We check the node. + * If data are corrupted node check will sort it out. + * We keep this block, it will fail on write or erase and the we + * mark it bad. Or should we do that now? But we should give him a chance. + * Maybe we had a system crash or power loss before the ecc write or + * a erase was completed. + * So we return success. :) + */ + ret = 0; + } + /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) return ret;; /* if we read in a different block, return */ - if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) + if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) return ret; /* Lock only if we have reason to believe wbuf contains relevant data, -- cgit v1.2.3-18-g5258 From 8f15fd55f9bf266139b10850947e19c4e3f4e9b7 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Wed, 9 Feb 2005 09:17:45 +0000 Subject: [JFFS2] Add support for JFFS2-on-Dataflash devices. For Dataflash, can_mark_obsolete = false and the NAND write buffering code (wbuf.c) is used. Since the DataFlash chip will automatically erase pages when writing, the cleanmarkers are not needed - so cleanmarker_oob = false and cleanmarker_size = 0 DataFlash page-sizes are not a power of two (they're multiples of 528 bytes). The SECTOR_ADDR macro (added in the previous core patch) is replaced with a (slower) div/mod version if CONFIG_JFFS2_FS_DATAFLASH is selected. Signed-off-by: Andrew Victor Signed-off-by: Thomas Gleixner --- fs/Kconfig | 7 +++++++ fs/jffs2/Makefile | 3 ++- fs/jffs2/erase.c | 13 ++++++++++--- fs/jffs2/fs.c | 21 ++++++++++++++++++++- fs/jffs2/os-linux.h | 18 ++++++++++++++++-- fs/jffs2/scan.c | 11 +++++++---- fs/jffs2/wbuf.c | 35 ++++++++++++++++++++++++++++++++--- 7 files changed, 94 insertions(+), 14 deletions(-) (limited to 'fs') diff --git a/fs/Kconfig b/fs/Kconfig index 6a4ad4bb7a5..07835d24c78 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1084,6 +1084,13 @@ config JFFS2_FS_NOR_ECC ECC for JFFS2. This type of flash chip is not common, however it is available from ST Microelectronics. +config JFFS2_FS_DATAFLASH + bool "JFFS2 support for DataFlash (EXPERIMENTAL)" + depends on JFFS2_FS && EXPERIMENTAL + default n + help + This enables the experimental support for JFFS2 on DataFlash devices. + config JFFS2_COMPRESSION_OPTIONS bool "Advanced compression options for JFFS2" depends on JFFS2_FS diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index e3c38ccf9c7..6c2ebe176b4 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $ +# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o @@ -13,6 +13,7 @@ jffs2-y += super.o jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o +jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ae858f87887..a3c6cc15049 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.70 2005/02/09 09:09:01 pavlov Exp $ + * $Id: erase.c,v 1.71 2005/02/09 09:17:40 pavlov Exp $ * */ @@ -310,7 +310,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb int ret; uint32_t bad_offset; - if (!jffs2_cleanmarker_oob(c)) { + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) { marker_ref = jffs2_alloc_raw_node_ref(); if (!marker_ref) { printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); @@ -351,7 +351,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb bad_offset += i; printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); bad: - if (!jffs2_cleanmarker_oob(c)) + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) jffs2_free_raw_node_ref(marker_ref); kfree(ebuf); bad2: @@ -383,6 +383,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb jeb->first_node = jeb->last_node = NULL; + jeb->free_size = c->sector_size; + jeb->used_size = 0; + jeb->dirty_size = 0; + jeb->wasted_size = 0; + } else if (c->cleanmarker_size == 0) { + jeb->first_node = jeb->last_node = NULL; + jeb->free_size = c->sector_size; jeb->used_size = 0; jeb->dirty_size = 0; diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 30ab233fe42..5b7c960a047 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ + * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $ * */ @@ -456,6 +456,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) return -EINVAL; } #endif +#ifndef CONFIG_JFFS2_FS_DATAFLASH + if (c->mtd->type == MTD_DATAFLASH) { + printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); + return -EINVAL; + } +#endif c->flash_size = c->mtd->size; @@ -661,6 +667,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { if (ret) return ret; } + + /* and Dataflash */ + if (jffs2_dataflash(c)) { + ret = jffs2_dataflash_setup(c); + if (ret) + return ret; + } + return ret; } @@ -674,4 +688,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { if (jffs2_nor_ecc(c)) { jffs2_nor_ecc_flash_cleanup(c); } + + /* and DataFlash */ + if (jffs2_dataflash(c)) { + jffs2_dataflash_cleanup(c); + } } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 0412416d1f2..af27b84007a 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $ + * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $ * */ @@ -97,12 +97,16 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #endif } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) +#else #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) +#endif #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) #define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) +#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH) #define jffs2_can_mark_obsolete(c) (1) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -119,6 +123,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_wbuf_timeout NULL #define jffs2_wbuf_process NULL #define jffs2_nor_ecc(c) (0) +#define jffs2_dataflash(c) (0) #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) @@ -154,6 +159,15 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) #endif /* NOR ECC */ +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) +int jffs2_dataflash_setup(struct jffs2_sb_info *c); +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); +#else +#define jffs2_dataflash(c) (0) +#define jffs2_dataflash_setup(c) (0) +#define jffs2_dataflash_cleanup(c) do {} while (0) +#endif /* DATAFLASH */ #endif /* NAND */ /* erase.c */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 76859ff5343..e8c43746c82 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.116 2005/02/09 09:09:02 pavlov Exp $ + * $Id: scan.c,v 1.117 2005/02/09 09:17:41 pavlov Exp $ * */ #include @@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo static inline int min_free(struct jffs2_sb_info *c) { uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize; #endif @@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, @@ -351,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } #endif D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); - return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ + if (c->cleanmarker_size == 0) + return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */ + else + return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ } if (ofs) { D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 894dea88678..a35e007e5bf 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.87 2005/02/09 09:09:02 pavlov Exp $ + * $Id: wbuf.c,v 1.88 2005/02/09 09:17:41 pavlov Exp $ * */ @@ -435,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if we have a switch to next page, we will not have enough remaining space for this. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { c->wbuf_len = PAD(c->wbuf_len); /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR @@ -486,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) spin_lock(&c->erase_completion_lock); /* Adjust free size of the block if we padded. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { struct jffs2_eraseblock *jeb; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -604,8 +604,14 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#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) ) +#else #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) +#endif + int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) { struct kvec outvecs[3]; @@ -1192,6 +1198,29 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) kfree(c->wbuf); } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +int jffs2_dataflash_setup(struct jffs2_sb_info *c) { + c->cleanmarker_size = 0; /* No cleanmarkers needed */ + + /* Initialize write buffer */ + init_rwsem(&c->wbuf_sem); + c->wbuf_pagesize = c->sector_size; + c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf) + return -ENOMEM; + + printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); + + return 0; +} + +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { + kfree(c->wbuf); +} +#endif + #ifdef CONFIG_JFFS2_FS_NOR_ECC int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { /* Cleanmarker is actually larger on the flashes */ -- cgit v1.2.3-18-g5258 From 2f82ce1eb637c06dfc60f095cd1891ae0ba4894c Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Wed, 9 Feb 2005 09:24:26 +0000 Subject: [JFFS2] Use a single config option for write buffer support This patch replaces the current CONFIG_JFFS2_FS_NAND, CONFIG_JFFS2_FS_NOR_ECC and CONFIG_JFFS2_FS_DATAFLASH with a single configuration option - CONFIG_JFFS2_FS_WRITEBUFFER. The only functional change of this patch is that the slower div/mod calculations for SECTOR_ADDR(), PAGE_DIV() and PAGE_MOD() are now always used when CONFIG_JFFS2_FS_WRITEBUFFER is enabled. Signed-off-by: Andrew Victor Signed-off-by: Thomas Gleixner --- fs/Kconfig | 33 +++++++++------------------------ fs/jffs2/Makefile | 6 ++---- fs/jffs2/fs.c | 6 ++---- fs/jffs2/nodelist.h | 4 ++-- fs/jffs2/os-linux.h | 28 ++++++++-------------------- fs/jffs2/scan.c | 12 ++++++------ fs/jffs2/super.c | 4 ++-- fs/jffs2/wbuf.c | 8 ++------ 8 files changed, 33 insertions(+), 68 deletions(-) (limited to 'fs') diff --git a/fs/Kconfig b/fs/Kconfig index 07835d24c78..475769c25d6 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1063,33 +1063,18 @@ config JFFS2_FS_DEBUG If reporting bugs, please try to have available a full dump of the messages at debug level 1 while the misbehaviour was occurring. -config JFFS2_FS_NAND - bool "JFFS2 support for NAND flash" +config JFFS2_FS_WRITEBUFFER + bool "JFFS2 write-buffering support" depends on JFFS2_FS - default n + default y help - This enables the support for NAND flash in JFFS2. NAND is a newer - type of flash chip design than the traditional NOR flash, with - higher density but a handful of characteristics which make it more - interesting for the file system to use. + This enables the write-buffering support in JFFS2. - Say 'N' unless you have NAND flash. - -config JFFS2_FS_NOR_ECC - bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - This enables the experimental support for NOR flash with transparent - ECC for JFFS2. This type of flash chip is not common, however it is - available from ST Microelectronics. - -config JFFS2_FS_DATAFLASH - bool "JFFS2 support for DataFlash (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - This enables the experimental support for JFFS2 on DataFlash devices. + This functionality is required to support JFFS2 on the following + types of flash devices: + - NAND flash + - NOR flash with transparent ECC + - DataFlash config JFFS2_COMPRESSION_OPTIONS bool "Advanced compression options for JFFS2" diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 6c2ebe176b4..f1afe681ecd 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $ +# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o @@ -11,9 +11,7 @@ jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o jffs2-y += super.o -jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o -jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o -jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o +jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 5b7c960a047..c91c66e5e86 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $ + * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -450,13 +450,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) c = JFFS2_SB_INFO(sb); -#ifndef CONFIG_JFFS2_FS_NAND +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER if (c->mtd->type == MTD_NANDFLASH) { printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); return -EINVAL; } -#endif -#ifndef CONFIG_JFFS2_FS_DATAFLASH if (c->mtd->type == MTD_DATAFLASH) { printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); return -EINVAL; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index a4864d05ea9..8c122838bf6 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.126 2004/11/19 15:06:29 dedekind Exp $ + * $Id: nodelist.h,v 1.127 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -462,7 +462,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c); /* erase.c */ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* wbuf.c */ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index af27b84007a..8989cd685e4 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $ + * $Id: os-linux.h,v 1.54 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -97,16 +97,12 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #endif } -#ifdef CONFIG_JFFS2_FS_DATAFLASH -#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) -#else -#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) -#endif #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) #define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH) +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER +#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) #define jffs2_can_mark_obsolete(c) (1) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -129,6 +125,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #else /* NAND and/or ECC'd NOR support present */ +#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) @@ -150,25 +147,16 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); int jffs2_nand_flash_setup(struct jffs2_sb_info *c); void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); -#ifdef CONFIG_JFFS2_FS_NOR_ECC + #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC)) int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c); void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); -#else -#define jffs2_nor_ecc(c) (0) -#define jffs2_nor_ecc_flash_setup(c) (0) -#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) -#endif /* NOR ECC */ -#ifdef CONFIG_JFFS2_FS_DATAFLASH + #define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) int jffs2_dataflash_setup(struct jffs2_sb_info *c); void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); -#else -#define jffs2_dataflash(c) (0) -#define jffs2_dataflash_setup(c) (0) -#define jffs2_dataflash_cleanup(c) do {} while (0) -#endif /* DATAFLASH */ -#endif /* NAND */ + +#endif /* WRITEBUFFER */ /* erase.c */ static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index e8c43746c82..bc6c9998002 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.117 2005/02/09 09:17:41 pavlov Exp $ + * $Id: scan.c,v 1.118 2005/02/09 09:23:53 pavlov Exp $ * */ #include @@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo static inline int min_free(struct jffs2_sb_info *c) { uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize; #endif @@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { /* If we're going to start writing into a block which already contains data, and the end of the data isn't page-aligned, @@ -294,7 +294,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo uint32_t hdr_crc, buf_ofs, buf_len; int err; int noise = 0; -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER int cleanmarkerfound = 0; #endif @@ -303,7 +303,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (jffs2_cleanmarker_oob(c)) { int ret = jffs2_check_nand_cleanmarker(c, jeb); D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); @@ -338,7 +338,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ofs += 4; if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (jffs2_cleanmarker_oob(c)) { /* scan oob, take care of cleanmarker */ int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 6b2a441d276..3bfc121a467 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.104 2004/11/23 15:37:31 gleixner Exp $ + * $Id: super.c,v 1.105 2005/02/09 09:23:54 pavlov Exp $ * */ @@ -309,7 +309,7 @@ static int __init init_jffs2_fs(void) int ret; printk(KERN_INFO "JFFS2 version 2.2." -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" #endif " (C) 2001-2003 Red Hat, Inc.\n"); diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index a35e007e5bf..890258505a7 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.88 2005/02/09 09:17:41 pavlov Exp $ + * $Id: wbuf.c,v 1.89 2005/02/09 09:23:54 pavlov Exp $ * */ @@ -604,7 +604,7 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } -#ifdef CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER #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) ) #else @@ -1198,7 +1198,6 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) kfree(c->wbuf); } -#ifdef CONFIG_JFFS2_FS_DATAFLASH int jffs2_dataflash_setup(struct jffs2_sb_info *c) { c->cleanmarker_size = 0; /* No cleanmarkers needed */ @@ -1219,9 +1218,7 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } -#endif -#ifdef CONFIG_JFFS2_FS_NOR_ECC int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { /* Cleanmarker is actually larger on the flashes */ c->cleanmarker_size = 16; @@ -1241,4 +1238,3 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } -#endif -- cgit v1.2.3-18-g5258 From b81226c5d55b16a23f044d37b45e9b6909d8fbce Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Thu, 17 Feb 2005 17:51:17 +0000 Subject: [JFFS2] Fix node lookup Look the ref->next_phys field instead of ->next_in_ino to determine if the block has more then one node. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/scan.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index bc6c9998002..b63160f83ba 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.118 2005/02/09 09:23:53 pavlov Exp $ + * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $ * */ #include @@ -433,7 +433,7 @@ scan_more: /* If we're only checking the beginning of a block with a cleanmarker, bail now */ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && - c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) { + c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) { D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size))); return BLK_STATE_CLEANMARKER; } @@ -629,7 +629,7 @@ scan_more: } if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size - && (!jeb->first_node || !jeb->first_node->next_in_ino) ) + && (!jeb->first_node || !jeb->first_node->next_phys) ) return BLK_STATE_CLEANMARKER; /* move blocks with max 4 byte dirty space to cleanlist */ -- cgit v1.2.3-18-g5258 From 67e345d17ff8c2085a54c293001ae548f7be7b21 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 27 Feb 2005 23:01:36 +0000 Subject: [JFFS2] Prevent ino cache removal for inodes in use Don't remove inocache for inodes which are in read_inode() or clear_inode() until they're done. Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- fs/jffs2/erase.c | 7 ++----- fs/jffs2/nodelist.c | 13 ++++++++++--- fs/jffs2/nodelist.h | 3 ++- fs/jffs2/nodemgmt.c | 7 ++----- fs/jffs2/readinode.c | 10 ++++++++-- 5 files changed, 24 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index a3c6cc15049..d1ae565352a 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.71 2005/02/09 09:17:40 pavlov Exp $ + * $Id: erase.c,v 1.72 2005/02/27 23:01:32 dwmw2 Exp $ * */ @@ -277,11 +277,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, printk("\n"); }); - if (ic->nodes == (void *)ic) { - D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); + if (ic->nodes == (void *)ic) jffs2_del_ino_cache(c, ic); - jffs2_free_inode_cache(ic); - } } static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 3c6d93c8ea0..b835a865262 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.92 2005/01/19 19:22:00 tpoynor Exp $ + * $Id: nodelist.c,v 1.93 2005/02/27 23:01:32 dwmw2 Exp $ * */ @@ -506,7 +506,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) { struct jffs2_inode_cache **prev; - D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); + D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino)); spin_lock(&c->inocache_lock); prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE]; @@ -518,6 +518,14 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old) *prev = old->next; } + /* Free it now unless it's in READING or CLEARING state, which + are the transitions upon read_inode() and clear_inode(). The + rest of the time we know nobody else is looking at it, and + if it's held by read_inode() or clear_inode() they'll free it + for themselves. */ + if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING) + jffs2_free_inode_cache(old); + spin_unlock(&c->inocache_lock); } @@ -530,7 +538,6 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) this = c->inocache_list[i]; while (this) { next = this->next; - D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this)); jffs2_free_inode_cache(this); this = next; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 8c122838bf6..57f675c2c97 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.127 2005/02/09 09:23:53 pavlov Exp $ + * $Id: nodelist.h,v 1.128 2005/02/27 23:01:32 dwmw2 Exp $ * */ @@ -135,6 +135,7 @@ struct jffs2_inode_cache { #define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ #define INO_STATE_GC 4 /* GCing a 'pristine' node */ #define INO_STATE_READING 5 /* In read_inode() */ +#define INO_STATE_CLEARING 6 /* In clear_inode() */ #define INOCACHE_HASHSIZE 128 diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 5e1e8caf54e..f9dcac1415a 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.117 2005/01/25 20:11:11 hammache Exp $ + * $Id: nodemgmt.c,v 1.118 2005/02/27 23:01:32 dwmw2 Exp $ * */ @@ -593,11 +593,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *p = ref->next_in_ino; ref->next_in_ino = NULL; - if (ic->nodes == (void *)ic) { - D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino)); + if (ic->nodes == (void *)ic) jffs2_del_ino_cache(c, ic); - jffs2_free_inode_cache(ic); - } spin_unlock(&c->erase_completion_lock); } diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index aca4a0b17bc..a1980a9da53 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $ + * $Id: readinode.c,v 1.118 2005/02/27 23:01:33 dwmw2 Exp $ * */ @@ -672,6 +672,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) down(&f->sem); deleted = f->inocache && !f->inocache->nlink; + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING); + if (f->metadata) { if (deleted) jffs2_mark_node_obsolete(c, f->metadata->raw); @@ -688,8 +691,11 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_free_full_dirent(fd); } - if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); + if (f->inocache->nodes == (void *)f->inocache) + jffs2_del_ino_cache(c, f->inocache); + } up(&f->sem); } -- cgit v1.2.3-18-g5258 From 31fbdf7aa5aac8a2a34f180a25deb157297a10c9 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Mon, 28 Feb 2005 08:21:09 +0000 Subject: [JFFS2] Fix NOR specific scan BUG Fix fairly sad NOR-specific bug - during FS building ic->scan_dents isn't zero, but jffs2_mark_node_obsolete() migt be called it tries to finde the ic corresponding to ref - this requires ic->scan_dents = 0. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/build.c | 9 ++++++--- fs/jffs2/nodemgmt.c | 11 ++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a01dd5fdbb9..3dd5394921c 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $ + * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $ * */ @@ -97,14 +97,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) /* First, scan the medium and build all the inode caches with lists of physical nodes */ - c->flags |= JFFS2_SB_FLAG_MOUNTING; + c->flags |= JFFS2_SB_FLAG_SCANNING; ret = jffs2_scan_medium(c); + c->flags &= ~JFFS2_SB_FLAG_SCANNING; if (ret) goto exit; D1(printk(KERN_DEBUG "Scanned flash completely\n")); D2(jffs2_dump_block_lists(c)); + c->flags |= JFFS2_SB_FLAG_BUILDING; /* Now scan the directory tree, increasing nlink according to every dirent found. */ for_each_inode(i, c, ic) { D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); @@ -116,7 +118,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) cond_resched(); } } - c->flags &= ~JFFS2_SB_FLAG_MOUNTING; D1(printk(KERN_DEBUG "Pass 1 complete\n")); @@ -164,6 +165,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ic->scan_dents = NULL; cond_resched(); } + c->flags &= ~JFFS2_SB_FLAG_BUILDING; + D1(printk(KERN_DEBUG "Pass 3 complete\n")); D2(jffs2_dump_block_lists(c)); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index f9dcac1415a..456adf020f2 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.118 2005/02/27 23:01:32 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.119 2005/02/28 08:21:05 dedekind Exp $ * */ @@ -403,7 +403,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref jeb = &c->blocks[blocknr]; if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && - !(c->flags & JFFS2_SB_FLAG_MOUNTING)) { + !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { /* Hm. This may confuse static lock analysis. If any of the above three conditions is false, we're going to return from this function without actually obliterating any nodes or freeing @@ -470,8 +470,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref D1(ACCT_PARANOIA_CHECK(jeb)); - if (c->flags & JFFS2_SB_FLAG_MOUNTING) { - /* Mount in progress. Don't muck about with the block + if (c->flags & JFFS2_SB_FLAG_SCANNING) { + /* Flash scanning is in progress. Don't muck about with the block lists because they're not ready yet, and don't actually obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ @@ -530,7 +530,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_unlock(&c->erase_completion_lock); - if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) { + if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || + (c->flags & JFFS2_SB_FLAG_BUILDING)) { /* We didn't lock the erase_free_sem */ return; } -- cgit v1.2.3-18-g5258 From 32f1a95d505b99b1f01b6aeea36ec3f97245b357 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Tue, 1 Mar 2005 10:50:52 +0000 Subject: [JFFS2] Add symlink caching support. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/dir.c | 28 ++++++++++++++++++++------- fs/jffs2/read.c | 32 +------------------------------ fs/jffs2/readinode.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++------ fs/jffs2/symlink.c | 42 ++++++++++++++++++++++++++++------------ fs/jffs2/write.c | 31 ++++++++++++++++-------------- 5 files changed, 117 insertions(+), 70 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 757306fa3ff..6421be874ce 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.84 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: dir.c,v 1.85 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -296,11 +296,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char struct jffs2_full_dirent *fd; int namelen; uint32_t alloclen, phys_ofs; - int ret; + int ret, targetlen = strlen(target); /* FIXME: If you care. We'd need to use frags for the target if it grows much more than this */ - if (strlen(target) > 254) + if (targetlen > 254) return -EINVAL; ri = jffs2_alloc_raw_inode(); @@ -314,7 +314,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char * Just the node will do for now, though */ namelen = dentry->d_name.len; - ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL); + ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL); if (ret) { jffs2_free_raw_inode(ri); @@ -333,16 +333,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char f = JFFS2_INODE_INFO(inode); - inode->i_size = strlen(target); + inode->i_size = targetlen; ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); ri->compr = JFFS2_COMPR_NONE; - ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); + ri->data_crc = cpu_to_je32(crc32(0, target, targetlen)); ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); + fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL); jffs2_free_raw_inode(ri); @@ -353,6 +353,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char jffs2_clear_inode(inode); return PTR_ERR(fn); } + + /* We use f->dents field to store the target path. */ + f->dents = kmalloc(targetlen + 1, GFP_KERNEL); + if (!f->dents) { + printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1); + up(&f->sem); + jffs2_complete_reservation(c); + jffs2_clear_inode(inode); + return -ENOMEM; + } + + memcpy(f->dents, target, targetlen + 1); + D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents)); + /* No data here. Only a metadata node, which will be obsoleted by the first data write */ diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c index eb493dc06db..c7f9068907c 100644 --- a/fs/jffs2/read.c +++ b/fs/jffs2/read.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return 0; } -/* Core function to read symlink target. */ -char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) -{ - char *buf; - int ret; - - down(&f->sem); - - if (!f->metadata) { - printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); - up(&f->sem); - return ERR_PTR(-EINVAL); - } - buf = kmalloc(f->metadata->size+1, GFP_USER); - if (!buf) { - up(&f->sem); - return ERR_PTR(-ENOMEM); - } - buf[f->metadata->size]=0; - - ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size); - - up(&f->sem); - - if (ret) { - kfree(buf); - return ERR_PTR(ret); - } - return buf; -} diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index a1980a9da53..ef552477c81 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.118 2005/02/27 23:01:33 dwmw2 Exp $ + * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -623,6 +623,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, case. */ if (!je32_to_cpu(latest_node->isize)) latest_node->isize = latest_node->dsize; + + if (f->inocache->state != INO_STATE_CHECKING) { + /* Symlink's inode data is the target path. Read it and + * keep in RAM to facilitate quick follow symlink operation. + * We use f->dents field to store the target path, which + * is somewhat ugly. */ + f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL); + if (!f->dents) { + printk(KERN_WARNING "Can't allocate %d bytes of memory " + "for the symlink target path cache\n", + je32_to_cpu(latest_node->csize)); + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -ENOMEM; + } + + ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node), + je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents); + + if (ret || retlen != je32_to_cpu(latest_node->csize)) { + if (retlen != je32_to_cpu(latest_node->csize)) + ret = -EIO; + kfree(f->dents); + f->dents = NULL; + up(&f->sem); + jffs2_do_clear_inode(c, f); + return -ret; + } + + ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0'; + D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n", + (char *)f->dents)); + } + /* fall through... */ case S_IFBLK: @@ -683,12 +717,20 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); - fds = f->dents; + /* For symlink inodes we us f->dents to store the target path name */ + if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) { + if (f->dents) { + kfree(f->dents); + f->dents = NULL; + } + } else { + fds = f->dents; - while(fds) { - fd = fds; - fds = fd->next; - jffs2_free_full_dirent(fd); + while(fds) { + fd = fds; + fds = fd->next; + jffs2_free_full_dirent(fd); + } } if (f->inocache && f->inocache->state != INO_STATE_CHECKING) { diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 7b1820d1371..65ab6b001dc 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $ + * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $ * */ @@ -19,27 +19,45 @@ #include "nodelist.h" static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); -static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd); struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, - .put_link = jffs2_put_link, .setattr = jffs2_setattr }; static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd) { - unsigned char *buf; - buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); - nd_set_link(nd, buf); + struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); + + /* + * We don't acquire the f->sem mutex here since the only data we + * use is f->dents which in case of the symlink inode points to the + * symlink's target path. + * + * 1. If we are here the inode has already built and f->dents has + * to point to the target path. + * 2. Nobody uses f->dents (if the inode is symlink's inode). The + * exception is inode freeing function which frees f->dents. But + * it can't be called while we are here and before VFS has + * stopped using our f->dents string which we provide by means of + * nd_set_link() call. + */ + + if (!f->dents) { + printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n"); + return -EIO; + } + D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents)); + + nd_set_link(nd, (char *)f->dents); + + /* + * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe + * since the only way that may cause f->dents to be changed is iput() operation. + * But VFS will not use f->dents after iput() has been called. + */ return 0; } -static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd) -{ - char *s = nd_get_link(nd); - if (!IS_ERR(s)) - kfree(s); -} diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index d6b4d55e70e..f3910dc1c2c 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.90 2005/01/28 18:53:01 hammache Exp $ + * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $ * */ @@ -644,20 +644,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f, down(&dead_f->sem); - while (dead_f->dents) { - /* There can be only deleted ones */ - fd = dead_f->dents; - - dead_f->dents = fd->next; - - if (fd->ino) { - printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", - dead_f->inocache->ino, fd->name, fd->ino); - } else { - D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); + if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) { + while (dead_f->dents) { + /* There can be only deleted ones */ + fd = dead_f->dents; + + dead_f->dents = fd->next; + + if (fd->ino) { + printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", + dead_f->inocache->ino, fd->name, fd->ino); + } else { + D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", + fd->name, dead_f->inocache->ino)); + } + jffs2_mark_node_obsolete(c, fd->raw); + jffs2_free_full_dirent(fd); } - jffs2_mark_node_obsolete(c, fd->raw); - jffs2_free_full_dirent(fd); } dead_f->inocache->nlink--; -- cgit v1.2.3-18-g5258 From 4d9527096e2e5da7bec4b6a276fdb05086b6c395 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Fri, 18 Mar 2005 09:58:09 +0000 Subject: [JFFS2] Use function to manipulate superblock dirty flag Use the corresponding function to mark Superblock dirty instead of doing it directly. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/wbuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 890258505a7..0a7676819df 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.89 2005/02/09 09:23:54 pavlov Exp $ + * $Id: wbuf.c,v 1.91 2005/03/18 09:58:06 dedekind Exp $ * */ @@ -83,7 +83,7 @@ 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... */ - OFNI_BS_2SFFJ(c)->s_dirt = 1; + jffs2_erase_pending_trigger(c); if (jffs2_wbuf_pending_for_ino(c, ino)) return; -- cgit v1.2.3-18-g5258 From a42163d7c331c2532551f675d6616a00e1e87fe9 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Sun, 20 Mar 2005 17:45:29 +0000 Subject: [JFFS2] Improve garbage collector block selection Make sure the erase_pending_wbuf_list's blocks are taken into account when picking the block to GC. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/gc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 61ae001eced..44fa7379098 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.145 2005/02/09 09:09:01 pavlov Exp $ + * $Id: gc.c,v 1.146 2005/03/20 17:45:25 dedekind Exp $ * */ @@ -50,6 +50,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) put the clever wear-levelling algorithms. Eventually. */ /* We possibly want to favour the dirtier blocks more when the number of free blocks is low. */ +again: if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); nextlist = &c->bad_used_list; @@ -79,6 +80,11 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n")); nextlist = &c->erasable_list; + } else if (!list_empty(&c->erasable_pending_wbuf_list)) { + /* There are blocks are wating for the wbuf sync */ + D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n")); + jffs2_flush_wbuf_pad(c); + goto again; } else { /* Eep. All were empty */ D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n")); -- cgit v1.2.3-18-g5258 From 437316d9b5ea142ca7ab9ef131c28506c407d1d6 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Sun, 20 Mar 2005 17:46:23 +0000 Subject: [JFFS2] Forbid to free inode_cache objects if its nlink isn't zero. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/erase.c | 4 ++-- fs/jffs2/nodemgmt.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index d1ae565352a..bed6e1b8d82 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.72 2005/02/27 23:01:32 dwmw2 Exp $ + * $Id: erase.c,v 1.74 2005/03/20 17:46:20 dedekind Exp $ * */ @@ -277,7 +277,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c, printk("\n"); }); - if (ic->nodes == (void *)ic) + if (ic->nodes == (void *)ic && ic->nlink == 0) jffs2_del_ino_cache(c, ic); } diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index 456adf020f2..a8e19823123 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.119 2005/02/28 08:21:05 dedekind Exp $ + * $Id: nodemgmt.c,v 1.120 2005/03/20 17:46:20 dedekind Exp $ * */ @@ -594,7 +594,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *p = ref->next_in_ino; ref->next_in_ino = NULL; - if (ic->nodes == (void *)ic) + if (ic->nodes == (void *)ic && ic->nlink == 0) jffs2_del_ino_cache(c, ic); spin_unlock(&c->erase_completion_lock); -- cgit v1.2.3-18-g5258 From 3cceb9f6cf433545b607451e5de7af2cd6cec0b5 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Sun, 20 Mar 2005 21:43:26 +0000 Subject: [JFFS2] Prevent deadlock when flushing write buffer Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/gc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 44fa7379098..694bc90ad77 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.146 2005/03/20 17:45:25 dedekind Exp $ + * $Id: gc.c,v 1.147 2005/03/20 21:43:22 dedekind Exp $ * */ @@ -83,7 +83,9 @@ again: } else if (!list_empty(&c->erasable_pending_wbuf_list)) { /* There are blocks are wating for the wbuf sync */ D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n")); + spin_unlock(&c->erase_completion_lock); jffs2_flush_wbuf_pad(c); + spin_lock(&c->erase_completion_lock); goto again; } else { /* Eep. All were empty */ -- cgit v1.2.3-18-g5258 From 894214d1a75745a283d5f1921125b3ad36d7ba26 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Tue, 5 Apr 2005 13:51:58 +0100 Subject: [JFFS2] Fix race problems with wbuf. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/erase.c | 8 ++++++-- fs/jffs2/wbuf.c | 12 ++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index bed6e1b8d82..bb47673c1e5 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.74 2005/03/20 17:46:20 dedekind Exp $ + * $Id: erase.c,v 1.75 2005/04/05 12:51:54 dedekind Exp $ * */ @@ -332,7 +332,11 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb bad_offset = ofs; - ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); + if (!jffs2_is_writebuffered(c) || !jffs2_cleanmarker_oob(c)) + ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); + else + ret = c->mtd->read_ecc(c->mtd, ofs, readlen, &retlen, ebuf, NULL, c->oobinfo); + if (ret) { printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); goto bad; diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 0a7676819df..996d922e503 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.91 2005/03/18 09:58:06 dedekind Exp $ + * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $ * */ @@ -873,6 +873,7 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re return c->mtd->read(c->mtd, ofs, len, retlen, buf); /* Read flash */ + down_read(&c->wbuf_sem); if (jffs2_cleanmarker_oob(c)) ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); else @@ -896,16 +897,11 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) - return ret;; + goto exit; /* if we read in a different block, return */ if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs)) - return ret; - - /* Lock only if we have reason to believe wbuf contains relevant data, - so that checking an erased block during wbuf recovery space allocation - does not deadlock. */ - down_read(&c->wbuf_sem); + goto exit; if (ofs >= c->wbuf_ofs) { owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ -- cgit v1.2.3-18-g5258 From 6f401a40b5e46144e1ea361a5e2be428fb18a344 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Wed, 6 Apr 2005 17:02:55 +0100 Subject: [JFFS2] Add KERN_DEBUG level to printks Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/nodemgmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index a8e19823123..f695c01ece5 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.120 2005/03/20 17:46:20 dedekind Exp $ + * $Id: nodemgmt.c,v 1.121 2005/04/06 16:02:52 dedekind Exp $ * */ @@ -437,7 +437,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref // Take care, that wasted size is taken into concern if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) { - D1(printk("Dirtying\n")); + D1(printk(KERN_DEBUG "Dirtying\n")); addedsize = ref_totlen(c, jeb, ref); jeb->dirty_size += ref_totlen(c, jeb, ref); c->dirty_size += ref_totlen(c, jeb, ref); @@ -459,7 +459,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref } } } else { - D1(printk("Wasting\n")); + D1(printk(KERN_DEBUG "Wasting\n")); addedsize = 0; jeb->wasted_size += ref_totlen(c, jeb, ref); c->wasted_size += ref_totlen(c, jeb, ref); -- cgit v1.2.3-18-g5258 From 8557fd51c22e4c2109f062decd19de439061ceae Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Sat, 9 Apr 2005 11:47:03 +0100 Subject: [JFFS2] Fix race in garbage collector Fix the race problem described here: http://lists.infradead.org/pipermail/linux-mtd/2005-April/012361.html Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/gc.c | 30 ++++++++++++++++++++++++------ fs/jffs2/nodelist.h | 14 +++++++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 694bc90ad77..7086cd63450 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.147 2005/03/20 21:43:22 dedekind Exp $ + * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $ * */ @@ -669,9 +669,10 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; + struct jffs2_node_frag *last_frag; jint16_t dev; char *mdata = NULL, mdatalen = 0; - uint32_t alloclen, phys_ofs; + uint32_t alloclen, phys_ofs, ilen; int ret; if (S_ISBLK(JFFS2_F_I_MODE(f)) || @@ -707,6 +708,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ goto out; } + last_frag = frag_last(&f->fragtree); + if (last_frag) + /* Fetch the inode length from the fragtree rather then + * from i_size since i_size may have not been updated yet */ + ilen = last_frag->ofs + last_frag->size; + else + ilen = JFFS2_F_I_SIZE(f); + memset(&ri, 0, sizeof(ri)); ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); @@ -718,7 +727,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); - ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); + ri.isize = cpu_to_je32(ilen); ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); @@ -898,7 +907,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras struct jffs2_raw_inode ri; struct jffs2_node_frag *frag; struct jffs2_full_dnode *new_fn; - uint32_t alloclen, phys_ofs; + uint32_t alloclen, phys_ofs, ilen; int ret; D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", @@ -958,10 +967,19 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; } + + frag = frag_last(&f->fragtree); + if (frag) + /* Fetch the inode length from the fragtree rather then + * from i_size since i_size may have not been updated yet */ + ilen = frag->ofs + frag->size; + else + ilen = JFFS2_F_I_SIZE(f); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); - ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); + ri.isize = cpu_to_je32(ilen); ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); @@ -1168,7 +1186,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", orig_start, orig_end, start, end)); - BUG_ON(end > JFFS2_F_I_SIZE(f)); + D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); BUG_ON(end < orig_end); BUG_ON(start > orig_start); } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index 57f675c2c97..a65539f28b0 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.128 2005/02/27 23:01:32 dwmw2 Exp $ + * $Id: nodelist.h,v 1.130 2005/04/09 10:46:59 dedekind Exp $ * */ @@ -363,6 +363,18 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root) node = node->rb_left; return rb_entry(node, struct jffs2_node_frag, rb); } + +static inline struct jffs2_node_frag *frag_last(struct rb_root *root) +{ + struct rb_node *node = root->rb_node; + + if (!node) + return NULL; + while(node->rb_right) + node = node->rb_right; + return rb_entry(node, struct jffs2_node_frag, rb); +} + #define rb_parent(rb) ((rb)->rb_parent) #define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) #define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) -- cgit v1.2.3-18-g5258 From 7d200960d4f3d1b50c3b9e9688408d9f81c66ff4 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 13 Apr 2005 14:22:38 +0100 Subject: [JFFS2] Fix inode allocation race Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- fs/jffs2/README.Locking | 6 +++++- fs/jffs2/nodelist.c | 6 +++++- fs/jffs2/write.c | 7 +++---- 3 files changed, 13 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking index 49771cf8513..b7943439b6e 100644 --- a/fs/jffs2/README.Locking +++ b/fs/jffs2/README.Locking @@ -1,4 +1,4 @@ - $Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $ + $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $ JFFS2 LOCKING DOCUMENTATION --------------------------- @@ -108,6 +108,10 @@ in-core jffs2_inode_cache objects (each inode in JFFS2 has the correspondent jffs2_inode_cache object). So, the inocache_lock has to be locked while walking the c->inocache_list hash buckets. +This spinlock also covers allocation of new inode numbers, which is +currently just '++->highest_ino++', but might one day get more complicated +if we need to deal with wrapping after 4 milliard inode numbers are used. + Note, the f->sem guarantees that the correspondent jffs2_inode_cache will not be removed. So, it is allowed to access it without locking the inocache_lock spinlock. diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index b835a865262..c9157e1ea40 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.93 2005/02/27 23:01:32 dwmw2 Exp $ + * $Id: nodelist.c,v 1.94 2005/04/13 13:22:35 dwmw2 Exp $ * */ @@ -491,6 +491,10 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new struct jffs2_inode_cache **prev; D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); spin_lock(&c->inocache_lock); + if (!new->ino) + new->ino = ++c->highest_ino; + + D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c index f3910dc1c2c..69100615d9a 100644 --- a/fs/jffs2/write.c +++ b/fs/jffs2/write.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.91 2005/03/01 10:34:03 dedekind Exp $ + * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $ * */ @@ -35,13 +35,12 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint f->inocache = ic; f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; - f->inocache->ino = ++c->highest_ino; f->inocache->state = INO_STATE_PRESENT; - ri->ino = cpu_to_je32(f->inocache->ino); - D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); jffs2_add_ino_cache(c, f->inocache); + D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); + ri->ino = cpu_to_je32(f->inocache->ino); ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -- cgit v1.2.3-18-g5258 From 8cd79216676d9122fa714615e6b49553761aca8a Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Tue, 3 May 2005 16:19:02 +0100 Subject: [JFFS2] Fix NOR only compile Fix the bug that caouses problems when compiling for NOR. We read a newly erased block so we don't need to check ECC. Define jffs2_is_writebuffered as zero if there is no wbuf. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/erase.c | 7 ++----- fs/jffs2/os-linux.h | 5 +++-- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index bb47673c1e5..088faadf8f3 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.75 2005/04/05 12:51:54 dedekind Exp $ + * $Id: erase.c,v 1.76 2005/05/03 15:11:40 dedekind Exp $ * */ @@ -332,10 +332,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb bad_offset = ofs; - if (!jffs2_is_writebuffered(c) || !jffs2_cleanmarker_oob(c)) - ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); - else - ret = c->mtd->read_ecc(c->mtd, ofs, readlen, &retlen, ebuf, NULL, c->oobinfo); + ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); if (ret) { printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 8989cd685e4..5a2d2ee4f64 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.54 2005/02/09 09:23:53 pavlov Exp $ + * $Id: os-linux.h,v 1.56 2005/05/03 15:19:00 dedekind Exp $ * */ @@ -99,11 +99,11 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) -#define jffs2_is_writebuffered(c) (c->wbuf != NULL) #ifndef CONFIG_JFFS2_FS_WRITEBUFFER #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) #define jffs2_can_mark_obsolete(c) (1) +#define jffs2_is_writebuffered(c) (0) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -125,6 +125,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #else /* NAND and/or ECC'd NOR support present */ +#define jffs2_is_writebuffered(c) (c->wbuf != NULL) #define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) -- cgit v1.2.3-18-g5258 From 4132ace8d6f1b57839048548a17a0265f889aa3e Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Fri, 6 May 2005 10:30:30 +0100 Subject: [JFFS2] Suppress annoying debug messages Embrace uneeded messages in D1(). Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/nodemgmt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index f695c01ece5..c1d8b5ed9ab 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.121 2005/04/06 16:02:52 dedekind Exp $ + * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $ * */ @@ -75,7 +75,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; if (dirty < c->nospc_dirty_size) { if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { - printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"); + D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n")); break; } D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", @@ -98,7 +98,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; if ( (avail / c->sector_size) <= blocksneeded) { if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { - printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"); + D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n")); break; } -- cgit v1.2.3-18-g5258 From a69dde91e8940b49bdc9920dd65ec02c6a51f85c Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Wed, 18 May 2005 12:37:28 +0100 Subject: [JFFS2] Kill GC thread before cleanup First kill GC thread, then start clearing the internal structures Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 3bfc121a467..2cf14cf8b35 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.105 2005/02/09 09:23:54 pavlov Exp $ + * $Id: super.c,v 1.106 2005/05/18 11:37:25 dedekind Exp $ * */ @@ -270,8 +270,6 @@ static void jffs2_put_super (struct super_block *sb) D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); - if (!(sb->s_flags & MS_RDONLY)) - jffs2_stop_garbage_collect_thread(c); down(&c->alloc_sem); jffs2_flush_wbuf_pad(c); up(&c->alloc_sem); @@ -292,6 +290,8 @@ static void jffs2_put_super (struct super_block *sb) static void jffs2_kill_sb(struct super_block *sb) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); + if (!(sb->s_flags & MS_RDONLY)) + jffs2_stop_garbage_collect_thread(c); generic_shutdown_super(sb); put_mtd_device(c->mtd); kfree(c); -- cgit v1.2.3-18-g5258 From fff7afd791f6a685b3ddedb8cfb152aed85f3cf8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 19 May 2005 17:18:11 +0100 Subject: [JFFS2] Convert thread start semaphore to completion Signed-off-by: Thomas Gleixner --- fs/jffs2/background.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 1be6de27dd8..5548749bacb 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $ + * $Id: background.c,v 1.52 2005/05/19 16:18:08 gleixner Exp $ * */ @@ -37,7 +37,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) if (c->gc_task) BUG(); - init_MUTEX_LOCKED(&c->gc_thread_start); + init_completion(&c->gc_thread_start); init_completion(&c->gc_thread_exit); pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES); @@ -48,7 +48,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) } else { /* Wait for it... */ D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); - down(&c->gc_thread_start); + wait_for_completion(&c->gc_thread_start); } return ret; @@ -75,7 +75,7 @@ static int jffs2_garbage_collect_thread(void *_c) allow_signal(SIGCONT); c->gc_task = current; - up(&c->gc_thread_start); + complete(&c->gc_thread_start); set_user_nice(current, 10); -- cgit v1.2.3-18-g5258 From e2d48b1a98bb5da8d6998ca4db0b20fa46938a11 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 20 May 2005 22:37:15 +0100 Subject: [JFFS2] Fix cleanup in case of GC-Task not started Do not call wait_for_completion, when the gc task is not there. Prevent an oops when the gc thread was not started. Signed-off-by: Thomas Gleixner --- fs/jffs2/background.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 5548749bacb..65119d72cce 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: background.c,v 1.52 2005/05/19 16:18:08 gleixner Exp $ + * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $ * */ @@ -56,13 +56,16 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) { + int wait = 0; spin_lock(&c->erase_completion_lock); if (c->gc_task) { D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); send_sig(SIGKILL, c->gc_task, 1); + wait = 1; } spin_unlock(&c->erase_completion_lock); - wait_for_completion(&c->gc_thread_exit); + if (wait) + wait_for_completion(&c->gc_thread_exit); } static int jffs2_garbage_collect_thread(void *_c) -- cgit v1.2.3-18-g5258 From c84441c47d21d9291e780cdb5686e927dcd6f227 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 20 May 2005 20:30:09 +0100 Subject: [JFFS2] Fix crosscompile Include sched.h instead of asm/semaphore.h to make it compile everywhere. Signed-off-by: Thomas Gleixner --- fs/jffs2/compr_zlib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index 078a30e406b..83f7e0788fd 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $ * */ @@ -17,10 +17,10 @@ #include #include +#include #include #include #include -#include #include "nodelist.h" #include "compr.h" -- cgit v1.2.3-18-g5258 From 7d27c8143c8234e1cae8285fd2d43c19dad69bde Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 22 May 2005 21:47:19 +0200 Subject: [JFFS2] Whitespace cleanup. Fix missing debug message Signed-off-by: Thomas Gleixner --- fs/jffs2/erase.c | 1 + fs/jffs2/nodelist.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 088faadf8f3..6a4c0a3685d 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -48,6 +48,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c, #else /* Linux */ struct erase_info *instr; + D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size)); instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index c9157e1ea40..8a8e4b86382 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -489,13 +489,13 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new) { struct jffs2_inode_cache **prev; - D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); + spin_lock(&c->inocache_lock); - if (!new->ino) - new->ino = ++c->highest_ino; - - D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); - + if (!new->ino) + new->ino = ++c->highest_ino; + + D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino)); + prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE]; while ((*prev) && (*prev)->ino < new->ino) { -- cgit v1.2.3-18-g5258 From 9dee7503ce3fc38911b9873216619190cf688128 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 5 Jul 2005 22:03:10 +0100 Subject: [JFFS2] Optimise jffs2_add_tn_to_list Use an rbtree instead of a simple linked list. We were wasting an amazing amount of time in jffs2_add_tn_to_list(). Thanks to Artem Bityuckiy and Jarkko Jlavinen for noticing. Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- fs/jffs2/nodelist.c | 73 ++++++++++++++++++++++++++++++++++++++-------------- fs/jffs2/nodelist.h | 6 ++--- fs/jffs2/readinode.c | 36 ++++++++++++++++++++++---- 3 files changed, 88 insertions(+), 27 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 8a8e4b86382..be38cc5c35c 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.94 2005/04/13 13:22:35 dwmw2 Exp $ + * $Id: nodelist.c,v 1.95 2005/07/05 21:03:07 dwmw2 Exp $ * */ @@ -58,27 +58,61 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new /* Put a new tmp_dnode_info into the list, keeping the list in order of increasing version */ -static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) + +static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct rb_root *list) { - struct jffs2_tmp_dnode_info **prev = list; - - while ((*prev) && (*prev)->version < tn->version) { - prev = &((*prev)->next); - } - tn->next = (*prev); - *prev = tn; + struct rb_node **p = &list->rb_node; + struct rb_node * parent = NULL; + struct jffs2_tmp_dnode_info *this; + + while (*p) { + parent = *p; + this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); + + if (tn->version < this->version) + p = &(*p)->rb_left; + else if (tn->version > this->version) + p = &(*p)->rb_right; + else if (tn < this) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + rb_link_node(&tn->rb, parent, p); + rb_insert_color(&tn->rb, list); } -static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) +static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) { - struct jffs2_tmp_dnode_info *next; + struct rb_node *this; + struct jffs2_tmp_dnode_info *tn; + + this = list->rb_node; - while (tn) { - next = tn; - tn = tn->next; - jffs2_free_full_dnode(next->fn); - jffs2_free_tmp_dnode_info(next); + /* Now at bottom of tree */ + while (this) { + if (this->rb_left) + this = this->rb_left; + else if (this->rb_right) + this = this->rb_right; + else { + tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb); + jffs2_free_full_dnode(tn->fn); + jffs2_free_tmp_dnode_info(tn); + + this = this->rb_parent; + if (!this) + break; + + if (this->rb_left == &tn->rb) + this->rb_left = NULL; + else if (this->rb_right == &tn->rb) + this->rb_right = NULL; + else BUG(); + } } + list->rb_node = NULL; } static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) @@ -108,12 +142,13 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r with this ino, returning the former in order of version */ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, + struct rb_root *tnp, struct jffs2_full_dirent **fdp, uint32_t *highest_version, uint32_t *latest_mctime, uint32_t *mctime_ver) { struct jffs2_raw_node_ref *ref, *valid_ref; - struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL; + struct jffs2_tmp_dnode_info *tn; + struct rb_root ret_tn = RB_ROOT; struct jffs2_full_dirent *fd, *ret_fd = NULL; union jffs2_node_union node; size_t retlen; @@ -450,7 +485,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, return 0; free_out: - jffs2_free_tmp_dnode_info_list(ret_tn); + jffs2_free_tmp_dnode_info_list(&ret_tn); jffs2_free_full_dirent_list(ret_fd); return err; } diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index a65539f28b0..b34c397909e 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.130 2005/04/09 10:46:59 dedekind Exp $ + * $Id: nodelist.h,v 1.131 2005/07/05 21:03:07 dwmw2 Exp $ * */ @@ -161,7 +161,7 @@ struct jffs2_full_dnode */ struct jffs2_tmp_dnode_info { - struct jffs2_tmp_dnode_info *next; + struct rb_node rb; struct jffs2_full_dnode *fn; uint32_t version; }; @@ -387,7 +387,7 @@ static inline struct jffs2_node_frag *frag_last(struct rb_root *root) D2(void jffs2_print_frag_list(struct jffs2_inode_info *f)); void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, - struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, + struct rb_root *tnp, struct jffs2_full_dirent **fdp, uint32_t *highest_version, uint32_t *latest_mctime, uint32_t *mctime_ver); void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index ef552477c81..081656c1d49 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.119 2005/03/01 10:34:03 dedekind Exp $ + * $Id: readinode.c,v 1.120 2005/07/05 21:03:07 dwmw2 Exp $ * */ @@ -500,7 +500,9 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_raw_inode *latest_node) { - struct jffs2_tmp_dnode_info *tn_list, *tn; + struct jffs2_tmp_dnode_info *tn = NULL; + struct rb_root tn_list; + struct rb_node *rb, *repl_rb; struct jffs2_full_dirent *fd_list; struct jffs2_full_dnode *fn = NULL; uint32_t crc; @@ -522,9 +524,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, } f->dents = fd_list; - while (tn_list) { - tn = tn_list; + rb = rb_first(&tn_list); + while (rb) { + tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb); fn = tn->fn; if (f->metadata) { @@ -556,7 +559,30 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, mdata_ver = tn->version; } next_tn: - tn_list = tn->next; + BUG_ON(rb->rb_left); + repl_rb = NULL; + if (rb->rb_parent && rb->rb_parent->rb_left == rb) { + /* We were then left-hand child of our parent. We need + to move our own right-hand child into our place. */ + repl_rb = rb->rb_right; + if (repl_rb) + repl_rb->rb_parent = rb->rb_parent; + } else + repl_rb = NULL; + + rb = rb_next(rb); + + /* Remove the spent tn from the tree; don't bother rebalancing + but put our right-hand child in our own place. */ + if (tn->rb.rb_parent) { + if (tn->rb.rb_parent->rb_left == &tn->rb) + tn->rb.rb_parent->rb_left = repl_rb; + else if (tn->rb.rb_parent->rb_right == &tn->rb) + tn->rb.rb_parent->rb_right = repl_rb; + else BUG(); + } else if (tn->rb.rb_right) + tn->rb.rb_right->rb_parent = NULL; + jffs2_free_tmp_dnode_info(tn); } D1(jffs2_sanitycheck_fragtree(f)); -- cgit v1.2.3-18-g5258 From 265489f01d8c05f7aae174651a98854af090efc0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 6 Jul 2005 13:13:13 +0100 Subject: [JFFS2] Remove compatibilty cruft for ancient kernels Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- fs/jffs2/dir.c | 20 +++++--------------- fs/jffs2/file.c | 5 +---- fs/jffs2/fs.c | 5 +---- fs/jffs2/os-linux.h | 38 +------------------------------------- 4 files changed, 8 insertions(+), 60 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 6421be874ce..3ca0d25eef1 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.85 2005/03/01 10:34:03 dedekind Exp $ + * $Id: dir.c,v 1.86 2005/07/06 12:13:09 dwmw2 Exp $ * */ @@ -22,16 +22,6 @@ #include #include "nodelist.h" -/* Urgh. Please tell me there's a nicer way of doing these. */ -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) -typedef int mknod_arg_t; -#define NAMEI_COMPAT(x) ((void *)x) -#else -typedef dev_t mknod_arg_t; -#define NAMEI_COMPAT(x) (x) -#endif - static int jffs2_readdir (struct file *, void *, filldir_t); static int jffs2_create (struct inode *,struct dentry *,int, @@ -43,7 +33,7 @@ static int jffs2_unlink (struct inode *,struct dentry *); static int jffs2_symlink (struct inode *,struct dentry *,const char *); static int jffs2_mkdir (struct inode *,struct dentry *,int); static int jffs2_rmdir (struct inode *,struct dentry *); -static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t); +static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); static int jffs2_rename (struct inode *, struct dentry *, struct inode *, struct dentry *); @@ -58,8 +48,8 @@ struct file_operations jffs2_dir_operations = struct inode_operations jffs2_dir_inode_operations = { - .create = NAMEI_COMPAT(jffs2_create), - .lookup = NAMEI_COMPAT(jffs2_lookup), + .create = jffs2_create, + .lookup = jffs2_lookup, .link = jffs2_link, .unlink = jffs2_unlink, .symlink = jffs2_symlink, @@ -578,7 +568,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry) return ret; } -static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev) +static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 771a554701d..bd9ed9b0247 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -7,11 +7,10 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $ + * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $ * */ -#include #include #include #include @@ -51,9 +50,7 @@ struct file_operations jffs2_file_operations = .ioctl = jffs2_ioctl, .mmap = generic_file_readonly_mmap, .fsync = jffs2_fsync, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29) .sendfile = generic_file_sendfile -#endif }; /* jffs2_file_inode_operations */ diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index c91c66e5e86..5687c3f4200 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,11 +7,10 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $ + * $Id: fs.c,v 1.56 2005/07/06 12:13:09 dwmw2 Exp $ * */ -#include #include #include #include @@ -526,9 +525,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) goto out_root_i; -#if LINUX_VERSION_CODE >= 0x20403 sb->s_maxbytes = 0xFFFFFFFF; -#endif sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = JFFS2_SUPER_MAGIC; diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 5a2d2ee4f64..7bf72e012c9 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,41 +7,24 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.56 2005/05/03 15:19:00 dedekind Exp $ + * $Id: os-linux.h,v 1.57 2005/07/06 12:13:09 dwmw2 Exp $ * */ #ifndef __JFFS2_OS_LINUX_H__ #define __JFFS2_OS_LINUX_H__ -#include /* JFFS2 uses Linux mode bits natively -- no need for conversion */ #define os_to_jffs2_mode(x) (x) #define jffs2_to_os_mode(x) (x) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73) -#define kstatfs statfs -#endif - struct kstatfs; struct kvec; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode)) #define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) #define JFFS2_SB_INFO(sb) (sb->s_fs_info) #define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv) -#elif defined(JFFS2_OUT_OF_KERNEL) -#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u) -#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) ) -#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u) -#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) -#else -#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i) -#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) ) -#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb) -#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) -#endif #define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) @@ -49,28 +32,14 @@ struct kvec; #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1) #define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f))) #define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f))) -#else -#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) -#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) -#endif -/* Urgh. The things we do to keep the 2.4 build working */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47) #define ITIME(sec) ((struct timespec){sec, 0}) #define I_SEC(tv) ((tv).tv_sec) #define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) #define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) #define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) -#else -#define ITIME(x) (x) -#define I_SEC(x) (x) -#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) -#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) -#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) -#endif #define sleep_on_spinunlock(wq, s) \ do { \ @@ -84,17 +53,12 @@ struct kvec; static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) f->highest_version = 0; f->fragtree = RB_ROOT; f->metadata = NULL; f->dents = NULL; f->flags = 0; f->usercompr = 0; -#else - memset(f, 0, sizeof(*f)); - init_MUTEX_LOCKED(&f->sem); -#endif } -- cgit v1.2.3-18-g5258 From 6430a8def12edebc1c9c7c2621d33ca0e8653c33 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Wed, 6 Jul 2005 15:43:18 +0100 Subject: [JFFS2] Simplify the tree insert code. It isn't _normal_ that we allow key collision in rbtrees, but it does not matter as long as the two nodes with the same version are together. Signed-off-by: Artem B. Bityuckiy Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner --- fs/jffs2/nodelist.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'fs') diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index be38cc5c35c..c7bbdeec93a 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.95 2005/07/05 21:03:07 dwmw2 Exp $ + * $Id: nodelist.c,v 1.97 2005/07/06 15:18:41 dwmw2 Exp $ * */ @@ -69,12 +69,11 @@ static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct rb_root parent = *p; this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); + /* There may actually be a collision here, but it doesn't + actually matter. As long as the two nodes with the same + version are together, it's all fine. */ if (tn->version < this->version) p = &(*p)->rb_left; - else if (tn->version > this->version) - p = &(*p)->rb_right; - else if (tn < this) - p = &(*p)->rb_left; else p = &(*p)->rb_right; } -- cgit v1.2.3-18-g5258