Skip to content

Commit

Permalink
[JFFS2] Optimise reading of eraseblock summary nodes
Browse files Browse the repository at this point in the history
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: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
David Woodhouse committed May 20, 2006
1 parent 6c8b44a commit 9641b78
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 49 deletions.
74 changes: 56 additions & 18 deletions fs/jffs2/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -306,11 +306,12 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je
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,
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;
Expand Down Expand Up @@ -344,32 +345,69 @@ 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);
}

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;
} else {
buf_len = EMPTY_SCAN_SIZE(c->sector_size);
Expand Down
36 changes: 6 additions & 30 deletions fs/jffs2/summary.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,15 +318,13 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
raw = jffs2_alloc_raw_node_ref();
if (!raw) {
JFFS2_NOTICE("allocation of node reference failed\n");
kfree(summary);
return -ENOMEM;
}

ic = jffs2_scan_make_ino_cache(c, ino);
if (!ic) {
JFFS2_NOTICE("scan_make_ino_cache failed\n");
jffs2_free_raw_node_ref(raw);
kfree(summary);
return -ENOMEM;
}

Expand Down Expand Up @@ -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));

fd = jffs2_alloc_full_dirent(spd->nsize+1);
if (!fd) {
kfree(summary);
if (!fd)
return -ENOMEM;
}

memcpy(&fd->name, spd->name, spd->nsize);
fd->name[spd->nsize] = 0;
Expand All @@ -370,15 +366,13 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras
if (!raw) {
jffs2_free_full_dirent(fd);
JFFS2_NOTICE("allocation of node reference failed\n");
kfree(summary);
return -ENOMEM;
}

ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
if (!ic) {
jffs2_free_full_dirent(fd);
jffs2_free_raw_node_ref(raw);
kfree(summary);
return -ENOMEM;
}

Expand Down Expand Up @@ -411,45 +405,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras

default : {
JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
kfree(summary);
return -EIO;
}
}
}

kfree(summary);
return 0;
}

/* Process the summary node - called from jffs2_scan_eraseblock() */

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_raw_node_ref *cache_ref;
struct jffs2_raw_summary *summary;
int ret, sumsize;
int ret, ofs;
uint32_t crc;

sumsize = c->sector_size - ofs;
ofs += jeb->offset;
ofs = jeb->offset + c->sector_size - sumsize;

dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
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;
}
jeb->offset, ofs, sumsize);

/* OK, now check for node validity and CRC */
crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
Expand Down Expand Up @@ -499,7 +476,6 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb

if (!marker_ref) {
JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
kfree(summary);
return -ENOMEM;
}

Expand Down
3 changes: 2 additions & 1 deletion fs/jffs2/summary.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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,
uint32_t ofs, uint32_t *pseudo_random);
struct jffs2_raw_summary *summary, uint32_t sumlen,
uint32_t *pseudo_random);

#else /* SUMMARY DISABLED */

Expand Down

0 comments on commit 9641b78

Please sign in to comment.