X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=fs%2Fjffs2%2Fjffs2_1pass.c;h=5912cde83840f1b997cdb46251286f6912f8813f;hb=7b83060b1eab4456b3dfaef636dfd5c0ff705b17;hp=11b66ab4b30847dc6b4f28ef9d72fb1cda7dc0a2;hpb=cb5473205206c7f14cbb1e747f28ec75b48826e2;p=oweals%2Fu-boot.git diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 11b66ab4b3..5912cde838 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -114,12 +114,16 @@ #include #include #include +#include +#include #include #include +#include #include #include #include -#include +#include +#include #include "jffs2_private.h" @@ -146,11 +150,7 @@ static struct part_info *current_part; #if (defined(CONFIG_JFFS2_NAND) && \ defined(CONFIG_CMD_NAND) ) -#if defined(CONFIG_NAND_LEGACY) -#include -#else #include -#endif /* * Support for jffs2 on top of NAND-flash * @@ -161,12 +161,6 @@ static struct part_info *current_part; * */ -#if defined(CONFIG_NAND_LEGACY) -/* this one defined in nand_legacy.c */ -int read_jffs2_nand(size_t start, size_t len, - size_t * retlen, u_char * buf, int nanddev); -#endif - #define NAND_PAGE_SIZE 512 #define NAND_PAGE_SHIFT 9 #define NAND_PAGE_MASK (~(NAND_PAGE_SIZE-1)) @@ -182,10 +176,15 @@ static u32 nand_cache_off = (u32)-1; static int read_nand_cached(u32 off, u32 size, u_char *buf) { struct mtdids *id = current_part->dev->id; + struct mtd_info *mtd; u32 bytes_read = 0; size_t retlen; int cpy_bytes; + mtd = get_nand_dev_by_index(id->num); + if (!mtd) + return -1; + while (bytes_read < size) { if ((off + bytes_read < nand_cache_off) || (off + bytes_read >= nand_cache_off+NAND_CACHE_SIZE)) { @@ -201,24 +200,14 @@ static int read_nand_cached(u32 off, u32 size, u_char *buf) } } -#if defined(CONFIG_NAND_LEGACY) - if (read_jffs2_nand(nand_cache_off, NAND_CACHE_SIZE, - &retlen, nand_cache, id->num) < 0 || - retlen != NAND_CACHE_SIZE) { - printf("read_nand_cached: error reading nand off %#x size %d bytes\n", - nand_cache_off, NAND_CACHE_SIZE); - return -1; - } -#else retlen = NAND_CACHE_SIZE; - if (nand_read(&nand_info[id->num], nand_cache_off, - &retlen, nand_cache) != 0 || + if (nand_read(mtd, nand_cache_off, + &retlen, nand_cache) < 0 || retlen != NAND_CACHE_SIZE) { printf("read_nand_cached: error reading nand off %#x size %d bytes\n", nand_cache_off, NAND_CACHE_SIZE); return -1; } -#endif } cpy_bytes = nand_cache_off + NAND_CACHE_SIZE - (off + bytes_read); if (cpy_bytes > size - bytes_read) @@ -312,7 +301,7 @@ static int read_onenand_cached(u32 off, u32 size, u_char *buf) retlen = ONENAND_CACHE_SIZE; if (onenand_read(&onenand_mtd, onenand_cache_off, retlen, - &retlen, onenand_cache) != 0 || + &retlen, onenand_cache) < 0 || retlen != ONENAND_CACHE_SIZE) { printf("read_onenand_cached: error reading nand off %#x size %d bytes\n", onenand_cache_off, ONENAND_CACHE_SIZE); @@ -417,23 +406,26 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf) { struct mtdids *id = current_part->dev->id; + switch(id->type) { #if defined(CONFIG_CMD_FLASH) - if (id->type == MTD_DEV_TYPE_NOR) { + case MTD_DEV_TYPE_NOR: return get_fl_mem_nor(off, size, ext_buf); - } + break; #endif - #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) - if (id->type == MTD_DEV_TYPE_NAND) + case MTD_DEV_TYPE_NAND: return get_fl_mem_nand(off, size, ext_buf); + break; #endif - #if defined(CONFIG_CMD_ONENAND) - if (id->type == MTD_DEV_TYPE_ONENAND) + case MTD_DEV_TYPE_ONENAND: return get_fl_mem_onenand(off, size, ext_buf); + break; #endif - - printf("get_fl_mem: unknown device type, using raw offset!\n"); + default: + printf("get_fl_mem: unknown device type, " \ + "using raw offset!\n"); + } return (void*)off; } @@ -441,23 +433,27 @@ static inline void *get_node_mem(u32 off, void *ext_buf) { struct mtdids *id = current_part->dev->id; + switch(id->type) { #if defined(CONFIG_CMD_FLASH) - if (id->type == MTD_DEV_TYPE_NOR) + case MTD_DEV_TYPE_NOR: return get_node_mem_nor(off, ext_buf); + break; #endif - #if defined(CONFIG_JFFS2_NAND) && \ defined(CONFIG_CMD_NAND) - if (id->type == MTD_DEV_TYPE_NAND) + case MTD_DEV_TYPE_NAND: return get_node_mem_nand(off, ext_buf); + break; #endif - #if defined(CONFIG_CMD_ONENAND) - if (id->type == MTD_DEV_TYPE_ONENAND) + case MTD_DEV_TYPE_ONENAND: return get_node_mem_onenand(off, ext_buf); + break; #endif - - printf("get_node_mem: unknown device type, using raw offset!\n"); + default: + printf("get_fl_mem: unknown device type, " \ + "using raw offset!\n"); + } return (void*)off; } @@ -490,9 +486,8 @@ static char *compr_names[] = { "COPY", "DYNRUBIN", "ZLIB", -#if defined(CONFIG_JFFS2_LZO_LZARI) +#if defined(CONFIG_JFFS2_LZO) "LZO", - "LZARI", #endif }; @@ -557,49 +552,19 @@ static struct b_node * insert_node(struct b_list *list, u32 offset) { struct b_node *new; -#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS - struct b_node *b, *prev; -#endif if (!(new = add_node(list))) { putstr("add_node failed!\r\n"); return NULL; } new->offset = offset; + new->next = NULL; -#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS - if (list->listTail != NULL && list->listCompare(new, list->listTail)) - prev = list->listTail; - else if (list->listLast != NULL && list->listCompare(new, list->listLast)) - prev = list->listLast; + if (list->listTail != NULL) + list->listTail->next = new; else - prev = NULL; - - for (b = (prev ? prev->next : list->listHead); - b != NULL && list->listCompare(new, b); - prev = b, b = b->next) { - list->listLoops++; - } - if (b != NULL) - list->listLast = prev; - - if (b != NULL) { - new->next = b; - if (prev != NULL) - prev->next = new; - else - list->listHead = new; - } else -#endif - { - new->next = (struct b_node *) NULL; - if (list->listTail != NULL) { - list->listTail->next = new; - list->listTail = new; - } else { - list->listTail = list->listHead = new; - } - } + list->listHead = new; + list->listTail = new; return new; } @@ -610,14 +575,18 @@ insert_node(struct b_list *list, u32 offset) */ 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; + /* + * Only read in the version info from flash, not the entire inode. + * This can make a big difference to speed if flash is slow. + */ + u32 new_version; + u32 old_version; + get_fl_mem(new->offset + offsetof(struct jffs2_raw_inode, version), + sizeof(new_version), &new_version); + get_fl_mem(old->offset + offsetof(struct jffs2_raw_inode, version), + sizeof(old_version), &old_version); + + return new_version > old_version; } /* Sort directory entries so all entries in the same directory @@ -627,42 +596,45 @@ static int compare_inodes(struct b_node *new, struct b_node *old) */ 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); - int cmp; - - /* ascending sort by pino */ - if (jNew->pino != jOld->pino) - return jNew->pino > jOld->pino; - - /* pino is the same, so use ascending sort by nsize, so - * we don't do strncmp unless we really must. + /* + * Using NULL as the buffer for NOR flash prevents the entire node + * being read. This makes most comparisons much quicker as only one + * or two entries from the node will be used most of the time. */ - if (jNew->nsize != jOld->nsize) - return jNew->nsize > jOld->nsize; - - /* length is also the same, so use ascending sort by name - */ - cmp = strncmp((char *)jNew->name, (char *)jOld->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) { - /* since jNew is newer, we know jOld is not valid, so - * mark it with inode 0 and it will not be used + struct jffs2_raw_dirent *jNew = get_node_mem(new->offset, NULL); + struct jffs2_raw_dirent *jOld = get_node_mem(old->offset, NULL); + int cmp; + int ret; + + if (jNew->pino != jOld->pino) { + /* ascending sort by pino */ + ret = jNew->pino > jOld->pino; + } else if (jNew->nsize != jOld->nsize) { + /* + * pino is the same, so use ascending sort by nsize, + * so we don't do strncmp unless we really must. */ - jOld->ino = 0; - return 1; + ret = jNew->nsize > jOld->nsize; + } else { + /* + * length is also the same, so use ascending sort by name + */ + cmp = strncmp((char *)jNew->name, (char *)jOld->name, + jNew->nsize); + if (cmp != 0) { + ret = cmp > 0; + } else { + /* + * we have duplicate names in this directory, + * so use ascending sort by version + */ + ret = jNew->version > jOld->version; + } } + put_fl_mem(jNew, NULL); + put_fl_mem(jOld, NULL); - return 0; + return ret; } #endif @@ -709,7 +681,6 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) u32 latestVersion = 0; uchar *lDest; uchar *src; - long ret; int i; u32 counter = 0; #ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS @@ -732,12 +703,23 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) } put_fl_mem(jNode, pL->readbuf); } + /* + * If no destination is provided, we are done. + * Just return the total size. + */ + if (!dest) + return totalSize; #endif for (b = pL->frag.listHead; b != NULL; b = b->next) { - jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset, - pL->readbuf); - if ((inode == jNode->ino)) { + /* + * Copy just the node and not the data at this point, + * since we don't yet know if we need this data. + */ + jNode = (struct jffs2_raw_inode *)get_fl_mem(b->offset, + sizeof(struct jffs2_raw_inode), + pL->readbuf); + if (inode == jNode->ino) { #if 0 putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen); putLabeledWord("read_inode: inode = ", jNode->ino); @@ -760,7 +742,15 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif if(dest) { - src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode); + /* + * Now that the inode has been checked, + * read the entire inode, including data. + */ + put_fl_mem(jNode, pL->readbuf); + jNode = (struct jffs2_raw_inode *) + get_node_mem(b->offset, pL->readbuf); + src = ((uchar *)jNode) + + sizeof(struct jffs2_raw_inode); /* ignore data behind latest known EOF */ if (jNode->offset > totalSize) { put_fl_mem(jNode, pL->readbuf); @@ -781,36 +771,30 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #endif switch (jNode->compr) { case JFFS2_COMPR_NONE: - ret = (unsigned long) ldr_memcpy(lDest, src, jNode->dsize); + ldr_memcpy(lDest, src, jNode->dsize); break; case JFFS2_COMPR_ZERO: - ret = 0; for (i = 0; i < jNode->dsize; i++) *(lDest++) = 0; break; case JFFS2_COMPR_RTIME: - ret = 0; rtime_decompress(src, lDest, jNode->csize, jNode->dsize); break; case JFFS2_COMPR_DYNRUBIN: /* this is slow but it works */ - ret = 0; dynrubin_decompress(src, lDest, jNode->csize, jNode->dsize); break; case JFFS2_COMPR_ZLIB: - ret = zlib_decompress(src, lDest, jNode->csize, jNode->dsize); + zlib_decompress(src, lDest, jNode->csize, jNode->dsize); break; -#if defined(CONFIG_JFFS2_LZO_LZARI) +#if defined(CONFIG_JFFS2_LZO) case JFFS2_COMPR_LZO: - ret = lzo_decompress(src, lDest, jNode->csize, jNode->dsize); - break; - case JFFS2_COMPR_LZARI: - ret = lzari_decompress(src, lDest, jNode->csize, jNode->dsize); + lzo_decompress(src, lDest, jNode->csize, jNode->dsize); break; #endif default: /* unknown */ - putLabeledWord("UNKOWN COMPRESSION METHOD = ", jNode->compr); + putLabeledWord("UNKNOWN COMPRESSION METHOD = ", jNode->compr); put_fl_mem(jNode, pL->readbuf); return -1; break; @@ -819,7 +803,6 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest) #if 0 putLabeledWord("read_inode: totalSize = ", totalSize); - putLabeledWord("read_inode: compr ret = ", ret); #endif } counter++; @@ -852,7 +835,6 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino) jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, pL->readbuf); if ((pino == jDir->pino) && (len == jDir->nsize) && - (jDir->ino) && /* 0 for unlink */ (!strncmp((char *)jDir->name, name, len))) { /* a match */ if (jDir->version < version) { put_fl_mem(jDir, pL->readbuf); @@ -973,16 +955,47 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) for (b = pL->dir.listHead; b; b = b->next) { jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, pL->readbuf); - if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */ + if (pino == jDir->pino) { u32 i_version = 0; - struct jffs2_raw_inode ojNode; struct jffs2_raw_inode *jNode, *i = NULL; - struct b_node *b2 = pL->frag.listHead; + struct b_node *b2; + +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS + /* Check for more recent versions of this file */ + int match; + do { + struct b_node *next = b->next; + struct jffs2_raw_dirent *jDirNext; + if (!next) + break; + jDirNext = (struct jffs2_raw_dirent *) + get_node_mem(next->offset, NULL); + match = jDirNext->pino == jDir->pino && + jDirNext->nsize == jDir->nsize && + strncmp((char *)jDirNext->name, + (char *)jDir->name, + jDir->nsize) == 0; + if (match) { + /* Use next. It is more recent */ + b = next; + /* Update buffer with the new info */ + *jDir = *jDirNext; + } + put_fl_mem(jDirNext, NULL); + } while (match); +#endif + if (jDir->ino == 0) { + /* Deleted file */ + put_fl_mem(jDir, pL->readbuf); + continue; + } - while (b2) { + for (b2 = pL->frag.listHead; b2; b2 = b2->next) { jNode = (struct jffs2_raw_inode *) - get_fl_mem(b2->offset, sizeof(ojNode), &ojNode); - if (jNode->ino == jDir->ino && jNode->version >= i_version) { + get_fl_mem(b2->offset, sizeof(*jNode), + NULL); + if (jNode->ino == jDir->ino && + jNode->version >= i_version) { i_version = jNode->version; if (i) put_fl_mem(i, NULL); @@ -995,7 +1008,7 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino) sizeof(*i), NULL); } - b2 = b2->next; + put_fl_mem(jNode, NULL); } dump_inode(pL, jDir, i); @@ -1220,8 +1233,30 @@ jffs2_1pass_rescan_needed(struct part_info *part) return 0; } +#ifdef CONFIG_JFFS2_SUMMARY +static u32 sum_get_unaligned32(u32 *ptr) +{ + u32 val; + u8 *p = (u8 *)ptr; + + val = *p | (*(p + 1) << 8) | (*(p + 2) << 16) | (*(p + 3) << 24); + + return __le32_to_cpu(val); +} + +static u16 sum_get_unaligned16(u16 *ptr) +{ + u16 val; + u8 *p = (u8 *)ptr; + + val = *p | (*(p + 1) << 8); + + return __le16_to_cpu(val); +} + #define dbg_summary(...) do {} while (0); -/* Process the stored summary information - helper function for +/* + * Process the stored summary information - helper function for * jffs2_sum_scan_sumnode() */ @@ -1230,54 +1265,64 @@ static int jffs2_sum_process_sum_data(struct part_info *part, uint32_t offset, struct b_lists *pL) { void *sp; - int i; + int i, pass; + void *ret; - sp = summary->sum; + for (pass = 0; pass < 2; pass++) { + sp = summary->sum; - for (i = 0; i < summary->sum_num; i++) { - dbg_summary("processing summary index %d\n", i); + for (i = 0; i < summary->sum_num; i++) { + struct jffs2_sum_unknown_flash *spu = sp; + dbg_summary("processing summary index %d\n", i); - switch (((struct jffs2_sum_unknown_flash *)sp)->nodetype) { - case JFFS2_NODETYPE_INODE: { + switch (sum_get_unaligned16(&spu->nodetype)) { + case JFFS2_NODETYPE_INODE: { struct jffs2_sum_inode_flash *spi; - spi = sp; - - dbg_summary("Inode at 0x%08x-0x%08x\n", - offset + spi->offset, - offset + spi->offset + spi->totlen); - - if (insert_node(&pL->frag, (u32) part->offset + - offset + spi->offset) == NULL) - return -1; - - sp += JFFS2_SUMMARY_INODE_SIZE; + if (pass) { + spi = sp; - break; - } + ret = insert_node(&pL->frag, + (u32)part->offset + + offset + + sum_get_unaligned32( + &spi->offset)); + if (ret == NULL) + return -1; + } - case JFFS2_NODETYPE_DIRENT: { - struct jffs2_sum_dirent_flash *spd; - spd = sp; + sp += JFFS2_SUMMARY_INODE_SIZE; - dbg_summary("Dirent at 0x%08x-0x%08x\n", - offset + spd->offset, - offset + spd->offset + spd->totlen); - - if (insert_node(&pL->dir, (u32) part->offset + - offset + spd->offset) == NULL) - return -1; - - sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); + break; + } + case JFFS2_NODETYPE_DIRENT: { + struct jffs2_sum_dirent_flash *spd; + spd = sp; + if (pass) { + ret = insert_node(&pL->dir, + (u32) part->offset + + offset + + sum_get_unaligned32( + &spd->offset)); + if (ret == NULL) + return -1; + } + + sp += JFFS2_SUMMARY_DIRENT_SIZE( + spd->nsize); - break; - } - default : { - uint16_t nodetype = - ((struct jffs2_sum_unknown_flash *) - sp)->nodetype; - printf("Unsupported node type %x found in " - "summary!\n", nodetype); - break; + break; + } + default : { + uint16_t nodetype = sum_get_unaligned16( + &spu->nodetype); + printf("Unsupported node type %x found" + " in summary!\n", + nodetype); + if ((nodetype & JFFS2_COMPAT_MASK) == + JFFS2_FEATURE_INCOMPAT) + return -EIO; + return -EBADMSG; + } } } } @@ -1290,7 +1335,7 @@ int jffs2_sum_scan_sumnode(struct part_info *part, uint32_t offset, struct b_lists *pL) { struct jffs2_unknown_node crcnode; - int ret, ofs; + int ret, __maybe_unused ofs; uint32_t crc; ofs = part->sector_size - sumsize; @@ -1335,6 +1380,8 @@ int jffs2_sum_scan_sumnode(struct part_info *part, uint32_t offset, dbg_summary("Summary : CLEANMARKER node \n"); ret = jffs2_sum_process_sum_data(part, offset, summary, pL); + if (ret == -EBADMSG) + return 0; if (ret) return ret; /* real error */ @@ -1345,6 +1392,7 @@ crc_err: return 0; } +#endif /* CONFIG_JFFS2_SUMMARY */ #ifdef DEBUG_FRAGMENTS static void @@ -1409,7 +1457,7 @@ dump_dirents(struct b_lists *pL) } #endif -#define DEFAULT_EMPTY_SCAN_SIZE 4096 +#define DEFAULT_EMPTY_SCAN_SIZE 256 static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { @@ -1424,15 +1472,16 @@ jffs2_1pass_build_lists(struct part_info * part) { struct b_lists *pL; struct jffs2_unknown_node *node; - u32 nr_sectors = part->size/part->sector_size; + u32 nr_sectors; u32 i; u32 counter4 = 0; u32 counterF = 0; u32 counterN = 0; u32 max_totlen = 0; - u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE; + u32 buf_size; char *buf; + nr_sectors = lldiv(part->size, part->sector_size); /* turn off the lcd. Refreshing the lcd adds 50% overhead to the */ /* jffs2 list building enterprise nope. in newer versions the overhead is */ /* only about 5 %. not enough to inconvenience people for. */ @@ -1441,7 +1490,7 @@ 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; - buf = malloc(buf_size); + buf = malloc(DEFAULT_EMPTY_SCAN_SIZE); puts ("Scanning JFFS2 FS: "); /* start at the beginning of the partition */ @@ -1450,13 +1499,20 @@ jffs2_1pass_build_lists(struct part_info * part) uint32_t buf_ofs = sector_ofs; uint32_t buf_len; uint32_t ofs, prevofs; +#ifdef CONFIG_JFFS2_SUMMARY struct jffs2_sum_marker *sm; void *sumptr = NULL; uint32_t sumlen; int ret; +#endif + /* Indicates a sector with a CLEANMARKER was found */ + int clean_sector = 0; + /* Set buf_size to maximum length */ + buf_size = DEFAULT_EMPTY_SCAN_SIZE; WATCHDOG_RESET(); +#ifdef CONFIG_JFFS2_SUMMARY buf_len = sizeof(*sm); /* Read as much as we want into the _end_ of the preallocated @@ -1477,6 +1533,8 @@ jffs2_1pass_build_lists(struct part_info * part) if (!sumptr) { putstr("Can't get memory for summary " "node!\n"); + free(buf); + jffs2_free_cache(part); return 0; } memcpy(sumptr + sumlen - buf_len, buf + @@ -1498,12 +1556,16 @@ jffs2_1pass_build_lists(struct part_info * part) if (buf_size && sumlen > buf_size) free(sumptr); - if (ret < 0) + if (ret < 0) { + free(buf); + jffs2_free_cache(part); return 0; + } if (ret) continue; } +#endif /* CONFIG_JFFS2_SUMMARY */ buf_len = EMPTY_SCAN_SIZE(part->sector_size); @@ -1522,6 +1584,11 @@ jffs2_1pass_build_lists(struct part_info * part) ofs += sector_ofs; prevofs = ofs - 1; + /* + * Set buf_size down to the minimum size required. + * This prevents reading in chunks of flash data unnecessarily. + */ + buf_size = sizeof(union jffs2_node_union); scan_more: while (ofs < sector_ofs + part->sector_size) { @@ -1547,9 +1614,8 @@ jffs2_1pass_build_lists(struct part_info * part) if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { uint32_t inbuf_ofs; - uint32_t empty_start, scan_end; + uint32_t scan_end; - empty_start = ofs; ofs += 4; scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE( part->sector_size)/8, @@ -1565,6 +1631,14 @@ jffs2_1pass_build_lists(struct part_info * part) ofs += 4; } /* Ran off end. */ + /* + * If this sector had a clean marker at the + * beginning, and immediately following this + * have been a bunch of FF bytes, treat the + * entire sector as empty. + */ + if (clean_sector) + break; /* See how much more there is to read in this * eraseblock... @@ -1586,6 +1660,11 @@ jffs2_1pass_build_lists(struct part_info * part) buf_ofs = ofs; goto more_empty; } + /* + * Found something not erased in the sector, so reset + * the 'clean_sector' flag. + */ + clean_sector = 0; if (node->magic != JFFS2_MAGIC_BITMASK || !hdr_crc(node)) { ofs += 4; @@ -1603,17 +1682,25 @@ jffs2_1pass_build_lists(struct part_info * part) case JFFS2_NODETYPE_INODE: if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) { + buf_len = min_t(uint32_t, + sizeof(struct jffs2_raw_inode), + sector_ofs + + part->sector_size - + ofs); 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 (!inode_crc((struct jffs2_raw_inode *)node)) + break; if (insert_node(&pL->frag, (u32) part->offset + - ofs) == NULL) + ofs) == NULL) { + free(buf); + jffs2_free_cache(part); return 0; + } if (max_totlen < node->totlen) max_totlen = node->totlen; break; @@ -1623,6 +1710,11 @@ jffs2_1pass_build_lists(struct part_info * part) ((struct jffs2_raw_dirent *) node)->nsize) { + buf_len = min_t(uint32_t, + node->totlen, + sector_ofs + + part->sector_size - + ofs); get_fl_mem((u32)part->offset + ofs, buf_len, buf); buf_ofs = ofs; @@ -1639,8 +1731,11 @@ jffs2_1pass_build_lists(struct part_info * part) if (! (counterN%100)) puts ("\b\b. "); if (insert_node(&pL->dir, (u32) part->offset + - ofs) == NULL) + ofs) == NULL) { + free(buf); + jffs2_free_cache(part); return 0; + } if (max_totlen < node->totlen) max_totlen = node->totlen; counterN++; @@ -1651,6 +1746,16 @@ jffs2_1pass_build_lists(struct part_info * part) "%d != %zu\n", node->totlen, sizeof(struct jffs2_unknown_node)); + if ((node->totlen == + sizeof(struct jffs2_unknown_node)) && + (ofs == sector_ofs)) { + /* + * Found a CLEANMARKER at the beginning + * of the sector. It's in the correct + * place with correct size and CRC. + */ + clean_sector = 1; + } break; case JFFS2_NODETYPE_PADDING: if (node->totlen < sizeof(struct jffs2_unknown_node)) @@ -1672,6 +1777,13 @@ jffs2_1pass_build_lists(struct part_info * part) } free(buf); +#if defined(CONFIG_SYS_JFFS2_SORT_FRAGMENTS) + /* + * Sort the lists. + */ + sort_list(&pL->frag); + sort_list(&pL->dir); +#endif putstr("\b\b done.\r\n"); /* close off the dots */ /* We don't care if malloc failed - then each read operation will