X-Git-Url: https://git.kernelconcepts.de/?p=karo-tx-uboot.git;a=blobdiff_plain;f=fs%2Fjffs2%2Fjffs2_1pass.c;h=e58e7d25cff128b248db26b99b0f50a73428a9bf;hp=be7c1a190b51a1c9aba5001886158fafae74df39;hb=ced4360c4a7a4e1509d2ebcfe8538bc871f56dc4;hpb=bd4345c175116df4a392f05c9f41679c545842d5 diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index be7c1a190b..e58e7d25cf 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -114,11 +114,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include #include "jffs2_private.h" @@ -145,11 +148,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 * @@ -160,12 +159,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)) @@ -200,15 +193,6 @@ 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 || @@ -217,7 +201,6 @@ static int read_nand_cached(u32 off, u32 size, u_char *buf) 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) @@ -416,23 +399,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; } @@ -440,23 +426,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; } @@ -489,9 +479,8 @@ static char *compr_names[] = { "COPY", "DYNRUBIN", "ZLIB", -#if defined(CONFIG_JFFS2_LZO_LZARI) +#if defined(CONFIG_JFFS2_LZO) "LZO", - "LZARI", #endif }; @@ -609,14 +598,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 @@ -626,42 +619,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 - */ - 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 + /* + * 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->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 @@ -708,7 +704,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 @@ -731,12 +726,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); @@ -759,7 +765,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); @@ -780,36 +794,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; @@ -818,7 +826,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++; @@ -851,7 +858,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); @@ -972,16 +978,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; - while (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; + } + + 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); @@ -994,7 +1031,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); @@ -1219,8 +1256,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() */ @@ -1229,54 +1288,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 (pass) { + spi = sp; - if (insert_node(&pL->frag, (u32) part->offset + - offset + spi->offset) == NULL) - return -1; + ret = insert_node(&pL->frag, + (u32)part->offset + + offset + + sum_get_unaligned32( + &spi->offset)); + if (ret == NULL) + return -1; + } - sp += JFFS2_SUMMARY_INODE_SIZE; + sp += JFFS2_SUMMARY_INODE_SIZE; - break; - } - - case JFFS2_NODETYPE_DIRENT: { - struct jffs2_sum_dirent_flash *spd; - spd = sp; - - 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; + } } } } @@ -1334,6 +1403,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 */ @@ -1344,6 +1415,7 @@ crc_err: return 0; } +#endif /* CONFIG_JFFS2_SUMMARY */ #ifdef DEBUG_FRAGMENTS static void @@ -1408,11 +1480,6 @@ 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) @@ -1428,7 +1495,7 @@ 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; @@ -1437,6 +1504,7 @@ jffs2_1pass_build_lists(struct part_info * part) u32 buf_size = DEFAULT_EMPTY_SCAN_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. */ @@ -1454,13 +1522,16 @@ 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 WATCHDOG_RESET(); +#ifdef CONFIG_JFFS2_SUMMARY buf_len = sizeof(*sm); /* Read as much as we want into the _end_ of the preallocated @@ -1481,6 +1552,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 + @@ -1502,12 +1575,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); @@ -1551,9 +1628,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, @@ -1616,8 +1692,11 @@ jffs2_1pass_build_lists(struct part_info * part) 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; @@ -1643,8 +1722,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++;