diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-05-20 11:13:34 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-20 11:13:34 -0400 |
commit | 9641b784ff82cf0a48a6c70ef9867f5fd728de67 (patch) | |
tree | 40d7bbc06ee5e54560ea7e7dabe75ac01a72e00c /fs | |
parent | 6c8b44abc86a3e23dd1a22c0ee187f06bd7c7f5d (diff) |
[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: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/jffs2/scan.c | 74 | ||||
-rw-r--r-- | fs/jffs2/summary.c | 36 | ||||
-rw-r--r-- | fs/jffs2/summary.h | 3 |
3 files changed, 64 insertions, 49 deletions
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 352ada892f3e..2a24b44662bb 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -306,11 +306,12 @@ int jffs2_scan_classify_jeb(struct jffs2_sb_info *c, struct jffs2_eraseblock *je | |||
306 | return BLK_STATE_ALLDIRTY; | 306 | return BLK_STATE_ALLDIRTY; |
307 | } | 307 | } |
308 | 308 | ||
309 | /* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into | ||
310 | the flash, XIP-style */ | ||
309 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 311 | static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
310 | unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { | 312 | unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) { |
311 | struct jffs2_unknown_node *node; | 313 | struct jffs2_unknown_node *node; |
312 | struct jffs2_unknown_node crcnode; | 314 | struct jffs2_unknown_node crcnode; |
313 | struct jffs2_sum_marker *sm; | ||
314 | uint32_t ofs, prevofs; | 315 | uint32_t ofs, prevofs; |
315 | uint32_t hdr_crc, buf_ofs, buf_len; | 316 | uint32_t hdr_crc, buf_ofs, buf_len; |
316 | int err; | 317 | int err; |
@@ -344,32 +345,69 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo | |||
344 | #endif | 345 | #endif |
345 | 346 | ||
346 | if (jffs2_sum_active()) { | 347 | if (jffs2_sum_active()) { |
347 | sm = kmalloc(sizeof(struct jffs2_sum_marker), GFP_KERNEL); | 348 | struct jffs2_sum_marker *sm; |
348 | if (!sm) { | 349 | void *sumptr = NULL; |
349 | return -ENOMEM; | 350 | uint32_t sumlen; |
350 | } | 351 | |
352 | if (!buf_size) { | ||
353 | /* XIP case. Just look, point at the summary if it's there */ | ||
354 | sm = (void *)buf + jeb->offset - sizeof(*sm); | ||
355 | if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { | ||
356 | sumptr = buf + je32_to_cpu(sm->offset); | ||
357 | sumlen = c->sector_size - je32_to_cpu(sm->offset); | ||
358 | } | ||
359 | } else { | ||
360 | /* If NAND flash, read a whole page of it. Else just the end */ | ||
361 | if (c->wbuf_pagesize) | ||
362 | buf_len = c->wbuf_pagesize; | ||
363 | else | ||
364 | buf_len = sizeof(*sm); | ||
365 | |||
366 | /* Read as much as we want into the _end_ of the preallocated buffer */ | ||
367 | err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len, | ||
368 | jeb->offset + c->sector_size - buf_len, | ||
369 | buf_len); | ||
370 | if (err) | ||
371 | return err; | ||
372 | |||
373 | sm = (void *)buf + buf_size - sizeof(*sm); | ||
374 | if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) { | ||
375 | sumlen = c->sector_size - je32_to_cpu(sm->offset); | ||
376 | sumptr = buf + buf_size - sumlen; | ||
377 | |||
378 | /* Now, make sure the summary itself is available */ | ||
379 | if (sumlen > buf_size) { | ||
380 | /* Need to kmalloc for this. */ | ||
381 | sumptr = kmalloc(sumlen, GFP_KERNEL); | ||
382 | if (!sumptr) | ||
383 | return -ENOMEM; | ||
384 | memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len); | ||
385 | } | ||
386 | if (buf_len < sumlen) { | ||
387 | /* Need to read more so that the entire summary node is present */ | ||
388 | err = jffs2_fill_scan_buf(c, sumptr, | ||
389 | jeb->offset + c->sector_size - sumlen, | ||
390 | sumlen - buf_len); | ||
391 | if (err) | ||
392 | return err; | ||
393 | } | ||
394 | } | ||
351 | 395 | ||
352 | err = jffs2_fill_scan_buf(c, (unsigned char *) sm, jeb->offset + c->sector_size - | ||
353 | sizeof(struct jffs2_sum_marker), sizeof(struct jffs2_sum_marker)); | ||
354 | if (err) { | ||
355 | kfree(sm); | ||
356 | return err; | ||
357 | } | 396 | } |
358 | 397 | ||
359 | if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC ) { | 398 | if (sumptr) { |
360 | err = jffs2_sum_scan_sumnode(c, jeb, je32_to_cpu(sm->offset), &pseudo_random); | 399 | err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random); |
361 | if (err) { | 400 | if (err) |
362 | kfree(sm); | ||
363 | return err; | 401 | return err; |
364 | } | 402 | if (buf_size && sumlen > buf_size) |
403 | kfree(sumptr); | ||
365 | } | 404 | } |
366 | |||
367 | kfree(sm); | ||
368 | } | 405 | } |
369 | 406 | ||
370 | buf_ofs = jeb->offset; | 407 | buf_ofs = jeb->offset; |
371 | 408 | ||
372 | if (!buf_size) { | 409 | if (!buf_size) { |
410 | /* This is the XIP case -- we're reading _directly_ from the flash chip */ | ||
373 | buf_len = c->sector_size; | 411 | buf_len = c->sector_size; |
374 | } else { | 412 | } else { |
375 | buf_len = EMPTY_SCAN_SIZE(c->sector_size); | 413 | buf_len = EMPTY_SCAN_SIZE(c->sector_size); |
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 48293c197f13..82a3706c54d8 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
@@ -318,7 +318,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
318 | raw = jffs2_alloc_raw_node_ref(); | 318 | raw = jffs2_alloc_raw_node_ref(); |
319 | if (!raw) { | 319 | if (!raw) { |
320 | JFFS2_NOTICE("allocation of node reference failed\n"); | 320 | JFFS2_NOTICE("allocation of node reference failed\n"); |
321 | kfree(summary); | ||
322 | return -ENOMEM; | 321 | return -ENOMEM; |
323 | } | 322 | } |
324 | 323 | ||
@@ -326,7 +325,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
326 | if (!ic) { | 325 | if (!ic) { |
327 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); | 326 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); |
328 | jffs2_free_raw_node_ref(raw); | 327 | jffs2_free_raw_node_ref(raw); |
329 | kfree(summary); | ||
330 | return -ENOMEM; | 328 | return -ENOMEM; |
331 | } | 329 | } |
332 | 330 | ||
@@ -358,10 +356,8 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
358 | jeb->offset + je32_to_cpu(spd->offset)); | 356 | jeb->offset + je32_to_cpu(spd->offset)); |
359 | 357 | ||
360 | fd = jffs2_alloc_full_dirent(spd->nsize+1); | 358 | fd = jffs2_alloc_full_dirent(spd->nsize+1); |
361 | if (!fd) { | 359 | if (!fd) |
362 | kfree(summary); | ||
363 | return -ENOMEM; | 360 | return -ENOMEM; |
364 | } | ||
365 | 361 | ||
366 | memcpy(&fd->name, spd->name, spd->nsize); | 362 | memcpy(&fd->name, spd->name, spd->nsize); |
367 | fd->name[spd->nsize] = 0; | 363 | 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 | if (!raw) { | 366 | if (!raw) { |
371 | jffs2_free_full_dirent(fd); | 367 | jffs2_free_full_dirent(fd); |
372 | JFFS2_NOTICE("allocation of node reference failed\n"); | 368 | JFFS2_NOTICE("allocation of node reference failed\n"); |
373 | kfree(summary); | ||
374 | return -ENOMEM; | 369 | return -ENOMEM; |
375 | } | 370 | } |
376 | 371 | ||
@@ -378,7 +373,6 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
378 | if (!ic) { | 373 | if (!ic) { |
379 | jffs2_free_full_dirent(fd); | 374 | jffs2_free_full_dirent(fd); |
380 | jffs2_free_raw_node_ref(raw); | 375 | jffs2_free_raw_node_ref(raw); |
381 | kfree(summary); | ||
382 | return -ENOMEM; | 376 | return -ENOMEM; |
383 | } | 377 | } |
384 | 378 | ||
@@ -411,45 +405,28 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
411 | 405 | ||
412 | default : { | 406 | default : { |
413 | JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); | 407 | JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); |
414 | kfree(summary); | ||
415 | return -EIO; | 408 | return -EIO; |
416 | } | 409 | } |
417 | } | 410 | } |
418 | } | 411 | } |
419 | 412 | ||
420 | kfree(summary); | ||
421 | return 0; | 413 | return 0; |
422 | } | 414 | } |
423 | 415 | ||
424 | /* Process the summary node - called from jffs2_scan_eraseblock() */ | 416 | /* Process the summary node - called from jffs2_scan_eraseblock() */ |
425 | |||
426 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 417 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
427 | uint32_t ofs, uint32_t *pseudo_random) | 418 | struct jffs2_raw_summary *summary, uint32_t sumsize, |
419 | uint32_t *pseudo_random) | ||
428 | { | 420 | { |
429 | struct jffs2_unknown_node crcnode; | 421 | struct jffs2_unknown_node crcnode; |
430 | struct jffs2_raw_node_ref *cache_ref; | 422 | struct jffs2_raw_node_ref *cache_ref; |
431 | struct jffs2_raw_summary *summary; | 423 | int ret, ofs; |
432 | int ret, sumsize; | ||
433 | uint32_t crc; | 424 | uint32_t crc; |
434 | 425 | ||
435 | sumsize = c->sector_size - ofs; | 426 | ofs = jeb->offset + c->sector_size - sumsize; |
436 | ofs += jeb->offset; | ||
437 | 427 | ||
438 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", | 428 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", |
439 | jeb->offset, ofs, sumsize); | 429 | jeb->offset, ofs, sumsize); |
440 | |||
441 | summary = kmalloc(sumsize, GFP_KERNEL); | ||
442 | |||
443 | if (!summary) { | ||
444 | return -ENOMEM; | ||
445 | } | ||
446 | |||
447 | ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize); | ||
448 | |||
449 | if (ret) { | ||
450 | kfree(summary); | ||
451 | return ret; | ||
452 | } | ||
453 | 430 | ||
454 | /* OK, now check for node validity and CRC */ | 431 | /* OK, now check for node validity and CRC */ |
455 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 432 | 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 | 476 | ||
500 | if (!marker_ref) { | 477 | if (!marker_ref) { |
501 | JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); | 478 | JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); |
502 | kfree(summary); | ||
503 | return -ENOMEM; | 479 | return -ENOMEM; |
504 | } | 480 | } |
505 | 481 | ||
diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h index b7a678be1709..afff4bd551a1 100644 --- a/fs/jffs2/summary.h +++ b/fs/jffs2/summary.h | |||
@@ -160,7 +160,8 @@ int jffs2_sum_add_padding_mem(struct jffs2_summary *s, uint32_t size); | |||
160 | int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); | 160 | int jffs2_sum_add_inode_mem(struct jffs2_summary *s, struct jffs2_raw_inode *ri, uint32_t ofs); |
161 | int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); | 161 | int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *rd, uint32_t ofs); |
162 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 162 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
163 | uint32_t ofs, uint32_t *pseudo_random); | 163 | struct jffs2_raw_summary *summary, uint32_t sumlen, |
164 | uint32_t *pseudo_random); | ||
164 | 165 | ||
165 | #else /* SUMMARY DISABLED */ | 166 | #else /* SUMMARY DISABLED */ |
166 | 167 | ||