Re: [U-Boot-Users] RO jffs2 implementation for bootloader

Hi Stefan,
Stefan Roese a écrit :
Hi Matthieu,
On Friday 04 May 2007 11:55, Matthieu CASTET wrote:
On Thu, 2007-05-03 at 08:40 +0000, Matthieu CASTET wrote:
I need to mount a jffs2 partition in a bootloader. I tried u-boot that support jffs2, but it is very slow (2 minutes for mounting a 64MB partition). Do you know if there are other (fast) implemenation of jffs2 suitable for a bootloader ?
Not sure about any existing "fast" implementation, but mounting a JFFS2 partition is about scanning whole partition. You may optimize some thing, but you have to scan anyway.
Well u-boot implementation is very slow. For 64MB partition : 2 minutes for u-boot
This really is slow. 64MB isn't that big and shouldn't take that long to mount.
and 11 s for linux (3s with summary).
So it can be done better.
Did you think about improving the performance in U-Boot? If so, please let's move this discussion to the u-boot-users mailing list.
Somebody already try something for u-boot jffs2 [1], but is doesn't seem to work (don't compile). He didn't receive any report, so u-boot jffs2 code seems unmaintained.
Thanks.
BTW: What cpu at what speed are you using?
an arm9 @240 Mhz.
Matthieu
[1] http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/25780/focus=25808

On Friday 04 May 2007 14:10, Matthieu CASTET wrote:
Did you think about improving the performance in U-Boot? If so, please let's move this discussion to the u-boot-users mailing list.
Somebody already try something for u-boot jffs2 [1], but is doesn't seem to work (don't compile). He didn't receive any report, so u-boot jffs2 code seems unmaintained.
I am willing to work with you on this issue. And will help to get it included.
Could you perhaps work on the patch (looks promising) mentioned below to get it working in the current U-Boot version? This would help. I'll give it a try on some of my systems too then.
http://thread.gmane.org/gmane.comp.boot-loaders.u-boot/25780/focus=25808
Best regards, Stefan

Hi Stefan,
Stefan Roese a écrit :
On Friday 04 May 2007 14:10, Matthieu CASTET wrote:
Did you think about improving the performance in U-Boot? If so, please let's move this discussion to the u-boot-users mailing list.
Somebody already try something for u-boot jffs2 [1], but is doesn't seem to work (don't compile). He didn't receive any report, so u-boot jffs2 code seems unmaintained.
I am willing to work with you on this issue. And will help to get it included.
Using jffs2_nand_1pass.c make thing lot's of better (very fast scaning)
Unfortunalty the code seems incomplete : if I do a ls, there are missing files.
Do you know what's the status of jffs2_nand_1pass.c ?
Thanks,
Matthieu

Hi Matthieu,
On Monday 07 May 2007, Matthieu CASTET wrote:
Using jffs2_nand_1pass.c make thing lot's of better (very fast scaning)
Unfortunalty the code seems incomplete : if I do a ls, there are missing files.
Do I understand this correctly? Some files are displayed and some are missing? Could you give an example?
Do you know what's the status of jffs2_nand_1pass.c ?
No, sorry I personally haven't used the JFFS2 code in U-Boot before.
IIRC this code originally is coming from Ladislav Michl (please correct me if I'm wrong here). So Ladis, can you say something about the status of this file and why it not used at all?
Thanks.
Best regards, Stefan
===================================================================== DENX Software Engineering GmbH, HRB 165235 Munich, CEO: Wolfgang Denk Office: Kirchenstr. 5, D-82194 Groebenzell, Germany =====================================================================

Hi Stefan,
Stefan Roese a écrit :
Hi Matthieu,
On Monday 07 May 2007, Matthieu CASTET wrote:
Using jffs2_nand_1pass.c make thing lot's of better (very fast scaning)
Unfortunalty the code seems incomplete : if I do a ls, there are missing files.
Do I understand this correctly? Some files are displayed and some are missing?
yes
Could you give an example?
SMDK2410 # ls
drwxr-xr-x 0 Mon May 07 14:52:44 2007 bin
drwxr-xr-x 0 Mon May 07 14:50:31 2007 dev
drwxr-xr-x 0 Mon May 07 14:52:44 2007 etc
drwxr-xr-x 0 Mon May 07 14:50:31 2007 home
drwxr-xr-x 0 Mon May 07 14:52:44 2007 lib
lrwxrwxrwx 11 Mon May 07 14:52:44 2007 linuxrc
drwxr-xr-x 0 Mon May 07 14:50:31 2007 mnt
drwxr-xr-x 0 Mon May 07 14:50:31 2007 proc
drwxr-xr-x 0 Mon May 07 14:50:31 2007 root
drwxr-xr-x 0 Mon May 07 14:52:44 2007 sbin
-rw-r--r-- 1120660 Mon May 07 14:52:40 2007 test.bin
# ls -l
-rw-r--r-- 1 root root 0 Jan 1 00:02 1234
drwxr-xr-x 2 root root 0 May 7 2007 bin
drwxr-xr-x 7 root root 0 May 7 2007 dev
drwxr-xr-x 3 root root 0 Mar 21 2007 etc
drwxr-xr-x 3 root root 0 May 7 2007 home
drwxr-xr-x 2 root root 0 May 7 2007 lib
lrwxrwxrwx 1 root root 11 May 7 2007 linuxrc -> bin/busybox drwxr-xr-x 2 root root 0 May 7 2007 mnt
dr-xr-xr-x 28 root root 0 Jan 1 00:00 proc
drwxr-xr-x 2 root root 0 May 7 2007 root
drwxr-xr-x 2 root root 0 May 7 2007 sbin
-rw-r--r-- 1 root root 1120660 May 7 2007 test.bin
drwxr-xr-x 2 root root 0 Jan 1 00:00 tmp
drwxr-xr-x 6 root root 0 May 7 2007 usr
drwxr-xr-x 2 root root 0 May 7 2007 var
I think jffs2_nand_1pass.c got the idea how to work with nand. Instead of trying to use pointer in flash (like do jffs2_1pass.c + a cache to emulate a nor), it parses the flash by pages.
Matthieu

On Mon, May 07, 2007 at 07:38:20PM +0200, Stefan Roese wrote:
Hi Matthieu,
On Monday 07 May 2007, Matthieu CASTET wrote:
Using jffs2_nand_1pass.c make thing lot's of better (very fast scaning)
Unfortunalty the code seems incomplete : if I do a ls, there are missing files.
Do I understand this correctly? Some files are displayed and some are missing? Could you give an example?
I'm also interrested in test case. Having filesystem image would help as well.
Do you know what's the status of jffs2_nand_1pass.c ?
No, sorry I personally haven't used the JFFS2 code in U-Boot before.
IIRC this code originally is coming from Ladislav Michl (please correct me if I'm wrong here). So Ladis, can you say something about the status of this file and why it not used at all?
Indeed... I wrote it (modified from jffs2_1pass.c) when I was adding NAND code. Unfortunately it is not that easy to support JFFS2 on NOR and NAND simultaneously. It would need more work... Below is what I'm currently using - some changes to shut up newer gcc warnings. Perhaps some kind of #define (evil grin) would be enough?
Best regards, ladis
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index c1357d0..d02b678 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)libjffs2.a
AOBJS = -COBJS = jffs2_1pass.o compr_rtime.o compr_rubin.o compr_zlib.o mini_inflate.o +COBJS = jffs2_nand_1pass.o compr_rtime.o compr_rubin.o compr_zlib.o mini_inflate.o COBJS += compr_lzo.o compr_lzari.o
SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/fs/jffs2/jffs2_nand_1pass.c b/fs/jffs2/jffs2_nand_1pass.c index e78af75..e908929 100644 --- a/fs/jffs2/jffs2_nand_1pass.c +++ b/fs/jffs2/jffs2_nand_1pass.c @@ -166,7 +166,7 @@ insert_dirent(struct b_list *list, struct jffs2_raw_dirent *node, u32 offset) new->version = node->version; new->pino = node->pino; new->ino = node->ino; - new->nhash = full_name_hash(node->name, node->nsize); + new->nhash = full_name_hash((char *)node->name, node->nsize); new->nsize = node->nsize; new->type = node->type;
@@ -298,16 +298,16 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 ino, char *dest, } #endif if (dest || stat) { - char *src, *dst; + unsigned char *src, *dst; char data[4096 + sizeof(struct jffs2_raw_inode)]; struct jffs2_raw_inode *inode; - size_t len; + ulong len;
inode = (struct jffs2_raw_inode *)&data; len = sizeof(struct jffs2_raw_inode); if (dest) len += jNode->csize; - nand_read(nand, jNode->offset, &len, inode); + nand_read(nand, jNode->offset, &len, (u_char *)inode); /* ignore data behind latest known EOF */ if (inode->offset > totalSize) continue; @@ -322,8 +322,8 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 ino, char *dest, if (!dest) continue;
- src = ((char *) inode) + sizeof(struct jffs2_raw_inode); - dst = (char *) (dest + inode->offset); + src = ((unsigned char *) inode) + sizeof(struct jffs2_raw_inode); + dst = (unsigned char *) (dest + inode->offset);
switch (inode->compr) { case JFFS2_COMPR_NONE: @@ -434,7 +434,7 @@ static inline void dump_stat(struct stat *st, const char *name) if (st->st_mtime == (time_t)(-1)) /* some ctimes really hate -1 */ st->st_mtime = 1;
- ctime_r(&st->st_mtime, s/*,64*/); /* newlib ctime doesn't have buflen */ + ctime_r((time_t *)&st->st_mtime, s/*,64*/); /* newlib ctime doesn't have buflen */
if ((p = strchr(s,'\n')) != NULL) *p = '\0'; if ((p = strchr(s,'\r')) != NULL) *p = '\0'; @@ -452,12 +452,12 @@ dump_inode(struct b_lists *pL, struct b_dirent *d, struct b_inode *i) { char fname[JFFS2_MAX_NAME_LEN + 1]; struct stat st; - size_t len; + ulong len;
if(!d || !i) return -1; len = d->nsize; nand_read(nand, d->offset + sizeof(struct jffs2_raw_dirent), - &len, &fname); + &len, (uchar *)fname); fname[d->nsize] = '\0';
memset(&st, 0, sizeof(st)); @@ -597,8 +597,9 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino) /* it's a soft link so we follow it again. */ for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) { if (jNode->ino == jDirFoundIno) { - size_t len = jNode->csize; - nand_read(nand, jNode->offset + sizeof(struct jffs2_raw_inode), &len, &tmp); + ulong len = jNode->csize; + nand_read(nand, jNode->offset + sizeof(struct jffs2_raw_inode), + &len, (uchar *)tmp); tmp[jNode->csize] = '\0'; break; } @@ -664,9 +665,11 @@ jffs2_1pass_search_list_inodes(struct b_lists * pL, const char *fname, u32 pino) unsigned char jffs2_1pass_rescan_needed(struct part_info *part) { +/* FIXME struct b_node *b; struct jffs2_unknown_node onode; struct jffs2_unknown_node *node; +*/ struct b_lists *pL = (struct b_lists *)part->jffs2_priv;
if (part->jffs2_priv == 0){ @@ -685,8 +688,9 @@ jffs2_1pass_rescan_needed(struct part_info *part) return 1; }
- /* FIXME */ + #if 0 + /* FIXME */ /* but suppose someone reflashed a partition at the same offset... */ b = pL->dir.listHead; while (b) { @@ -770,7 +774,7 @@ jffs2_fill_scan_buf(nand_info_t *nand, unsigned char *buf, unsigned ofs, unsigned len) { int ret; - unsigned olen; + ulong olen;
olen = len; ret = nand_read(nand, ofs, &olen, buf); @@ -792,7 +796,7 @@ jffs2_1pass_build_lists(struct part_info * part) struct b_lists *pL; struct jffs2_unknown_node *node; unsigned nr_blocks, sectorsize, ofs, offset; - char *buf; + unsigned char *buf; int i; u32 counter = 0; u32 counter4 = 0; @@ -910,9 +914,11 @@ jffs2_1pass_build_lists(struct part_info * part) static u32 jffs2_1pass_fill_info(struct b_lists * pL, struct b_jffs2_info * piL) { +/* FIXME struct b_node *b; struct jffs2_raw_inode ojNode; struct jffs2_raw_inode *jNode; +*/ int i;
for (i = 0; i < JFFS2_NUM_COMPR; i++) { diff --git a/fs/jffs2/jffs2_nand_private.h b/fs/jffs2/jffs2_nand_private.h index 18cca8d..2e4d50c 100644 --- a/fs/jffs2/jffs2_nand_private.h +++ b/fs/jffs2/jffs2_nand_private.h @@ -35,7 +35,7 @@ struct b_list { };
struct b_lists { - char *partOffset; + u32 partOffset; struct b_list dir; struct b_list frag; }; @@ -122,7 +122,7 @@ static inline unsigned long end_name_hash(unsigned long hash)
/* Compute the hash for a name string. */ static inline unsigned int -full_name_hash(const unsigned char *name, unsigned int len) +full_name_hash(const char *name, unsigned int len) { unsigned long hash = init_name_hash(); while (len--)

Hi Ladislav,
Ladislav Michl a écrit :
On Mon, May 07, 2007 at 07:38:20PM +0200, Stefan Roese wrote:
Hi Matthieu,
On Monday 07 May 2007, Matthieu CASTET wrote:
Using jffs2_nand_1pass.c make thing lot's of better (very fast scaning)
Unfortunalty the code seems incomplete : if I do a ls, there are missing files.
Do I understand this correctly? Some files are displayed and some are missing? Could you give an example?
I'm also interrested in test case. Having filesystem image would help as well.
The problem is that delete file are not handled : image we have 2 dirent : pino=1 ino=4 name=toto version=1 pino=1 ino=0 name=toto version=5
jffs2_1pass_list_inodes will list all dirent inode ie diplay version 1 and ignore version 5.
Do you know what's the status of jffs2_nand_1pass.c ?
No, sorry I personally haven't used the JFFS2 code in U-Boot before.
IIRC this code originally is coming from Ladislav Michl (please correct me if I'm wrong here). So Ladis, can you say something about the status of this file and why it not used at all?
Indeed... I wrote it (modified from jffs2_1pass.c) when I was adding NAND code. Unfortunately it is not that easy to support JFFS2 on NOR and NAND simultaneously. It would need more work...
I found that jffs2_1pass_read_inode code is buggy on garbage collected image : we should load inode in version order (small first). If we don't, obsolete inode could be put in the final file.
ino=4 offset=5 dsize=5 version=4 ino=4 offset=0 dsize=5 version=1 ino=4 offset=5 dsize=5 version=2
The code will load version 4, version 1 and version 2. In the dest we will have version 1 & 2 instead of version 1 & 4.
Matthieu

On Wed, May 16, 2007 at 02:17:17PM +0200, Matthieu CASTET wrote:
I found that jffs2_1pass_read_inode code is buggy on garbage collected image : we should load inode in version order (small first). If we don't, obsolete inode could be put in the final file.
ino=4 offset=5 dsize=5 version=4 ino=4 offset=0 dsize=5 version=1 ino=4 offset=5 dsize=5 version=2
The code will load version 4, version 1 and version 2. In the dest we will have version 1 & 2 instead of version 1 & 4.
Hmm, did you #define CFG_JFFS2_SORT_FRAGMENTS ?
Best regards, ladis

Ladislav Michl a écrit :
On Wed, May 16, 2007 at 02:17:17PM +0200, Matthieu CASTET wrote:
I found that jffs2_1pass_read_inode code is buggy on garbage collected image : we should load inode in version order (small first). If we don't, obsolete inode could be put in the final file.
ino=4 offset=5 dsize=5 version=4 ino=4 offset=0 dsize=5 version=1 ino=4 offset=5 dsize=5 version=2
The code will load version 4, version 1 and version 2. In the dest we will have version 1 & 2 instead of version 1 & 4.
Hmm, did you #define CFG_JFFS2_SORT_FRAGMENTS ?
I tried, but it doesn't work :
jffs2_nand_1pass.c: In function 'insert_node': jffs2_nand_1pass.c:102: error: 'struct b_list' has no member named 'listCompare' jffs2_nand_1pass.c:104: error: 'struct b_list' has no member named 'listLast' jffs2_nand_1pass.c:104: error: 'struct b_list' has no member named 'listCompare' jffs2_nand_1pass.c:104: error: 'struct b_list' has no member named 'listLast' jffs2_nand_1pass.c:105: error: 'struct b_list' has no member named 'listLast' jffs2_nand_1pass.c:110: error: 'struct b_list' has no member named 'listCompare' jffs2_nand_1pass.c:112: error: 'struct b_list' has no member named 'listLoops' jffs2_nand_1pass.c:115: error: 'struct b_list' has no member named 'listLast' [...]

On Wed, May 16, 2007 at 02:45:02PM +0200, Matthieu CASTET wrote:
I tried, but it doesn't work :
See patch below. It is not complete and most liklely will not fix your problem. But at least it compiles and can be used as starting point ;-) Based on top of cleanup I sent earlier.
Best regards, ladis
--- fs/jffs2/jffs2_nand_private.h.orig 2007-05-18 11:07:53.000000000 +0200 +++ fs/jffs2/jffs2_nand_private.h 2007-05-18 12:39:10.000000000 +0200 @@ -30,6 +32,11 @@ struct b_list { struct b_node *listTail; struct b_node *listHead; +#ifdef CFG_JFFS2_SORT_FRAGMENTS + struct b_node *listLast; + int (*listCompare)(struct b_node *new, struct b_node *node); + u32 listLoops; +#endif unsigned int listCount; struct mem_block *listMemBase; }; --- fs/jffs2/jffs2_nand_1pass.c.orig 2007-05-18 11:08:12.000000000 +0200 +++ fs/jffs2/jffs2_nand_1pass.c 2007-05-18 12:40:47.000000000 +0200 @@ -1,7 +1,5 @@ #include <common.h>
-#define CFG_JFFS2_SORT_FRAGMENTS - #if !defined(CFG_NAND_LEGACY) && (CONFIG_COMMANDS & CFG_CMD_JFFS2)
#include <malloc.h> @@ -181,14 +179,7 @@ */ static int compare_inodes(struct b_node *new, struct b_node *old) { - struct jffs2_raw_inode ojNew; - struct jffs2_raw_inode ojOld; - struct jffs2_raw_inode *jNew = - (struct jffs2_raw_inode *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew); - struct jffs2_raw_inode *jOld = - (struct jffs2_raw_inode *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld); - - return jNew->version > jOld->version; + return ((struct b_inode *)new)->version > ((struct b_inode *)old)->version; }
/* Sort directory entries so all entries in the same directory @@ -198,38 +189,37 @@ */ static int compare_dirents(struct b_node *new, struct b_node *old) { - struct jffs2_raw_dirent ojNew; - struct jffs2_raw_dirent ojOld; - struct jffs2_raw_dirent *jNew = - (struct jffs2_raw_dirent *)get_fl_mem(new->offset, sizeof(ojNew), &ojNew); - struct jffs2_raw_dirent *jOld = - (struct jffs2_raw_dirent *)get_fl_mem(old->offset, sizeof(ojOld), &ojOld); + struct b_dirent *bNew = (struct b_dirent *) new; + struct b_dirent *bOld = (struct b_dirent *) old; +/* TODO int cmp; - +*/ /* ascending sort by pino */ - if (jNew->pino != jOld->pino) - return jNew->pino > jOld->pino; + if (bNew->pino != bOld->pino) + return bNew->pino > bOld->pino;
/* pino is the same, so use ascending sort by nsize, so * we don't do strncmp unless we really must. */ - if (jNew->nsize != jOld->nsize) - return jNew->nsize > jOld->nsize; + if (bNew->nsize != bOld->nsize) + return bNew->nsize > bOld->nsize;
/* length is also the same, so use ascending sort by name */ - cmp = strncmp(jNew->name, jOld->name, jNew->nsize); + /* TODO: compare name + cmp = strncmp(bNew->name, bOld->name, jNew->nsize); if (cmp != 0) return cmp > 0; + */
/* we have duplicate names in this directory, so use ascending * sort by version */ - if (jNew->version > jOld->version) { + if (bNew->version > bOld->version) { /* since jNew is newer, we know jOld is not valid, so * mark it with inode 0 and it will not be used */ - jOld->ino = 0; + bOld->ino = 0; return 1; }
@@ -270,35 +260,16 @@ u32 latestVersion = 0; long ret;
-#ifdef CFG_JFFS2_SORT_FRAGMENTS - /* Find file size before loading any data, so fragments that - * start past the end of file can be ignored. A fragment - * that is partially in the file is loaded, so extra data may - * be loaded up to the next 4K boundary above the file size. - * This shouldn't cause trouble when loading kernel images, so - * we will live with it. - */ - for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) { - if ((ino == jNode->ino)) { - /* get actual file length from the newest node */ - if (jNode->version >= latestVersion) { - totalSize = jNode->isize; - latestVersion = jNode->version; - } - } - } -#endif - for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) { if ((ino != jNode->ino)) continue; -#ifndef CFG_JFFS2_SORT_FRAGMENTS + /* get actual file length from the newest node */ if (jNode->version >= latestVersion) { totalSize = jNode->isize; latestVersion = jNode->version; } -#endif + if (dest || stat) { unsigned char *src, *dst; char data[4096 + sizeof(struct jffs2_raw_inode)];
participants (4)
-
Ladislav Michl
-
Matthieu CASTET
-
Matthieu CASTET
-
Stefan Roese