diff options
Diffstat (limited to 'fs/jffs2/summary.c')
-rw-r--r-- | fs/jffs2/summary.c | 484 |
1 files changed, 303 insertions, 181 deletions
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index fb9cec61fcf2..0b02fc79e4d1 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, | 5 | * Zoltan Sogor <weth@inf.u-szeged.hu>, |
6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, | 6 | * Patrik Kluba <pajko@halom.u-szeged.hu>, |
7 | * University of Szeged, Hungary | 7 | * University of Szeged, Hungary |
8 | * 2005 KaiGai Kohei <kaigai@ak.jp.nec.com> | ||
8 | * | 9 | * |
9 | * For licensing information, see the file 'LICENCE' in this directory. | 10 | * For licensing information, see the file 'LICENCE' in this directory. |
10 | * | 11 | * |
@@ -81,6 +82,19 @@ static int jffs2_sum_add_mem(struct jffs2_summary *s, union jffs2_sum_mem *item) | |||
81 | dbg_summary("dirent (%u) added to summary\n", | 82 | dbg_summary("dirent (%u) added to summary\n", |
82 | je32_to_cpu(item->d.ino)); | 83 | je32_to_cpu(item->d.ino)); |
83 | break; | 84 | break; |
85 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
86 | case JFFS2_NODETYPE_XATTR: | ||
87 | s->sum_size += JFFS2_SUMMARY_XATTR_SIZE; | ||
88 | s->sum_num++; | ||
89 | dbg_summary("xattr (xid=%u, version=%u) added to summary\n", | ||
90 | je32_to_cpu(item->x.xid), je32_to_cpu(item->x.version)); | ||
91 | break; | ||
92 | case JFFS2_NODETYPE_XREF: | ||
93 | s->sum_size += JFFS2_SUMMARY_XREF_SIZE; | ||
94 | s->sum_num++; | ||
95 | dbg_summary("xref added to summary\n"); | ||
96 | break; | ||
97 | #endif | ||
84 | default: | 98 | default: |
85 | JFFS2_WARNING("UNKNOWN node type %u\n", | 99 | JFFS2_WARNING("UNKNOWN node type %u\n", |
86 | je16_to_cpu(item->u.nodetype)); | 100 | je16_to_cpu(item->u.nodetype)); |
@@ -141,6 +155,40 @@ int jffs2_sum_add_dirent_mem(struct jffs2_summary *s, struct jffs2_raw_dirent *r | |||
141 | return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); | 155 | return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); |
142 | } | 156 | } |
143 | 157 | ||
158 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
159 | int jffs2_sum_add_xattr_mem(struct jffs2_summary *s, struct jffs2_raw_xattr *rx, uint32_t ofs) | ||
160 | { | ||
161 | struct jffs2_sum_xattr_mem *temp; | ||
162 | |||
163 | temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); | ||
164 | if (!temp) | ||
165 | return -ENOMEM; | ||
166 | |||
167 | temp->nodetype = rx->nodetype; | ||
168 | temp->xid = rx->xid; | ||
169 | temp->version = rx->version; | ||
170 | temp->offset = cpu_to_je32(ofs); | ||
171 | temp->totlen = rx->totlen; | ||
172 | temp->next = NULL; | ||
173 | |||
174 | return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); | ||
175 | } | ||
176 | |||
177 | int jffs2_sum_add_xref_mem(struct jffs2_summary *s, struct jffs2_raw_xref *rr, uint32_t ofs) | ||
178 | { | ||
179 | struct jffs2_sum_xref_mem *temp; | ||
180 | |||
181 | temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); | ||
182 | if (!temp) | ||
183 | return -ENOMEM; | ||
184 | |||
185 | temp->nodetype = rr->nodetype; | ||
186 | temp->offset = cpu_to_je32(ofs); | ||
187 | temp->next = NULL; | ||
188 | |||
189 | return jffs2_sum_add_mem(s, (union jffs2_sum_mem *)temp); | ||
190 | } | ||
191 | #endif | ||
144 | /* Cleanup every collected summary information */ | 192 | /* Cleanup every collected summary information */ |
145 | 193 | ||
146 | static void jffs2_sum_clean_collected(struct jffs2_summary *s) | 194 | static void jffs2_sum_clean_collected(struct jffs2_summary *s) |
@@ -259,7 +307,40 @@ int jffs2_sum_add_kvec(struct jffs2_sb_info *c, const struct kvec *invecs, | |||
259 | 307 | ||
260 | return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); | 308 | return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); |
261 | } | 309 | } |
310 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
311 | case JFFS2_NODETYPE_XATTR: { | ||
312 | struct jffs2_sum_xattr_mem *temp; | ||
313 | if (je32_to_cpu(node->x.version) == 0xffffffff) | ||
314 | return 0; | ||
315 | temp = kmalloc(sizeof(struct jffs2_sum_xattr_mem), GFP_KERNEL); | ||
316 | if (!temp) | ||
317 | goto no_mem; | ||
318 | |||
319 | temp->nodetype = node->x.nodetype; | ||
320 | temp->xid = node->x.xid; | ||
321 | temp->version = node->x.version; | ||
322 | temp->totlen = node->x.totlen; | ||
323 | temp->offset = cpu_to_je32(ofs); | ||
324 | temp->next = NULL; | ||
325 | |||
326 | return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); | ||
327 | } | ||
328 | case JFFS2_NODETYPE_XREF: { | ||
329 | struct jffs2_sum_xref_mem *temp; | ||
330 | |||
331 | if (je32_to_cpu(node->r.ino) == 0xffffffff | ||
332 | && je32_to_cpu(node->r.xid) == 0xffffffff) | ||
333 | return 0; | ||
334 | temp = kmalloc(sizeof(struct jffs2_sum_xref_mem), GFP_KERNEL); | ||
335 | if (!temp) | ||
336 | goto no_mem; | ||
337 | temp->nodetype = node->r.nodetype; | ||
338 | temp->offset = cpu_to_je32(ofs); | ||
339 | temp->next = NULL; | ||
262 | 340 | ||
341 | return jffs2_sum_add_mem(c->summary, (union jffs2_sum_mem *)temp); | ||
342 | } | ||
343 | #endif | ||
263 | case JFFS2_NODETYPE_PADDING: | 344 | case JFFS2_NODETYPE_PADDING: |
264 | dbg_summary("node PADDING\n"); | 345 | dbg_summary("node PADDING\n"); |
265 | c->summary->sum_padded += je32_to_cpu(node->u.totlen); | 346 | c->summary->sum_padded += je32_to_cpu(node->u.totlen); |
@@ -288,23 +369,41 @@ no_mem: | |||
288 | return -ENOMEM; | 369 | return -ENOMEM; |
289 | } | 370 | } |
290 | 371 | ||
372 | static struct jffs2_raw_node_ref *sum_link_node_ref(struct jffs2_sb_info *c, | ||
373 | struct jffs2_eraseblock *jeb, | ||
374 | uint32_t ofs, uint32_t len, | ||
375 | struct jffs2_inode_cache *ic) | ||
376 | { | ||
377 | /* If there was a gap, mark it dirty */ | ||
378 | if ((ofs & ~3) > c->sector_size - jeb->free_size) { | ||
379 | /* Ew. Summary doesn't actually tell us explicitly about dirty space */ | ||
380 | jffs2_scan_dirty_space(c, jeb, (ofs & ~3) - (c->sector_size - jeb->free_size)); | ||
381 | } | ||
382 | |||
383 | return jffs2_link_node_ref(c, jeb, jeb->offset + ofs, len, ic); | ||
384 | } | ||
291 | 385 | ||
292 | /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ | 386 | /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ |
293 | 387 | ||
294 | static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | 388 | static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
295 | struct jffs2_raw_summary *summary, uint32_t *pseudo_random) | 389 | struct jffs2_raw_summary *summary, uint32_t *pseudo_random) |
296 | { | 390 | { |
297 | struct jffs2_raw_node_ref *raw; | ||
298 | struct jffs2_inode_cache *ic; | 391 | struct jffs2_inode_cache *ic; |
299 | struct jffs2_full_dirent *fd; | 392 | struct jffs2_full_dirent *fd; |
300 | void *sp; | 393 | void *sp; |
301 | int i, ino; | 394 | int i, ino; |
395 | int err; | ||
302 | 396 | ||
303 | sp = summary->sum; | 397 | sp = summary->sum; |
304 | 398 | ||
305 | for (i=0; i<je32_to_cpu(summary->sum_num); i++) { | 399 | for (i=0; i<je32_to_cpu(summary->sum_num); i++) { |
306 | dbg_summary("processing summary index %d\n", i); | 400 | dbg_summary("processing summary index %d\n", i); |
307 | 401 | ||
402 | /* Make sure there's a spare ref for dirty space */ | ||
403 | err = jffs2_prealloc_raw_node_refs(c, jeb, 2); | ||
404 | if (err) | ||
405 | return err; | ||
406 | |||
308 | switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { | 407 | switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) { |
309 | case JFFS2_NODETYPE_INODE: { | 408 | case JFFS2_NODETYPE_INODE: { |
310 | struct jffs2_sum_inode_flash *spi; | 409 | struct jffs2_sum_inode_flash *spi; |
@@ -312,38 +411,20 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
312 | 411 | ||
313 | ino = je32_to_cpu(spi->inode); | 412 | ino = je32_to_cpu(spi->inode); |
314 | 413 | ||
315 | dbg_summary("Inode at 0x%08x\n", | 414 | dbg_summary("Inode at 0x%08x-0x%08x\n", |
316 | jeb->offset + je32_to_cpu(spi->offset)); | 415 | jeb->offset + je32_to_cpu(spi->offset), |
317 | 416 | jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen)); | |
318 | raw = jffs2_alloc_raw_node_ref(); | ||
319 | if (!raw) { | ||
320 | JFFS2_NOTICE("allocation of node reference failed\n"); | ||
321 | kfree(summary); | ||
322 | return -ENOMEM; | ||
323 | } | ||
324 | 417 | ||
325 | ic = jffs2_scan_make_ino_cache(c, ino); | 418 | ic = jffs2_scan_make_ino_cache(c, ino); |
326 | if (!ic) { | 419 | if (!ic) { |
327 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); | 420 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); |
328 | jffs2_free_raw_node_ref(raw); | ||
329 | kfree(summary); | ||
330 | return -ENOMEM; | 421 | return -ENOMEM; |
331 | } | 422 | } |
332 | 423 | ||
333 | raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED; | 424 | sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED, |
334 | raw->__totlen = PAD(je32_to_cpu(spi->totlen)); | 425 | PAD(je32_to_cpu(spi->totlen)), ic); |
335 | raw->next_phys = NULL; | ||
336 | raw->next_in_ino = ic->nodes; | ||
337 | |||
338 | ic->nodes = raw; | ||
339 | if (!jeb->first_node) | ||
340 | jeb->first_node = raw; | ||
341 | if (jeb->last_node) | ||
342 | jeb->last_node->next_phys = raw; | ||
343 | jeb->last_node = raw; | ||
344 | *pseudo_random += je32_to_cpu(spi->version); | ||
345 | 426 | ||
346 | UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen))); | 427 | *pseudo_random += je32_to_cpu(spi->version); |
347 | 428 | ||
348 | sp += JFFS2_SUMMARY_INODE_SIZE; | 429 | sp += JFFS2_SUMMARY_INODE_SIZE; |
349 | 430 | ||
@@ -354,52 +435,33 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
354 | struct jffs2_sum_dirent_flash *spd; | 435 | struct jffs2_sum_dirent_flash *spd; |
355 | spd = sp; | 436 | spd = sp; |
356 | 437 | ||
357 | dbg_summary("Dirent at 0x%08x\n", | 438 | dbg_summary("Dirent at 0x%08x-0x%08x\n", |
358 | jeb->offset + je32_to_cpu(spd->offset)); | 439 | jeb->offset + je32_to_cpu(spd->offset), |
440 | jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); | ||
441 | |||
359 | 442 | ||
360 | fd = jffs2_alloc_full_dirent(spd->nsize+1); | 443 | fd = jffs2_alloc_full_dirent(spd->nsize+1); |
361 | if (!fd) { | 444 | if (!fd) |
362 | kfree(summary); | ||
363 | return -ENOMEM; | 445 | return -ENOMEM; |
364 | } | ||
365 | 446 | ||
366 | memcpy(&fd->name, spd->name, spd->nsize); | 447 | memcpy(&fd->name, spd->name, spd->nsize); |
367 | fd->name[spd->nsize] = 0; | 448 | fd->name[spd->nsize] = 0; |
368 | 449 | ||
369 | raw = jffs2_alloc_raw_node_ref(); | ||
370 | if (!raw) { | ||
371 | jffs2_free_full_dirent(fd); | ||
372 | JFFS2_NOTICE("allocation of node reference failed\n"); | ||
373 | kfree(summary); | ||
374 | return -ENOMEM; | ||
375 | } | ||
376 | |||
377 | ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); | 450 | ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino)); |
378 | if (!ic) { | 451 | if (!ic) { |
379 | jffs2_free_full_dirent(fd); | 452 | jffs2_free_full_dirent(fd); |
380 | jffs2_free_raw_node_ref(raw); | ||
381 | kfree(summary); | ||
382 | return -ENOMEM; | 453 | return -ENOMEM; |
383 | } | 454 | } |
384 | 455 | ||
385 | raw->__totlen = PAD(je32_to_cpu(spd->totlen)); | 456 | fd->raw = sum_link_node_ref(c, jeb, je32_to_cpu(spd->offset) | REF_UNCHECKED, |
386 | raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE; | 457 | PAD(je32_to_cpu(spd->totlen)), ic); |
387 | raw->next_phys = NULL; | 458 | |
388 | raw->next_in_ino = ic->nodes; | ||
389 | ic->nodes = raw; | ||
390 | if (!jeb->first_node) | ||
391 | jeb->first_node = raw; | ||
392 | if (jeb->last_node) | ||
393 | jeb->last_node->next_phys = raw; | ||
394 | jeb->last_node = raw; | ||
395 | |||
396 | fd->raw = raw; | ||
397 | fd->next = NULL; | 459 | fd->next = NULL; |
398 | fd->version = je32_to_cpu(spd->version); | 460 | fd->version = je32_to_cpu(spd->version); |
399 | fd->ino = je32_to_cpu(spd->ino); | 461 | fd->ino = je32_to_cpu(spd->ino); |
400 | fd->nhash = full_name_hash(fd->name, spd->nsize); | 462 | fd->nhash = full_name_hash(fd->name, spd->nsize); |
401 | fd->type = spd->type; | 463 | fd->type = spd->type; |
402 | USED_SPACE(PAD(je32_to_cpu(spd->totlen))); | 464 | |
403 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); | 465 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); |
404 | 466 | ||
405 | *pseudo_random += je32_to_cpu(spd->version); | 467 | *pseudo_random += je32_to_cpu(spd->version); |
@@ -408,48 +470,105 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
408 | 470 | ||
409 | break; | 471 | break; |
410 | } | 472 | } |
473 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
474 | case JFFS2_NODETYPE_XATTR: { | ||
475 | struct jffs2_xattr_datum *xd; | ||
476 | struct jffs2_sum_xattr_flash *spx; | ||
477 | |||
478 | spx = (struct jffs2_sum_xattr_flash *)sp; | ||
479 | dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", | ||
480 | jeb->offset + je32_to_cpu(spx->offset), | ||
481 | jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), | ||
482 | je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); | ||
483 | |||
484 | xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), | ||
485 | je32_to_cpu(spx->version)); | ||
486 | if (IS_ERR(xd)) { | ||
487 | if (PTR_ERR(xd) == -EEXIST) { | ||
488 | /* a newer version of xd exists */ | ||
489 | if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen)))) | ||
490 | return err; | ||
491 | sp += JFFS2_SUMMARY_XATTR_SIZE; | ||
492 | break; | ||
493 | } | ||
494 | JFFS2_NOTICE("allocation of xattr_datum failed\n"); | ||
495 | return PTR_ERR(xd); | ||
496 | } | ||
497 | |||
498 | xd->node = sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED, | ||
499 | PAD(je32_to_cpu(spx->totlen)), NULL); | ||
500 | /* FIXME */ xd->node->next_in_ino = (void *)xd; | ||
501 | |||
502 | *pseudo_random += je32_to_cpu(spx->xid); | ||
503 | sp += JFFS2_SUMMARY_XATTR_SIZE; | ||
504 | |||
505 | break; | ||
506 | } | ||
507 | case JFFS2_NODETYPE_XREF: { | ||
508 | struct jffs2_xattr_ref *ref; | ||
509 | struct jffs2_sum_xref_flash *spr; | ||
510 | |||
511 | spr = (struct jffs2_sum_xref_flash *)sp; | ||
512 | dbg_summary("xref at %#08x-%#08x\n", | ||
513 | jeb->offset + je32_to_cpu(spr->offset), | ||
514 | jeb->offset + je32_to_cpu(spr->offset) + | ||
515 | (uint32_t)PAD(sizeof(struct jffs2_raw_xref))); | ||
516 | |||
517 | ref = jffs2_alloc_xattr_ref(); | ||
518 | if (!ref) { | ||
519 | JFFS2_NOTICE("allocation of xattr_datum failed\n"); | ||
520 | return -ENOMEM; | ||
521 | } | ||
522 | ref->ino = 0xfffffffe; | ||
523 | ref->xid = 0xfffffffd; | ||
524 | ref->next = c->xref_temp; | ||
525 | c->xref_temp = ref; | ||
411 | 526 | ||
527 | ref->node = sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED, | ||
528 | PAD(sizeof(struct jffs2_raw_xref)), NULL); | ||
529 | /* FIXME */ ref->node->next_in_ino = (void *)ref; | ||
530 | |||
531 | *pseudo_random += ref->node->flash_offset; | ||
532 | sp += JFFS2_SUMMARY_XREF_SIZE; | ||
533 | |||
534 | break; | ||
535 | } | ||
536 | #endif | ||
412 | default : { | 537 | default : { |
413 | JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); | 538 | uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype); |
414 | kfree(summary); | 539 | JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype); |
415 | return -EIO; | 540 | if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT) |
541 | return -EIO; | ||
542 | |||
543 | /* For compatible node types, just fall back to the full scan */ | ||
544 | c->wasted_size -= jeb->wasted_size; | ||
545 | c->free_size += c->sector_size - jeb->free_size; | ||
546 | c->used_size -= jeb->used_size; | ||
547 | c->dirty_size -= jeb->dirty_size; | ||
548 | jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0; | ||
549 | jeb->free_size = c->sector_size; | ||
550 | |||
551 | jffs2_free_jeb_node_refs(c, jeb); | ||
552 | return -ENOTRECOVERABLE; | ||
416 | } | 553 | } |
417 | } | 554 | } |
418 | } | 555 | } |
419 | |||
420 | kfree(summary); | ||
421 | return 0; | 556 | return 0; |
422 | } | 557 | } |
423 | 558 | ||
424 | /* Process the summary node - called from jffs2_scan_eraseblock() */ | 559 | /* 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, | 560 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
427 | uint32_t ofs, uint32_t *pseudo_random) | 561 | struct jffs2_raw_summary *summary, uint32_t sumsize, |
562 | uint32_t *pseudo_random) | ||
428 | { | 563 | { |
429 | struct jffs2_unknown_node crcnode; | 564 | struct jffs2_unknown_node crcnode; |
430 | struct jffs2_raw_node_ref *cache_ref; | 565 | int ret, ofs; |
431 | struct jffs2_raw_summary *summary; | ||
432 | int ret, sumsize; | ||
433 | uint32_t crc; | 566 | uint32_t crc; |
434 | 567 | ||
435 | sumsize = c->sector_size - ofs; | 568 | ofs = c->sector_size - sumsize; |
436 | ofs += jeb->offset; | ||
437 | 569 | ||
438 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", | 570 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", |
439 | jeb->offset, ofs, sumsize); | 571 | jeb->offset, 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 | 572 | ||
454 | /* OK, now check for node validity and CRC */ | 573 | /* OK, now check for node validity and CRC */ |
455 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 574 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -486,66 +605,49 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb | |||
486 | 605 | ||
487 | dbg_summary("Summary : CLEANMARKER node \n"); | 606 | dbg_summary("Summary : CLEANMARKER node \n"); |
488 | 607 | ||
608 | ret = jffs2_prealloc_raw_node_refs(c, jeb, 1); | ||
609 | if (ret) | ||
610 | return ret; | ||
611 | |||
489 | if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { | 612 | if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { |
490 | dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", | 613 | dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", |
491 | je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); | 614 | je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); |
492 | UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); | 615 | if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) |
616 | return ret; | ||
493 | } else if (jeb->first_node) { | 617 | } else if (jeb->first_node) { |
494 | dbg_summary("CLEANMARKER node not first node in block " | 618 | dbg_summary("CLEANMARKER node not first node in block " |
495 | "(0x%08x)\n", jeb->offset); | 619 | "(0x%08x)\n", jeb->offset); |
496 | UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); | 620 | if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) |
621 | return ret; | ||
497 | } else { | 622 | } else { |
498 | struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); | 623 | jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL, |
499 | 624 | je32_to_cpu(summary->cln_mkr), NULL); | |
500 | if (!marker_ref) { | ||
501 | JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); | ||
502 | kfree(summary); | ||
503 | return -ENOMEM; | ||
504 | } | ||
505 | |||
506 | marker_ref->next_in_ino = NULL; | ||
507 | marker_ref->next_phys = NULL; | ||
508 | marker_ref->flash_offset = jeb->offset | REF_NORMAL; | ||
509 | marker_ref->__totlen = je32_to_cpu(summary->cln_mkr); | ||
510 | jeb->first_node = jeb->last_node = marker_ref; | ||
511 | |||
512 | USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) ); | ||
513 | } | 625 | } |
514 | } | 626 | } |
515 | 627 | ||
516 | if (je32_to_cpu(summary->padded)) { | ||
517 | DIRTY_SPACE(je32_to_cpu(summary->padded)); | ||
518 | } | ||
519 | |||
520 | ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); | 628 | ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); |
629 | /* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full | ||
630 | scan of this eraseblock. So return zero */ | ||
631 | if (ret == -ENOTRECOVERABLE) | ||
632 | return 0; | ||
521 | if (ret) | 633 | if (ret) |
522 | return ret; | 634 | return ret; /* real error */ |
523 | 635 | ||
524 | /* for PARANOIA_CHECK */ | 636 | /* for PARANOIA_CHECK */ |
525 | cache_ref = jffs2_alloc_raw_node_ref(); | 637 | ret = jffs2_prealloc_raw_node_refs(c, jeb, 2); |
526 | 638 | if (ret) | |
527 | if (!cache_ref) { | 639 | return ret; |
528 | JFFS2_NOTICE("Failed to allocate node ref for cache\n"); | ||
529 | return -ENOMEM; | ||
530 | } | ||
531 | |||
532 | cache_ref->next_in_ino = NULL; | ||
533 | cache_ref->next_phys = NULL; | ||
534 | cache_ref->flash_offset = ofs | REF_NORMAL; | ||
535 | cache_ref->__totlen = sumsize; | ||
536 | |||
537 | if (!jeb->first_node) | ||
538 | jeb->first_node = cache_ref; | ||
539 | if (jeb->last_node) | ||
540 | jeb->last_node->next_phys = cache_ref; | ||
541 | jeb->last_node = cache_ref; | ||
542 | 640 | ||
543 | USED_SPACE(sumsize); | 641 | sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL); |
544 | 642 | ||
545 | jeb->wasted_size += jeb->free_size; | 643 | if (unlikely(jeb->free_size)) { |
546 | c->wasted_size += jeb->free_size; | 644 | JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", |
547 | c->free_size -= jeb->free_size; | 645 | jeb->free_size, jeb->offset); |
548 | jeb->free_size = 0; | 646 | jeb->wasted_size += jeb->free_size; |
647 | c->wasted_size += jeb->free_size; | ||
648 | c->free_size -= jeb->free_size; | ||
649 | jeb->free_size = 0; | ||
650 | } | ||
549 | 651 | ||
550 | return jffs2_scan_classify_jeb(c, jeb); | 652 | return jffs2_scan_classify_jeb(c, jeb); |
551 | 653 | ||
@@ -564,6 +666,7 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
564 | union jffs2_sum_mem *temp; | 666 | union jffs2_sum_mem *temp; |
565 | struct jffs2_sum_marker *sm; | 667 | struct jffs2_sum_marker *sm; |
566 | struct kvec vecs[2]; | 668 | struct kvec vecs[2]; |
669 | uint32_t sum_ofs; | ||
567 | void *wpage; | 670 | void *wpage; |
568 | int ret; | 671 | int ret; |
569 | size_t retlen; | 672 | size_t retlen; |
@@ -581,16 +684,17 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
581 | wpage = c->summary->sum_buf; | 684 | wpage = c->summary->sum_buf; |
582 | 685 | ||
583 | while (c->summary->sum_num) { | 686 | while (c->summary->sum_num) { |
687 | temp = c->summary->sum_list_head; | ||
584 | 688 | ||
585 | switch (je16_to_cpu(c->summary->sum_list_head->u.nodetype)) { | 689 | switch (je16_to_cpu(temp->u.nodetype)) { |
586 | case JFFS2_NODETYPE_INODE: { | 690 | case JFFS2_NODETYPE_INODE: { |
587 | struct jffs2_sum_inode_flash *sino_ptr = wpage; | 691 | struct jffs2_sum_inode_flash *sino_ptr = wpage; |
588 | 692 | ||
589 | sino_ptr->nodetype = c->summary->sum_list_head->i.nodetype; | 693 | sino_ptr->nodetype = temp->i.nodetype; |
590 | sino_ptr->inode = c->summary->sum_list_head->i.inode; | 694 | sino_ptr->inode = temp->i.inode; |
591 | sino_ptr->version = c->summary->sum_list_head->i.version; | 695 | sino_ptr->version = temp->i.version; |
592 | sino_ptr->offset = c->summary->sum_list_head->i.offset; | 696 | sino_ptr->offset = temp->i.offset; |
593 | sino_ptr->totlen = c->summary->sum_list_head->i.totlen; | 697 | sino_ptr->totlen = temp->i.totlen; |
594 | 698 | ||
595 | wpage += JFFS2_SUMMARY_INODE_SIZE; | 699 | wpage += JFFS2_SUMMARY_INODE_SIZE; |
596 | 700 | ||
@@ -600,30 +704,60 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
600 | case JFFS2_NODETYPE_DIRENT: { | 704 | case JFFS2_NODETYPE_DIRENT: { |
601 | struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; | 705 | struct jffs2_sum_dirent_flash *sdrnt_ptr = wpage; |
602 | 706 | ||
603 | sdrnt_ptr->nodetype = c->summary->sum_list_head->d.nodetype; | 707 | sdrnt_ptr->nodetype = temp->d.nodetype; |
604 | sdrnt_ptr->totlen = c->summary->sum_list_head->d.totlen; | 708 | sdrnt_ptr->totlen = temp->d.totlen; |
605 | sdrnt_ptr->offset = c->summary->sum_list_head->d.offset; | 709 | sdrnt_ptr->offset = temp->d.offset; |
606 | sdrnt_ptr->pino = c->summary->sum_list_head->d.pino; | 710 | sdrnt_ptr->pino = temp->d.pino; |
607 | sdrnt_ptr->version = c->summary->sum_list_head->d.version; | 711 | sdrnt_ptr->version = temp->d.version; |
608 | sdrnt_ptr->ino = c->summary->sum_list_head->d.ino; | 712 | sdrnt_ptr->ino = temp->d.ino; |
609 | sdrnt_ptr->nsize = c->summary->sum_list_head->d.nsize; | 713 | sdrnt_ptr->nsize = temp->d.nsize; |
610 | sdrnt_ptr->type = c->summary->sum_list_head->d.type; | 714 | sdrnt_ptr->type = temp->d.type; |
611 | 715 | ||
612 | memcpy(sdrnt_ptr->name, c->summary->sum_list_head->d.name, | 716 | memcpy(sdrnt_ptr->name, temp->d.name, |
613 | c->summary->sum_list_head->d.nsize); | 717 | temp->d.nsize); |
614 | 718 | ||
615 | wpage += JFFS2_SUMMARY_DIRENT_SIZE(c->summary->sum_list_head->d.nsize); | 719 | wpage += JFFS2_SUMMARY_DIRENT_SIZE(temp->d.nsize); |
616 | 720 | ||
617 | break; | 721 | break; |
618 | } | 722 | } |
723 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
724 | case JFFS2_NODETYPE_XATTR: { | ||
725 | struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; | ||
726 | |||
727 | temp = c->summary->sum_list_head; | ||
728 | sxattr_ptr->nodetype = temp->x.nodetype; | ||
729 | sxattr_ptr->xid = temp->x.xid; | ||
730 | sxattr_ptr->version = temp->x.version; | ||
731 | sxattr_ptr->offset = temp->x.offset; | ||
732 | sxattr_ptr->totlen = temp->x.totlen; | ||
733 | |||
734 | wpage += JFFS2_SUMMARY_XATTR_SIZE; | ||
735 | break; | ||
736 | } | ||
737 | case JFFS2_NODETYPE_XREF: { | ||
738 | struct jffs2_sum_xref_flash *sxref_ptr = wpage; | ||
619 | 739 | ||
740 | temp = c->summary->sum_list_head; | ||
741 | sxref_ptr->nodetype = temp->r.nodetype; | ||
742 | sxref_ptr->offset = temp->r.offset; | ||
743 | |||
744 | wpage += JFFS2_SUMMARY_XREF_SIZE; | ||
745 | break; | ||
746 | } | ||
747 | #endif | ||
620 | default : { | 748 | default : { |
621 | BUG(); /* unknown node in summary information */ | 749 | if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK) |
750 | == JFFS2_FEATURE_RWCOMPAT_COPY) { | ||
751 | dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n", | ||
752 | je16_to_cpu(temp->u.nodetype)); | ||
753 | jffs2_sum_disable_collecting(c->summary); | ||
754 | } else { | ||
755 | BUG(); /* unknown node in summary information */ | ||
756 | } | ||
622 | } | 757 | } |
623 | } | 758 | } |
624 | 759 | ||
625 | temp = c->summary->sum_list_head; | 760 | c->summary->sum_list_head = temp->u.next; |
626 | c->summary->sum_list_head = c->summary->sum_list_head->u.next; | ||
627 | kfree(temp); | 761 | kfree(temp); |
628 | 762 | ||
629 | c->summary->sum_num--; | 763 | c->summary->sum_num--; |
@@ -645,25 +779,34 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
645 | vecs[1].iov_base = c->summary->sum_buf; | 779 | vecs[1].iov_base = c->summary->sum_buf; |
646 | vecs[1].iov_len = datasize; | 780 | vecs[1].iov_len = datasize; |
647 | 781 | ||
648 | dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n", | 782 | sum_ofs = jeb->offset + c->sector_size - jeb->free_size; |
649 | jeb->offset + c->sector_size - jeb->free_size); | ||
650 | 783 | ||
651 | spin_unlock(&c->erase_completion_lock); | 784 | dbg_summary("JFFS2: writing out data to flash to pos : 0x%08x\n", |
652 | ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - | 785 | sum_ofs); |
653 | jeb->free_size, &retlen, 0); | ||
654 | spin_lock(&c->erase_completion_lock); | ||
655 | 786 | ||
787 | ret = jffs2_flash_writev(c, vecs, 2, sum_ofs, &retlen, 0); | ||
656 | 788 | ||
657 | if (ret || (retlen != infosize)) { | 789 | if (ret || (retlen != infosize)) { |
658 | JFFS2_WARNING("Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", | 790 | |
659 | infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); | 791 | JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", |
792 | infosize, sum_ofs, ret, retlen); | ||
793 | |||
794 | if (retlen) { | ||
795 | /* Waste remaining space */ | ||
796 | spin_lock(&c->erase_completion_lock); | ||
797 | jffs2_link_node_ref(c, jeb, sum_ofs | REF_OBSOLETE, infosize, NULL); | ||
798 | spin_unlock(&c->erase_completion_lock); | ||
799 | } | ||
660 | 800 | ||
661 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; | 801 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; |
662 | WASTED_SPACE(infosize); | ||
663 | 802 | ||
664 | return 1; | 803 | return 0; |
665 | } | 804 | } |
666 | 805 | ||
806 | spin_lock(&c->erase_completion_lock); | ||
807 | jffs2_link_node_ref(c, jeb, sum_ofs | REF_NORMAL, infosize, NULL); | ||
808 | spin_unlock(&c->erase_completion_lock); | ||
809 | |||
667 | return 0; | 810 | return 0; |
668 | } | 811 | } |
669 | 812 | ||
@@ -671,13 +814,16 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
671 | 814 | ||
672 | int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | 815 | int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) |
673 | { | 816 | { |
674 | struct jffs2_raw_node_ref *summary_ref; | 817 | int datasize, infosize, padsize; |
675 | int datasize, infosize, padsize, ret; | ||
676 | struct jffs2_eraseblock *jeb; | 818 | struct jffs2_eraseblock *jeb; |
819 | int ret; | ||
677 | 820 | ||
678 | dbg_summary("called\n"); | 821 | dbg_summary("called\n"); |
679 | 822 | ||
823 | spin_unlock(&c->erase_completion_lock); | ||
824 | |||
680 | jeb = c->nextblock; | 825 | jeb = c->nextblock; |
826 | jffs2_prealloc_raw_node_refs(c, jeb, 1); | ||
681 | 827 | ||
682 | if (!c->summary->sum_num || !c->summary->sum_list_head) { | 828 | if (!c->summary->sum_num || !c->summary->sum_list_head) { |
683 | JFFS2_WARNING("Empty summary info!!!\n"); | 829 | JFFS2_WARNING("Empty summary info!!!\n"); |
@@ -696,35 +842,11 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | |||
696 | jffs2_sum_disable_collecting(c->summary); | 842 | jffs2_sum_disable_collecting(c->summary); |
697 | 843 | ||
698 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); | 844 | JFFS2_WARNING("Not enough space for summary, padsize = %d\n", padsize); |
845 | spin_lock(&c->erase_completion_lock); | ||
699 | return 0; | 846 | return 0; |
700 | } | 847 | } |
701 | 848 | ||
702 | ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); | 849 | ret = jffs2_sum_write_data(c, jeb, infosize, datasize, padsize); |
703 | if (ret) | ||
704 | return 0; /* can't write out summary, block is marked as NOSUM_SIZE */ | ||
705 | |||
706 | /* for ACCT_PARANOIA_CHECK */ | ||
707 | spin_unlock(&c->erase_completion_lock); | ||
708 | summary_ref = jffs2_alloc_raw_node_ref(); | ||
709 | spin_lock(&c->erase_completion_lock); | 850 | spin_lock(&c->erase_completion_lock); |
710 | 851 | return ret; | |
711 | if (!summary_ref) { | ||
712 | JFFS2_NOTICE("Failed to allocate node ref for summary\n"); | ||
713 | return -ENOMEM; | ||
714 | } | ||
715 | |||
716 | summary_ref->next_in_ino = NULL; | ||
717 | summary_ref->next_phys = NULL; | ||
718 | summary_ref->flash_offset = (jeb->offset + c->sector_size - jeb->free_size) | REF_NORMAL; | ||
719 | summary_ref->__totlen = infosize; | ||
720 | |||
721 | if (!jeb->first_node) | ||
722 | jeb->first_node = summary_ref; | ||
723 | if (jeb->last_node) | ||
724 | jeb->last_node->next_phys = summary_ref; | ||
725 | jeb->last_node = summary_ref; | ||
726 | |||
727 | USED_SPACE(infosize); | ||
728 | |||
729 | return 0; | ||
730 | } | 852 | } |