jffs2: rewrite jffs2 scanning code based on Linux one

Rewrites jffs2_1pass_build_lists() function in style of Linux's
jffs2_scan_medium() and jffs2_scan_eraseblock().
This includes:
 - Caching flash acceses
 - Smart dealing with free space

Signed-off-by: Alexey Neyman <avn@emcraft.com>
Signed-off-by: Ilya Yanok <yanok@emcraft.com>
This commit is contained in:
Ilya Yanok 2008-11-13 19:49:33 +03:00 committed by Wolfgang Denk
parent e0b5532579
commit 8a36d31f72
1 changed files with 174 additions and 59 deletions

View File

@ -389,6 +389,12 @@ static inline void *get_fl_mem_nor(u32 off)
return (void*)addr;
}
static inline void *get_fl_mem_nor_copy(u32 off, u32 size, void *ext_buf)
{
memcpy(ext_buf, get_fl_mem_nor(off), size);
return ext_buf;
}
static inline void *get_node_mem_nor(u32 off)
{
return (void*)get_fl_mem_nor(off);
@ -405,8 +411,11 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
struct mtdids *id = current_part->dev->id;
#if defined(CONFIG_CMD_FLASH)
if (id->type == MTD_DEV_TYPE_NOR)
if (id->type == MTD_DEV_TYPE_NOR) {
if (ext_buf)
return get_fl_mem_nor_copy(off, size, ext_buf);
return get_fl_mem_nor(off);
}
#endif
#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND)
@ -478,9 +487,6 @@ static char *compr_names[] = {
#endif
};
/* Spinning wheel */
static char spinner[] = { '|', '/', '-', '\\' };
/* Memory management */
struct mem_block {
u32 index;
@ -651,23 +657,6 @@ static int compare_dirents(struct b_node *new, struct b_node *old)
}
#endif
static u32
jffs2_scan_empty(u32 start_offset, struct part_info *part)
{
char *max = (char *)(part->offset + part->size - sizeof(struct jffs2_raw_inode));
char *offset = (char *)(part->offset + start_offset);
u32 off;
while (offset < max &&
*(u32*)get_fl_mem((u32)offset, sizeof(u32), &off) == 0xFFFFFFFF) {
offset += sizeof(u32);
/* return if spinning is due */
if (((u32)offset & ((1 << SPIN_BLKSIZE)-1)) == 0) break;
}
return (u32)offset - part->offset;
}
void
jffs2_free_cache(struct part_info *part)
{
@ -766,6 +755,10 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)
put_fl_mem(jNode);
continue;
}
if (!data_crc(jNode)) {
put_fl_mem(jNode);
continue;
}
lDest = (uchar *) (dest + jNode->offset);
#if 0
@ -1268,17 +1261,33 @@ dump_dirents(struct b_lists *pL)
}
#endif
#define min_t(type, x, y) ({ \
type __min1 = (x); \
type __min2 = (y); \
__min1 < __min2 ? __min1: __min2; })
#define DEFAULT_EMPTY_SCAN_SIZE 4096
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;
}
static u32
jffs2_1pass_build_lists(struct part_info * part)
{
struct b_lists *pL;
struct jffs2_unknown_node *node;
u32 offset, oldoffset = 0;
u32 max = part->size - sizeof(struct jffs2_raw_inode);
u32 counter = 0;
u32 nr_sectors = part->size/part->sector_size;
u32 i;
u32 counter4 = 0;
u32 counterF = 0;
u32 counterN = 0;
u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE;
char *buf;
/* turn off the lcd. Refreshing the lcd adds 50% overhead to the */
/* jffs2 list building enterprise nope. in newer versions the overhead is */
@ -1288,70 +1297,176 @@ jffs2_1pass_build_lists(struct part_info * part)
/* if we are building a list we need to refresh the cache. */
jffs_init_1pass_list(part);
pL = (struct b_lists *)part->jffs2_priv;
offset = 0;
buf = malloc(buf_size);
puts ("Scanning JFFS2 FS: ");
/* start at the beginning of the partition */
while (offset < max) {
if ((oldoffset >> SPIN_BLKSIZE) != (offset >> SPIN_BLKSIZE)) {
printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]);
oldoffset = offset;
}
for (i = 0; i < nr_sectors; i++) {
uint32_t sector_ofs = i * part->sector_size;
uint32_t buf_ofs = sector_ofs;
uint32_t buf_len = EMPTY_SCAN_SIZE(part->sector_size);
uint32_t ofs, prevofs;
WATCHDOG_RESET();
get_fl_mem((u32)part->offset + buf_ofs, buf_len, buf);
node = (struct jffs2_unknown_node *) get_node_mem((u32)part->offset + offset);
if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) {
/* if its a fragment add it */
if (node->nodetype == JFFS2_NODETYPE_INODE &&
inode_crc((struct jffs2_raw_inode *) node) &&
data_crc((struct jffs2_raw_inode *) node)) {
if (insert_node(&pL->frag, (u32) part->offset +
offset) == NULL) {
put_fl_mem(node);
return 0;
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs = 0;
/* Scan only 4KiB of 0xFF before declaring it's empty */
while (ofs < EMPTY_SCAN_SIZE(part->sector_size) &&
*(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
ofs += 4;
if (ofs == EMPTY_SCAN_SIZE(part->sector_size))
continue;
ofs += sector_ofs;
prevofs = ofs - 1;
scan_more:
while (ofs < sector_ofs + part->sector_size) {
if (ofs == prevofs) {
printf("offset %08x already seen, skip\n", ofs);
ofs += 4;
counter4++;
continue;
}
prevofs = ofs;
if (sector_ofs + part->sector_size <
ofs + sizeof(*node))
break;
if (buf_ofs + buf_len < ofs + sizeof(*node)) {
buf_len = min_t(uint32_t, buf_size, sector_ofs
+ part->sector_size - ofs);
get_fl_mem((u32)part->offset + ofs, buf_len,
buf);
buf_ofs = ofs;
}
node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];
if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
uint32_t inbuf_ofs;
uint32_t empty_start, scan_end;
empty_start = ofs;
ofs += 4;
scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(
part->sector_size)/8,
buf_len);
more_empty:
inbuf_ofs = ofs - buf_ofs;
while (inbuf_ofs < scan_end) {
if (*(uint32_t *)(&buf[inbuf_ofs]) !=
0xffffffff)
goto scan_more;
inbuf_ofs += 4;
ofs += 4;
}
} else if (node->nodetype == JFFS2_NODETYPE_DIRENT &&
dirent_crc((struct jffs2_raw_dirent *) node) &&
dirent_name_crc((struct jffs2_raw_dirent *) node)) {
/* Ran off end. */
/* See how much more there is to read in this
* eraseblock...
*/
buf_len = min_t(uint32_t, buf_size,
sector_ofs +
part->sector_size - ofs);
if (!buf_len) {
/* No more to read. Break out of main
* loop without marking this range of
* empty space as dirty (because it's
* not)
*/
break;
}
scan_end = buf_len;
get_fl_mem((u32)part->offset + ofs, buf_len,
buf);
buf_ofs = ofs;
goto more_empty;
}
if (node->magic != JFFS2_MAGIC_BITMASK ||
!hdr_crc(node)) {
ofs += 4;
counter4++;
continue;
}
if (ofs + node->totlen >
sector_ofs + part->sector_size) {
ofs += 4;
counter4++;
continue;
}
/* if its a fragment add it */
switch (node->nodetype) {
case JFFS2_NODETYPE_INODE:
if (buf_ofs + buf_len < ofs + sizeof(struct
jffs2_raw_inode)) {
get_fl_mem((u32)part->offset + ofs,
buf_len, buf);
buf_ofs = ofs;
node = (void *)buf;
}
if (!inode_crc((struct jffs2_raw_inode *) node))
break;
if (insert_node(&pL->frag, (u32) part->offset +
ofs) == NULL)
return 0;
break;
case JFFS2_NODETYPE_DIRENT:
if (buf_ofs + buf_len < ofs + sizeof(struct
jffs2_raw_dirent) +
((struct
jffs2_raw_dirent *)
node)->nsize) {
get_fl_mem((u32)part->offset + ofs,
buf_len, buf);
buf_ofs = ofs;
node = (void *)buf;
}
if (!dirent_crc((struct jffs2_raw_dirent *)
node) ||
!dirent_name_crc(
(struct
jffs2_raw_dirent *)
node))
break;
if (! (counterN%100))
puts ("\b\b. ");
if (insert_node(&pL->dir, (u32) part->offset +
offset) == NULL) {
put_fl_mem(node);
ofs) == NULL)
return 0;
}
counterN++;
} else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) {
break;
case JFFS2_NODETYPE_CLEANMARKER:
if (node->totlen != sizeof(struct jffs2_unknown_node))
printf("OOPS Cleanmarker has bad size "
"%d != %zu\n",
node->totlen,
sizeof(struct jffs2_unknown_node));
} else if (node->nodetype == JFFS2_NODETYPE_PADDING) {
break;
case JFFS2_NODETYPE_PADDING:
if (node->totlen < sizeof(struct jffs2_unknown_node))
printf("OOPS Padding has bad size "
"%d < %zu\n",
node->totlen,
sizeof(struct jffs2_unknown_node));
} else {
break;
default:
printf("Unknown node type: %x len %d offset 0x%x\n",
node->nodetype,
node->totlen, offset);
node->totlen, ofs);
}
offset += ((node->totlen + 3) & ~3);
ofs += ((node->totlen + 3) & ~3);
counterF++;
} else if (node->magic == JFFS2_EMPTY_BITMASK &&
node->nodetype == JFFS2_EMPTY_BITMASK) {
offset = jffs2_scan_empty(offset, part);
} else { /* if we know nothing, we just step and look. */
offset += 4;
counter4++;
}
/* printf("unknown node magic %4.4x %4.4x @ %lx\n", node->magic, node->nodetype, (unsigned long)node); */
put_fl_mem(node);
}
free(buf);
putstr("\b\b done.\r\n"); /* close off the dots */
/* turn the lcd back on. */
/* splash(); */