X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=fs%2Fjffs2%2Fjffs2_1pass.c;h=6bf1943958246f66e1d258887810afa01d084cf3;hb=a9bdd67653c026d3f568375ca8e48fb5014c62c9;hp=73d3ddc9e137fa7e68cc8e1855e9186d3fffeeaa;hpb=70741004dc28946cd82c7af6789c4ddb3fc94526;p=u-boot diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 73d3ddc9e1..6bf1943958 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -114,11 +114,15 @@ #include #include #include +#include +#include #include #include #include #include #include +#include +#include #include "jffs2_private.h" @@ -138,16 +142,14 @@ # define DEBUGF(fmt,args...) #endif +#include "summary.h" + /* keeps pointer to currentlu processed partition */ 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 * @@ -158,12 +160,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)) @@ -179,10 +175,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)) { @@ -198,24 +199,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) @@ -309,7 +300,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); @@ -414,23 +405,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; } @@ -438,23 +432,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; } @@ -487,9 +485,8 @@ static char *compr_names[] = { "COPY", "DYNRUBIN", "ZLIB", -#if defined(CONFIG_JFFS2_LZO_LZARI) +#if defined(CONFIG_JFFS2_LZO) "LZO", - "LZARI", #endif }; @@ -554,49 +551,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; } @@ -607,14 +574,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 @@ -624,42 +595,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. - */ - if (jNew->nsize != jOld->nsize) - return jNew->nsize > jOld->nsize; - - /* length is also the same, so use ascending sort by name + /* + * 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. */ - 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 @@ -706,7 +680,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 @@ -729,12 +702,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); @@ -757,13 +741,24 @@ 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); continue; } - if (!data_crc(jNode)) { + if (b->datacrc == CRC_UNKNOWN) + b->datacrc = data_crc(jNode) ? + CRC_OK : CRC_BAD; + if (b->datacrc == CRC_BAD) { put_fl_mem(jNode, pL->readbuf); continue; } @@ -775,36 +770,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; @@ -813,7 +802,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++; @@ -846,7 +834,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); @@ -967,16 +954,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); @@ -989,7 +1007,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); @@ -1214,6 +1232,167 @@ 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 + * jffs2_sum_scan_sumnode() + */ + +static int jffs2_sum_process_sum_data(struct part_info *part, uint32_t offset, + struct jffs2_raw_summary *summary, + struct b_lists *pL) +{ + void *sp; + int i, pass; + void *ret; + + for (pass = 0; pass < 2; pass++) { + sp = summary->sum; + + for (i = 0; i < summary->sum_num; i++) { + struct jffs2_sum_unknown_flash *spu = sp; + dbg_summary("processing summary index %d\n", i); + + switch (sum_get_unaligned16(&spu->nodetype)) { + case JFFS2_NODETYPE_INODE: { + struct jffs2_sum_inode_flash *spi; + if (pass) { + spi = sp; + + ret = insert_node(&pL->frag, + (u32)part->offset + + offset + + sum_get_unaligned32( + &spi->offset)); + if (ret == NULL) + return -1; + } + + sp += JFFS2_SUMMARY_INODE_SIZE; + + 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 = 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; + } + } + } + } + return 0; +} + +/* Process the summary node - called from jffs2_scan_eraseblock() */ +int jffs2_sum_scan_sumnode(struct part_info *part, uint32_t offset, + struct jffs2_raw_summary *summary, uint32_t sumsize, + struct b_lists *pL) +{ + struct jffs2_unknown_node crcnode; + int ret, __maybe_unused ofs; + uint32_t crc; + + ofs = part->sector_size - sumsize; + + dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", + offset, offset + ofs, sumsize); + + /* OK, now check for node validity and CRC */ + crcnode.magic = JFFS2_MAGIC_BITMASK; + crcnode.nodetype = JFFS2_NODETYPE_SUMMARY; + crcnode.totlen = summary->totlen; + crc = crc32_no_comp(0, (uchar *)&crcnode, sizeof(crcnode)-4); + + if (summary->hdr_crc != crc) { + dbg_summary("Summary node header is corrupt (bad CRC or " + "no summary at all)\n"); + goto crc_err; + } + + if (summary->totlen != sumsize) { + dbg_summary("Summary node is corrupt (wrong erasesize?)\n"); + goto crc_err; + } + + crc = crc32_no_comp(0, (uchar *)summary, + sizeof(struct jffs2_raw_summary)-8); + + if (summary->node_crc != crc) { + dbg_summary("Summary node is corrupt (bad CRC)\n"); + goto crc_err; + } + + crc = crc32_no_comp(0, (uchar *)summary->sum, + sumsize - sizeof(struct jffs2_raw_summary)); + + if (summary->sum_crc != crc) { + dbg_summary("Summary node data is corrupt (bad CRC)\n"); + goto crc_err; + } + + if (summary->cln_mkr) + 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 */ + + return 1; + +crc_err: + putstr("Summary node crc error, skipping summary information.\n"); + + return 0; +} +#endif /* CONFIG_JFFS2_SUMMARY */ + #ifdef DEBUG_FRAGMENTS static void dump_fragments(struct b_lists *pL) @@ -1277,12 +1456,7 @@ 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 +#define DEFAULT_EMPTY_SCAN_SIZE 256 static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) { @@ -1297,15 +1471,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. */ @@ -1314,17 +1489,85 @@ 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 */ 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 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 + * buffer + */ + get_fl_mem(part->offset + sector_ofs + part->sector_size - + buf_len, buf_len, buf + buf_size - buf_len); + + sm = (void *)buf + buf_size - sizeof(*sm); + if (sm->magic == JFFS2_SUM_MAGIC) { + sumlen = part->sector_size - sm->offset; + sumptr = buf + buf_size - sumlen; + + /* Now, make sure the summary itself is available */ + if (sumlen > buf_size) { + /* Need to kmalloc for this. */ + sumptr = malloc(sumlen); + 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 + + buf_size - buf_len, buf_len); + } + if (buf_len < sumlen) { + /* Need to read more so that the entire summary + * node is present + */ + get_fl_mem(part->offset + sector_ofs + + part->sector_size - sumlen, + sumlen - buf_len, sumptr); + } + } + + if (sumptr) { + ret = jffs2_sum_scan_sumnode(part, sector_ofs, sumptr, + sumlen, pL); + + if (buf_size && sumlen > buf_size) + free(sumptr); + 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); + get_fl_mem((u32)part->offset + buf_ofs, buf_len, buf); /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ @@ -1340,6 +1583,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) { @@ -1365,9 +1613,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, @@ -1383,6 +1630,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... @@ -1404,6 +1659,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; @@ -1421,17 +1681,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; @@ -1441,6 +1709,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; @@ -1457,8 +1730,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++; @@ -1469,6 +1745,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)) @@ -1477,6 +1763,8 @@ jffs2_1pass_build_lists(struct part_info * part) node->totlen, sizeof(struct jffs2_unknown_node)); break; + case JFFS2_NODETYPE_SUMMARY: + break; default: printf("Unknown node type: %x len %d offset 0x%x\n", node->nodetype, @@ -1488,6 +1776,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