Commit 9641b784 authored by David Woodhouse's avatar David Woodhouse

[JFFS2] Optimise reading of eraseblock summary nodes

This improves the time to mount 512MiB of NAND flash on my OLPC prototype
by about 4%. We used to read the last page of the eraseblock twice -- once
to find the offset of the summary node, and again to actually _read_ the
summary node. Now we read the last page only once, and read more only if
we need to.

We also don't allocate a new buffer just for the summary code -- we use
the buffer which was already allocated for the scan. Better still, if the
'buffer' for the scan is actually just a pointer directly into NOR flash,
we use that too, avoiding the memcpy() which we used to do.
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 6c8b44ab
...@@ -306,11 +306,12 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je ...@@ -306,11 +306,12 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
return BLK_STATE_ALLDIRTY; return BLK_STATE_ALLDIRTY;
} }
/* 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, 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 *node;
struct jffs2_unknown_node crcnode; struct jffs2_unknown_node crcnode;
struct jffs2_sum_marker *sm;
uint32_t ofs, prevofs; uint32_t ofs, prevofs;
uint32_t hdr_crc, buf_ofs, buf_len; uint32_t hdr_crc, buf_ofs, buf_len;
int err; int err;
...@@ -344,32 +345,69 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ...@@ -344,32 +345,69 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
#endif #endif
if (jffs2_sum_active()) { if (jffs2_sum_active()) {
sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL); struct jffs2_sum_marker *sm;
if (!sm) { void *sumptr = NULL;
return -ENOMEM; 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 ) { if (sumptr) {
err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random); err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random);
if (err) { if (err)
kfree(sm);
return err; return err;
} if (buf_size && sumlen > buf_size)
kfree(sumptr);
} }
kfree(sm);
} }
buf_ofs = jeb->offset; buf_ofs = jeb->offset;
if (!buf_size) { if (!buf_size) {
/* This is the XIP case -- we're reading _directly_ from the flash chip */
buf_len = c->sector_size; buf_len = c->sector_size;
} else { } else {
buf_len = EMPTY_SCAN_SIZE(c->sector_size); buf_len = EMPTY_SCAN_SIZE(c->sector_size);
......
...@@ -318,7 +318,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -318,7 +318,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
raw = jffs2_alloc_raw_node_ref(); raw = jffs2_alloc_raw_node_ref();
if (!raw) { if (!raw) {
JFFS2_NOTICE("allocation of node reference failed\n"); JFFS2_NOTICE("allocation of node reference failed\n");
kfree(summary);
return -ENOMEM; return -ENOMEM;
} }
...@@ -326,7 +325,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -326,7 +325,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!ic) { if (!ic) {
JFFS2_NOTICE("scan_make_ino_cache failed\n"); JFFS2_NOTICE("scan_make_ino_cache failed\n");
jffs2_free_raw_node_ref(raw); jffs2_free_raw_node_ref(raw);
kfree(summary);
return -ENOMEM; return -ENOMEM;
} }
...@@ -358,10 +356,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -358,10 +356,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
jeb->offset + je32_to_cpu(spd->offset)); jeb->offset + je32_to_cpu(spd->offset));
fd = jffs2_alloc_full_dirent(spd->nsize+1); fd = jffs2_alloc_full_dirent(spd->nsize+1);
if (!fd) { if (!fd)
kfree(summary);
return -ENOMEM; return -ENOMEM;
}
memcpy(&fd->name, spd->name, spd->nsize); memcpy(&fd->name, spd->name, spd->nsize);
fd->name[spd->nsize] = 0; fd->name[spd->nsize] = 0;
...@@ -370,7 +366,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -370,7 +366,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!raw) { if (!raw) {
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
JFFS2_NOTICE("allocation of node reference failed\n"); JFFS2_NOTICE("allocation of node reference failed\n");
kfree(summary);
return -ENOMEM; return -ENOMEM;
} }
...@@ -378,7 +373,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -378,7 +373,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!ic) { if (!ic) {
jffs2_free_full_dirent(fd); jffs2_free_full_dirent(fd);
jffs2_free_raw_node_ref(raw); jffs2_free_raw_node_ref(raw);
kfree(summary);
return -ENOMEM; return -ENOMEM;
} }
...@@ -411,45 +405,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras ...@@ -411,45 +405,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
default : { default : {
JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
kfree(summary);
return -EIO; return -EIO;
} }
} }
} }
kfree(summary);
return 0; return 0;
} }
/* Process the summary node - called from jffs2_scan_eraseblock() */ /* Process the summary node - called from jffs2_scan_eraseblock() */
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random) struct jffs2_raw_summary *summary, uint32_t sumsize,
uint32_t *pseudo_random)
{ {
struct jffs2_unknown_node crcnode; struct jffs2_unknown_node crcnode;
struct jffs2_raw_node_ref *cache_ref; struct jffs2_raw_node_ref *cache_ref;
struct jffs2_raw_summary *summary; int ret, ofs;
int ret, sumsize;
uint32_t crc; uint32_t crc;
sumsize = c->sector_size - ofs; ofs = jeb->offset + c->sector_size - sumsize;
ofs += jeb->offset;
dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
jeb->offset, ofs, sumsize); jeb->offset, ofs, sumsize);
summary = kmalloc(sumsize, GFP_KERNEL);
if (!summary) {
return -ENOMEM;
}
ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);
if (ret) {
kfree(summary);
return ret;
}
/* OK, now check for node validity and CRC */ /* OK, now check for node validity and CRC */
crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
...@@ -499,7 +476,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb ...@@ -499,7 +476,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb
if (!marker_ref) { if (!marker_ref) {
JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
kfree(summary);
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -160,7 +160,8 @@ int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); ...@@ -160,7 +160,8 @@ int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size);
int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs);
int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs);
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
uint32_t ofs, uint32_t *pseudo_random); struct jffs2_raw_summary *summary, uint32_t sumlen,
uint32_t *pseudo_random);
#else /* SUMMARY DISABLED */ #else /* SUMMARY DISABLED */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment