diff options
Diffstat (limited to 'fs/jffs2/summary.c')
-rw-r--r-- | fs/jffs2/summary.c | 385 |
1 files changed, 287 insertions, 98 deletions
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 48293c197f13..1451732e1fa7 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; | ||
262 | 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; | ||
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,6 +369,23 @@ no_mem: | |||
288 | return -ENOMEM; | 369 | return -ENOMEM; |
289 | } | 370 | } |
290 | 371 | ||
372 | static struct jffs2_raw_node_ref *alloc_ref_at(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
373 | uint32_t offset) | ||
374 | { | ||
375 | struct jffs2_raw_node_ref *ref; | ||
376 | /* If there was a gap, mark it dirty */ | ||
377 | if (offset > c->sector_size - jeb->free_size) { | ||
378 | int ret = jffs2_scan_dirty_space(c, jeb, offset - (c->sector_size - jeb->free_size)); | ||
379 | if (ret) | ||
380 | return NULL; | ||
381 | } | ||
382 | ref = jffs2_alloc_raw_node_ref(); | ||
383 | if (!ref) | ||
384 | return NULL; | ||
385 | |||
386 | ref->flash_offset = jeb->offset + offset; | ||
387 | return ref; | ||
388 | } | ||
291 | 389 | ||
292 | /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ | 390 | /* Process the stored summary information - helper function for jffs2_sum_scan_sumnode() */ |
293 | 391 | ||
@@ -299,6 +397,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
299 | struct jffs2_full_dirent *fd; | 397 | struct jffs2_full_dirent *fd; |
300 | void *sp; | 398 | void *sp; |
301 | int i, ino; | 399 | int i, ino; |
400 | int err; | ||
302 | 401 | ||
303 | sp = summary->sum; | 402 | sp = summary->sum; |
304 | 403 | ||
@@ -312,13 +411,13 @@ 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), |
416 | jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spu->totlen)); | ||
317 | 417 | ||
318 | raw = jffs2_alloc_raw_node_ref(); | 418 | raw = alloc_ref_at(c, jeb, je32_to_cpu(spi->offset)); |
319 | if (!raw) { | 419 | if (!raw) { |
320 | JFFS2_NOTICE("allocation of node reference failed\n"); | 420 | JFFS2_NOTICE("allocation of node reference failed\n"); |
321 | kfree(summary); | ||
322 | return -ENOMEM; | 421 | return -ENOMEM; |
323 | } | 422 | } |
324 | 423 | ||
@@ -326,24 +425,17 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
326 | if (!ic) { | 425 | if (!ic) { |
327 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); | 426 | JFFS2_NOTICE("scan_make_ino_cache failed\n"); |
328 | jffs2_free_raw_node_ref(raw); | 427 | jffs2_free_raw_node_ref(raw); |
329 | kfree(summary); | ||
330 | return -ENOMEM; | 428 | return -ENOMEM; |
331 | } | 429 | } |
332 | 430 | ||
333 | raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED; | 431 | raw->flash_offset |= REF_UNCHECKED; |
334 | raw->__totlen = PAD(je32_to_cpu(spi->totlen)); | ||
335 | raw->next_phys = NULL; | ||
336 | raw->next_in_ino = ic->nodes; | ||
337 | 432 | ||
433 | raw->next_in_ino = ic->nodes; | ||
338 | ic->nodes = raw; | 434 | 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 | 435 | ||
346 | UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen))); | 436 | jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spi->totlen))); |
437 | |||
438 | *pseudo_random += je32_to_cpu(spi->version); | ||
347 | 439 | ||
348 | sp += JFFS2_SUMMARY_INODE_SIZE; | 440 | sp += JFFS2_SUMMARY_INODE_SIZE; |
349 | 441 | ||
@@ -355,22 +447,21 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
355 | spd = sp; | 447 | spd = sp; |
356 | 448 | ||
357 | dbg_summary("Dirent at 0x%08x\n", | 449 | dbg_summary("Dirent at 0x%08x\n", |
358 | jeb->offset + je32_to_cpu(spd->offset)); | 450 | jeb->offset + je32_to_cpu(spd->offset), |
451 | jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen)); | ||
452 | |||
359 | 453 | ||
360 | fd = jffs2_alloc_full_dirent(spd->nsize+1); | 454 | fd = jffs2_alloc_full_dirent(spd->nsize+1); |
361 | if (!fd) { | 455 | if (!fd) |
362 | kfree(summary); | ||
363 | return -ENOMEM; | 456 | return -ENOMEM; |
364 | } | ||
365 | 457 | ||
366 | memcpy(&fd->name, spd->name, spd->nsize); | 458 | memcpy(&fd->name, spd->name, spd->nsize); |
367 | fd->name[spd->nsize] = 0; | 459 | fd->name[spd->nsize] = 0; |
368 | 460 | ||
369 | raw = jffs2_alloc_raw_node_ref(); | 461 | raw = alloc_ref_at(c, jeb, je32_to_cpu(spd->offset)); |
370 | if (!raw) { | 462 | if (!raw) { |
371 | jffs2_free_full_dirent(fd); | 463 | jffs2_free_full_dirent(fd); |
372 | JFFS2_NOTICE("allocation of node reference failed\n"); | 464 | JFFS2_NOTICE("allocation of node reference failed\n"); |
373 | kfree(summary); | ||
374 | return -ENOMEM; | 465 | return -ENOMEM; |
375 | } | 466 | } |
376 | 467 | ||
@@ -378,20 +469,14 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
378 | if (!ic) { | 469 | if (!ic) { |
379 | jffs2_free_full_dirent(fd); | 470 | jffs2_free_full_dirent(fd); |
380 | jffs2_free_raw_node_ref(raw); | 471 | jffs2_free_raw_node_ref(raw); |
381 | kfree(summary); | ||
382 | return -ENOMEM; | 472 | return -ENOMEM; |
383 | } | 473 | } |
384 | 474 | ||
385 | raw->__totlen = PAD(je32_to_cpu(spd->totlen)); | 475 | raw->flash_offset |= REF_PRISTINE; |
386 | raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE; | ||
387 | raw->next_phys = NULL; | ||
388 | raw->next_in_ino = ic->nodes; | 476 | raw->next_in_ino = ic->nodes; |
389 | ic->nodes = raw; | 477 | ic->nodes = raw; |
390 | if (!jeb->first_node) | 478 | |
391 | jeb->first_node = raw; | 479 | jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spd->totlen))); |
392 | if (jeb->last_node) | ||
393 | jeb->last_node->next_phys = raw; | ||
394 | jeb->last_node = raw; | ||
395 | 480 | ||
396 | fd->raw = raw; | 481 | fd->raw = raw; |
397 | fd->next = NULL; | 482 | fd->next = NULL; |
@@ -399,7 +484,7 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
399 | fd->ino = je32_to_cpu(spd->ino); | 484 | fd->ino = je32_to_cpu(spd->ino); |
400 | fd->nhash = full_name_hash(fd->name, spd->nsize); | 485 | fd->nhash = full_name_hash(fd->name, spd->nsize); |
401 | fd->type = spd->type; | 486 | fd->type = spd->type; |
402 | USED_SPACE(PAD(je32_to_cpu(spd->totlen))); | 487 | |
403 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); | 488 | jffs2_add_fd_to_list(c, fd, &ic->scan_dents); |
404 | 489 | ||
405 | *pseudo_random += je32_to_cpu(spd->version); | 490 | *pseudo_random += je32_to_cpu(spd->version); |
@@ -408,48 +493,122 @@ static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eras | |||
408 | 493 | ||
409 | break; | 494 | break; |
410 | } | 495 | } |
496 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
497 | case JFFS2_NODETYPE_XATTR: { | ||
498 | struct jffs2_xattr_datum *xd; | ||
499 | struct jffs2_sum_xattr_flash *spx; | ||
500 | |||
501 | spx = (struct jffs2_sum_xattr_flash *)sp; | ||
502 | dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", | ||
503 | jeb->offset + je32_to_cpu(spx->offset), | ||
504 | jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen), | ||
505 | je32_to_cpu(spx->xid), je32_to_cpu(spx->version)); | ||
506 | raw = alloc_ref_at(c, jeb, je32_to_cpu(spx->offset)); | ||
507 | if (!raw) { | ||
508 | JFFS2_NOTICE("allocation of node reference failed\n"); | ||
509 | return -ENOMEM; | ||
510 | } | ||
511 | xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid), | ||
512 | je32_to_cpu(spx->version)); | ||
513 | if (IS_ERR(xd)) { | ||
514 | jffs2_free_raw_node_ref(raw); | ||
515 | if (PTR_ERR(xd) == -EEXIST) { | ||
516 | /* a newer version of xd exists */ | ||
517 | if ((err = jffs2_scan_dirty_space(c, jeb, je32_to_cpu(spx->totlen)))) | ||
518 | return err; | ||
519 | sp += JFFS2_SUMMARY_XATTR_SIZE; | ||
520 | break; | ||
521 | } | ||
522 | JFFS2_NOTICE("allocation of xattr_datum failed\n"); | ||
523 | return PTR_ERR(xd); | ||
524 | } | ||
525 | xd->node = raw; | ||
526 | |||
527 | raw->flash_offset |= REF_UNCHECKED; | ||
528 | raw->next_in_ino = (void *)xd; | ||
529 | |||
530 | jffs2_link_node_ref(c, jeb, raw, PAD(je32_to_cpu(spx->totlen))); | ||
531 | |||
532 | *pseudo_random += je32_to_cpu(spx->xid); | ||
533 | sp += JFFS2_SUMMARY_XATTR_SIZE; | ||
534 | |||
535 | break; | ||
536 | } | ||
537 | case JFFS2_NODETYPE_XREF: { | ||
538 | struct jffs2_xattr_ref *ref; | ||
539 | struct jffs2_sum_xref_flash *spr; | ||
540 | |||
541 | spr = (struct jffs2_sum_xref_flash *)sp; | ||
542 | dbg_summary("xref at %#08x-%#08x\n", | ||
543 | jeb->offset + je32_to_cpu(spr->offset), | ||
544 | jeb->offset + je32_to_cpu(spr->offset) + PAD(sizeof(struct jffs2_raw_xref))); | ||
545 | |||
546 | raw = alloc_ref_at(c, jeb, je32_to_cpu(spr->offset)); | ||
547 | if (!raw) { | ||
548 | JFFS2_NOTICE("allocation of node reference failed\n"); | ||
549 | return -ENOMEM; | ||
550 | } | ||
551 | ref = jffs2_alloc_xattr_ref(); | ||
552 | if (!ref) { | ||
553 | JFFS2_NOTICE("allocation of xattr_datum failed\n"); | ||
554 | jffs2_free_raw_node_ref(raw); | ||
555 | return -ENOMEM; | ||
556 | } | ||
557 | ref->ino = 0xfffffffe; | ||
558 | ref->xid = 0xfffffffd; | ||
559 | ref->node = raw; | ||
560 | ref->next = c->xref_temp; | ||
561 | c->xref_temp = ref; | ||
562 | |||
563 | raw->flash_offset |= REF_UNCHECKED; | ||
564 | raw->next_in_ino = (void *)ref; | ||
411 | 565 | ||
566 | jffs2_link_node_ref(c, jeb, raw, PAD(sizeof(struct jffs2_raw_xref))); | ||
567 | |||
568 | *pseudo_random += raw->flash_offset; | ||
569 | sp += JFFS2_SUMMARY_XREF_SIZE; | ||
570 | |||
571 | break; | ||
572 | } | ||
573 | #endif | ||
412 | default : { | 574 | default : { |
413 | JFFS2_WARNING("Unsupported node type found in summary! Exiting..."); | 575 | uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype); |
414 | kfree(summary); | 576 | JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype); |
415 | return -EIO; | 577 | if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT) |
578 | return -EIO; | ||
579 | |||
580 | /* For compatible node types, just fall back to the full scan */ | ||
581 | c->wasted_size -= jeb->wasted_size; | ||
582 | c->free_size += c->sector_size - jeb->free_size; | ||
583 | c->used_size -= jeb->used_size; | ||
584 | c->dirty_size -= jeb->dirty_size; | ||
585 | jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0; | ||
586 | jeb->free_size = c->sector_size; | ||
587 | |||
588 | jffs2_free_all_node_refs(c, jeb); | ||
589 | return -ENOTRECOVERABLE; | ||
416 | } | 590 | } |
417 | } | 591 | } |
418 | } | 592 | } |
419 | 593 | ||
420 | kfree(summary); | ||
421 | return 0; | 594 | return 0; |
422 | } | 595 | } |
423 | 596 | ||
424 | /* Process the summary node - called from jffs2_scan_eraseblock() */ | 597 | /* 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, | 598 | int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, |
427 | uint32_t ofs, uint32_t *pseudo_random) | 599 | struct jffs2_raw_summary *summary, uint32_t sumsize, |
600 | uint32_t *pseudo_random) | ||
428 | { | 601 | { |
429 | struct jffs2_unknown_node crcnode; | 602 | struct jffs2_unknown_node crcnode; |
430 | struct jffs2_raw_node_ref *cache_ref; | 603 | struct jffs2_raw_node_ref *cache_ref; |
431 | struct jffs2_raw_summary *summary; | 604 | int ret, ofs; |
432 | int ret, sumsize; | ||
433 | uint32_t crc; | 605 | uint32_t crc; |
606 | int err; | ||
434 | 607 | ||
435 | sumsize = c->sector_size - ofs; | 608 | ofs = c->sector_size - sumsize; |
436 | ofs += jeb->offset; | ||
437 | 609 | ||
438 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", | 610 | dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", |
439 | jeb->offset, ofs, sumsize); | 611 | 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 | 612 | ||
454 | /* OK, now check for node validity and CRC */ | 613 | /* OK, now check for node validity and CRC */ |
455 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); | 614 | crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); |
@@ -489,40 +648,38 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb | |||
489 | if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { | 648 | if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) { |
490 | dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", | 649 | dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n", |
491 | je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); | 650 | je32_to_cpu(summary->cln_mkr), c->cleanmarker_size); |
492 | UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); | 651 | if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) |
652 | return err; | ||
493 | } else if (jeb->first_node) { | 653 | } else if (jeb->first_node) { |
494 | dbg_summary("CLEANMARKER node not first node in block " | 654 | dbg_summary("CLEANMARKER node not first node in block " |
495 | "(0x%08x)\n", jeb->offset); | 655 | "(0x%08x)\n", jeb->offset); |
496 | UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr))); | 656 | if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr))))) |
657 | return err; | ||
497 | } else { | 658 | } else { |
498 | struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); | 659 | struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); |
499 | 660 | ||
500 | if (!marker_ref) { | 661 | if (!marker_ref) { |
501 | JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); | 662 | JFFS2_NOTICE("Failed to allocate node ref for clean marker\n"); |
502 | kfree(summary); | ||
503 | return -ENOMEM; | 663 | return -ENOMEM; |
504 | } | 664 | } |
505 | 665 | ||
506 | marker_ref->next_in_ino = NULL; | ||
507 | marker_ref->next_phys = NULL; | ||
508 | marker_ref->flash_offset = jeb->offset | REF_NORMAL; | 666 | marker_ref->flash_offset = jeb->offset | REF_NORMAL; |
509 | marker_ref->__totlen = je32_to_cpu(summary->cln_mkr); | 667 | marker_ref->next_in_ino = NULL; |
510 | jeb->first_node = jeb->last_node = marker_ref; | ||
511 | 668 | ||
512 | USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) ); | 669 | jffs2_link_node_ref(c, jeb, marker_ref, je32_to_cpu(summary->cln_mkr)); |
513 | } | 670 | } |
514 | } | 671 | } |
515 | 672 | ||
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); | 673 | ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random); |
674 | /* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full | ||
675 | scan of this eraseblock. So return zero */ | ||
676 | if (ret == -ENOTRECOVERABLE) | ||
677 | return 0; | ||
521 | if (ret) | 678 | if (ret) |
522 | return ret; | 679 | return ret; /* real error */ |
523 | 680 | ||
524 | /* for PARANOIA_CHECK */ | 681 | /* for PARANOIA_CHECK */ |
525 | cache_ref = jffs2_alloc_raw_node_ref(); | 682 | cache_ref = alloc_ref_at(c, jeb, ofs); |
526 | 683 | ||
527 | if (!cache_ref) { | 684 | if (!cache_ref) { |
528 | JFFS2_NOTICE("Failed to allocate node ref for cache\n"); | 685 | JFFS2_NOTICE("Failed to allocate node ref for cache\n"); |
@@ -530,22 +687,18 @@ int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb | |||
530 | } | 687 | } |
531 | 688 | ||
532 | cache_ref->next_in_ino = NULL; | 689 | cache_ref->next_in_ino = NULL; |
533 | cache_ref->next_phys = NULL; | 690 | cache_ref->flash_offset |= REF_NORMAL; |
534 | cache_ref->flash_offset = ofs | REF_NORMAL; | ||
535 | cache_ref->__totlen = sumsize; | ||
536 | 691 | ||
537 | if (!jeb->first_node) | 692 | jffs2_link_node_ref(c, jeb, cache_ref, sumsize); |
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 | 693 | ||
543 | USED_SPACE(sumsize); | 694 | if (unlikely(jeb->free_size)) { |
544 | 695 | JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n", | |
545 | jeb->wasted_size += jeb->free_size; | 696 | jeb->free_size, jeb->offset); |
546 | c->wasted_size += jeb->free_size; | 697 | jeb->wasted_size += jeb->free_size; |
547 | c->free_size -= jeb->free_size; | 698 | c->wasted_size += jeb->free_size; |
548 | jeb->free_size = 0; | 699 | c->free_size -= jeb->free_size; |
700 | jeb->free_size = 0; | ||
701 | } | ||
549 | 702 | ||
550 | return jffs2_scan_classify_jeb(c, jeb); | 703 | return jffs2_scan_classify_jeb(c, jeb); |
551 | 704 | ||
@@ -617,9 +770,40 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
617 | 770 | ||
618 | break; | 771 | break; |
619 | } | 772 | } |
773 | #ifdef CONFIG_JFFS2_FS_XATTR | ||
774 | case JFFS2_NODETYPE_XATTR: { | ||
775 | struct jffs2_sum_xattr_flash *sxattr_ptr = wpage; | ||
776 | |||
777 | temp = c->summary->sum_list_head; | ||
778 | sxattr_ptr->nodetype = temp->x.nodetype; | ||
779 | sxattr_ptr->xid = temp->x.xid; | ||
780 | sxattr_ptr->version = temp->x.version; | ||
781 | sxattr_ptr->offset = temp->x.offset; | ||
782 | sxattr_ptr->totlen = temp->x.totlen; | ||
783 | |||
784 | wpage += JFFS2_SUMMARY_XATTR_SIZE; | ||
785 | break; | ||
786 | } | ||
787 | case JFFS2_NODETYPE_XREF: { | ||
788 | struct jffs2_sum_xref_flash *sxref_ptr = wpage; | ||
620 | 789 | ||
790 | temp = c->summary->sum_list_head; | ||
791 | sxref_ptr->nodetype = temp->r.nodetype; | ||
792 | sxref_ptr->offset = temp->r.offset; | ||
793 | |||
794 | wpage += JFFS2_SUMMARY_XREF_SIZE; | ||
795 | break; | ||
796 | } | ||
797 | #endif | ||
621 | default : { | 798 | default : { |
622 | BUG(); /* unknown node in summary information */ | 799 | if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK) |
800 | == JFFS2_FEATURE_RWCOMPAT_COPY) { | ||
801 | dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n", | ||
802 | je16_to_cpu(temp->u.nodetype)); | ||
803 | jffs2_sum_disable_collecting(c->summary); | ||
804 | } else { | ||
805 | BUG(); /* unknown node in summary information */ | ||
806 | } | ||
623 | } | 807 | } |
624 | } | 808 | } |
625 | 809 | ||
@@ -651,19 +835,32 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
651 | spin_unlock(&c->erase_completion_lock); | 835 | spin_unlock(&c->erase_completion_lock); |
652 | ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - | 836 | ret = jffs2_flash_writev(c, vecs, 2, jeb->offset + c->sector_size - |
653 | jeb->free_size, &retlen, 0); | 837 | jeb->free_size, &retlen, 0); |
654 | spin_lock(&c->erase_completion_lock); | ||
655 | |||
656 | 838 | ||
657 | if (ret || (retlen != infosize)) { | 839 | if (ret || (retlen != infosize)) { |
840 | struct jffs2_raw_node_ref *ref; | ||
841 | |||
658 | JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", | 842 | JFFS2_WARNING("Write of %u bytes at 0x%08x failed. returned %d, retlen %zd\n", |
659 | infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); | 843 | infosize, jeb->offset + c->sector_size - jeb->free_size, ret, retlen); |
660 | 844 | ||
845 | /* Waste remaining space */ | ||
846 | ref = jffs2_alloc_raw_node_ref(); | ||
847 | if (ref) { | ||
848 | spin_lock(&c->erase_completion_lock); | ||
849 | |||
850 | ref->flash_offset = jeb->offset + c->sector_size - jeb->free_size; | ||
851 | ref->flash_offset |= REF_OBSOLETE; | ||
852 | ref->next_in_ino = 0; | ||
853 | |||
854 | jffs2_link_node_ref(c, jeb, ref, c->sector_size - jeb->free_size); | ||
855 | } | ||
856 | |||
661 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; | 857 | c->summary->sum_size = JFFS2_SUMMARY_NOSUM_SIZE; |
662 | WASTED_SPACE(infosize); | ||
663 | 858 | ||
664 | return 1; | 859 | return 1; |
665 | } | 860 | } |
666 | 861 | ||
862 | spin_lock(&c->erase_completion_lock); | ||
863 | |||
667 | return 0; | 864 | return 0; |
668 | } | 865 | } |
669 | 866 | ||
@@ -706,7 +903,6 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | |||
706 | /* for ACCT_PARANOIA_CHECK */ | 903 | /* for ACCT_PARANOIA_CHECK */ |
707 | spin_unlock(&c->erase_completion_lock); | 904 | spin_unlock(&c->erase_completion_lock); |
708 | summary_ref = jffs2_alloc_raw_node_ref(); | 905 | summary_ref = jffs2_alloc_raw_node_ref(); |
709 | spin_lock(&c->erase_completion_lock); | ||
710 | 906 | ||
711 | if (!summary_ref) { | 907 | if (!summary_ref) { |
712 | JFFS2_NOTICE("Failed to allocate node ref for summary\n"); | 908 | JFFS2_NOTICE("Failed to allocate node ref for summary\n"); |
@@ -714,17 +910,10 @@ int jffs2_sum_write_sumnode(struct jffs2_sb_info *c) | |||
714 | } | 910 | } |
715 | 911 | ||
716 | summary_ref->next_in_ino = NULL; | 912 | 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; | 913 | 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 | 914 | ||
727 | USED_SPACE(infosize); | 915 | spin_lock(&c->erase_completion_lock); |
916 | jffs2_link_node_ref(c, jeb, summary_ref, infosize); | ||
728 | 917 | ||
729 | return 0; | 918 | return 0; |
730 | } | 919 | } |