diff options
Diffstat (limited to 'fs/jffs2/scan.c')
-rw-r--r-- | fs/jffs2/scan.c | 85 |
1 files changed, 56 insertions, 29 deletions
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 5847e76ce16..40d62d057aa 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -437,11 +437,12 @@ static int jffs2_scan_xref_node(struct jffs2_sb_info *c, struct jffs2_eraseblock } #endif +/* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into + the flash, XIP-style */ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, - unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { + unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { struct jffs2_unknown_node *node; struct jffs2_unknown_node crcnode; - struct jffs2_sum_marker *sm; uint32_t ofs, prevofs; uint32_t hdr_crc, buf_ofs, buf_len; int err; @@ -475,44 +476,70 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo #endif if (jffs2_sum_active()) { - sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL); - if (!sm) { - return -ENOMEM; - } + struct jffs2_sum_marker *sm; + void *sumptr = NULL; + uint32_t sumlen; + + if (!buf_size) { + /* XIP case. Just look, point at the summary if it's there */ + sm = (void *)buf + jeb->offset - sizeof(*sm); + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { + sumptr = buf + je32_to_cpu(sm->offset); + sumlen = c->sector_size - je32_to_cpu(sm->offset); + } + } else { + /* If NAND flash, read a whole page of it. Else just the end */ + if (c->wbuf_pagesize) + buf_len = c->wbuf_pagesize; + else + buf_len = sizeof(*sm); + + /* Read as much as we want into the _end_ of the preallocated buffer */ + err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, + jeb->offset + c->sector_size - buf_len, + buf_len); + if (err) + return err; + + sm = (void *)buf + buf_size - sizeof(*sm); + if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { + sumlen = c->sector_size - je32_to_cpu(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 = kmalloc(sumlen, GFP_KERNEL); + if (!sumptr) + return -ENOMEM; + 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 */ + err = jffs2_fill_scan_buf(c, sumptr, + jeb->offset + c->sector_size - sumlen, + sumlen - buf_len); + if (err) + return err; + } + } - err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size - - sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker)); - if (err) { - kfree(sm); - return err; } - if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) { - err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random); - if (err) { - kfree(sm); + if (sumptr) { + err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random); + if (err) return err; - } + if (buf_size && sumlen > buf_size) + kfree(sumptr); } - - kfree(sm); - - ofs = jeb->offset; - prevofs = jeb->offset - 1; } buf_ofs = jeb->offset; if (!buf_size) { + /* This is the XIP case -- we're reading _directly_ from the flash chip */ buf_len = c->sector_size; - - if (jffs2_sum_active()) { - /* must reread because of summary test */ - err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); - if (err) - return err; - } - } else { buf_len = EMPTY_SCAN_SIZE(c->sector_size); err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); |