diff options
Diffstat (limited to 'fs/jffs2/readinode.c')
-rw-r--r-- | fs/jffs2/readinode.c | 137 |
1 files changed, 83 insertions, 54 deletions
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index f1695642d0f7..5fec012b02ed 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -66,7 +66,7 @@ static void jffs2_free_tmp_dnode_info_list(struct rb_root *list) | |||
66 | jffs2_free_full_dnode(tn->fn); | 66 | jffs2_free_full_dnode(tn->fn); |
67 | jffs2_free_tmp_dnode_info(tn); | 67 | jffs2_free_tmp_dnode_info(tn); |
68 | 68 | ||
69 | this = this->rb_parent; | 69 | this = rb_parent(this); |
70 | if (!this) | 70 | if (!this) |
71 | break; | 71 | break; |
72 | 72 | ||
@@ -116,19 +116,42 @@ static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_r | |||
116 | uint32_t *latest_mctime, uint32_t *mctime_ver) | 116 | uint32_t *latest_mctime, uint32_t *mctime_ver) |
117 | { | 117 | { |
118 | struct jffs2_full_dirent *fd; | 118 | struct jffs2_full_dirent *fd; |
119 | uint32_t crc; | ||
119 | 120 | ||
120 | /* The direntry nodes are checked during the flash scanning */ | ||
121 | BUG_ON(ref_flags(ref) == REF_UNCHECKED); | ||
122 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | 121 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ |
123 | BUG_ON(ref_obsolete(ref)); | 122 | BUG_ON(ref_obsolete(ref)); |
124 | 123 | ||
125 | /* Sanity check */ | 124 | crc = crc32(0, rd, sizeof(*rd) - 8); |
126 | if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { | 125 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { |
127 | JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", | 126 | JFFS2_NOTICE("header CRC failed on dirent node at %#08x: read %#08x, calculated %#08x\n", |
128 | ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); | 127 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); |
129 | return 1; | 128 | return 1; |
130 | } | 129 | } |
131 | 130 | ||
131 | /* If we've never checked the CRCs on this node, check them now */ | ||
132 | if (ref_flags(ref) == REF_UNCHECKED) { | ||
133 | struct jffs2_eraseblock *jeb; | ||
134 | int len; | ||
135 | |||
136 | /* Sanity check */ | ||
137 | if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) { | ||
138 | JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n", | ||
139 | ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen)); | ||
140 | return 1; | ||
141 | } | ||
142 | |||
143 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
144 | len = ref_totlen(c, jeb, ref); | ||
145 | |||
146 | spin_lock(&c->erase_completion_lock); | ||
147 | jeb->used_size += len; | ||
148 | jeb->unchecked_size -= len; | ||
149 | c->used_size += len; | ||
150 | c->unchecked_size -= len; | ||
151 | ref->flash_offset = ref_offset(ref) | REF_PRISTINE; | ||
152 | spin_unlock(&c->erase_completion_lock); | ||
153 | } | ||
154 | |||
132 | fd = jffs2_alloc_full_dirent(rd->nsize + 1); | 155 | fd = jffs2_alloc_full_dirent(rd->nsize + 1); |
133 | if (unlikely(!fd)) | 156 | if (unlikely(!fd)) |
134 | return -ENOMEM; | 157 | return -ENOMEM; |
@@ -198,13 +221,21 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
198 | struct jffs2_tmp_dnode_info *tn; | 221 | struct jffs2_tmp_dnode_info *tn; |
199 | uint32_t len, csize; | 222 | uint32_t len, csize; |
200 | int ret = 1; | 223 | int ret = 1; |
224 | uint32_t crc; | ||
201 | 225 | ||
202 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ | 226 | /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ |
203 | BUG_ON(ref_obsolete(ref)); | 227 | BUG_ON(ref_obsolete(ref)); |
204 | 228 | ||
229 | crc = crc32(0, rd, sizeof(*rd) - 8); | ||
230 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { | ||
231 | JFFS2_NOTICE("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n", | ||
232 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); | ||
233 | return 1; | ||
234 | } | ||
235 | |||
205 | tn = jffs2_alloc_tmp_dnode_info(); | 236 | tn = jffs2_alloc_tmp_dnode_info(); |
206 | if (!tn) { | 237 | if (!tn) { |
207 | JFFS2_ERROR("failed to allocate tn (%d bytes).\n", sizeof(*tn)); | 238 | JFFS2_ERROR("failed to allocate tn (%zu bytes).\n", sizeof(*tn)); |
208 | return -ENOMEM; | 239 | return -ENOMEM; |
209 | } | 240 | } |
210 | 241 | ||
@@ -213,14 +244,6 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
213 | 244 | ||
214 | /* If we've never checked the CRCs on this node, check them now */ | 245 | /* If we've never checked the CRCs on this node, check them now */ |
215 | if (ref_flags(ref) == REF_UNCHECKED) { | 246 | if (ref_flags(ref) == REF_UNCHECKED) { |
216 | uint32_t crc; | ||
217 | |||
218 | crc = crc32(0, rd, sizeof(*rd) - 8); | ||
219 | if (unlikely(crc != je32_to_cpu(rd->node_crc))) { | ||
220 | JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n", | ||
221 | ref_offset(ref), je32_to_cpu(rd->node_crc), crc); | ||
222 | goto free_out; | ||
223 | } | ||
224 | 247 | ||
225 | /* Sanity checks */ | 248 | /* Sanity checks */ |
226 | if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || | 249 | if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) || |
@@ -343,7 +366,7 @@ free_out: | |||
343 | * Helper function for jffs2_get_inode_nodes(). | 366 | * Helper function for jffs2_get_inode_nodes(). |
344 | * It is called every time an unknown node is found. | 367 | * It is called every time an unknown node is found. |
345 | * | 368 | * |
346 | * Returns: 0 on succes; | 369 | * Returns: 0 on success; |
347 | * 1 if the node should be marked obsolete; | 370 | * 1 if the node should be marked obsolete; |
348 | * negative error code on failure. | 371 | * negative error code on failure. |
349 | */ | 372 | */ |
@@ -354,37 +377,30 @@ static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_re | |||
354 | 377 | ||
355 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); | 378 | un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype)); |
356 | 379 | ||
357 | if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) { | 380 | switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { |
358 | /* Hmmm. This should have been caught at scan time. */ | ||
359 | JFFS2_NOTICE("node header CRC failed at %#08x. But it must have been OK earlier.\n", ref_offset(ref)); | ||
360 | jffs2_dbg_dump_node(c, ref_offset(ref)); | ||
361 | return 1; | ||
362 | } else { | ||
363 | switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) { | ||
364 | 381 | ||
365 | case JFFS2_FEATURE_INCOMPAT: | 382 | case JFFS2_FEATURE_INCOMPAT: |
366 | JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n", | 383 | JFFS2_ERROR("unknown INCOMPAT nodetype %#04X at %#08x\n", |
367 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 384 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
368 | /* EEP */ | 385 | /* EEP */ |
369 | BUG(); | 386 | BUG(); |
370 | break; | 387 | break; |
371 | 388 | ||
372 | case JFFS2_FEATURE_ROCOMPAT: | 389 | case JFFS2_FEATURE_ROCOMPAT: |
373 | JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n", | 390 | JFFS2_ERROR("unknown ROCOMPAT nodetype %#04X at %#08x\n", |
374 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 391 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
375 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); | 392 | BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO)); |
376 | break; | 393 | break; |
377 | 394 | ||
378 | case JFFS2_FEATURE_RWCOMPAT_COPY: | 395 | case JFFS2_FEATURE_RWCOMPAT_COPY: |
379 | JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", | 396 | JFFS2_NOTICE("unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n", |
380 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 397 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
381 | break; | 398 | break; |
382 | 399 | ||
383 | case JFFS2_FEATURE_RWCOMPAT_DELETE: | 400 | case JFFS2_FEATURE_RWCOMPAT_DELETE: |
384 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", | 401 | JFFS2_NOTICE("unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n", |
385 | je16_to_cpu(un->nodetype), ref_offset(ref)); | 402 | je16_to_cpu(un->nodetype), ref_offset(ref)); |
386 | return 1; | 403 | return 1; |
387 | } | ||
388 | } | 404 | } |
389 | 405 | ||
390 | return 0; | 406 | return 0; |
@@ -434,7 +450,7 @@ static int read_more(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, | |||
434 | } | 450 | } |
435 | 451 | ||
436 | if (retlen < len) { | 452 | if (retlen < len) { |
437 | JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", | 453 | JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", |
438 | offs, retlen, len); | 454 | offs, retlen, len); |
439 | return -EIO; | 455 | return -EIO; |
440 | } | 456 | } |
@@ -542,13 +558,25 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
542 | } | 558 | } |
543 | 559 | ||
544 | if (retlen < len) { | 560 | if (retlen < len) { |
545 | JFFS2_ERROR("short read at %#08x: %d instead of %d.\n", ref_offset(ref), retlen, len); | 561 | JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", ref_offset(ref), retlen, len); |
546 | err = -EIO; | 562 | err = -EIO; |
547 | goto free_out; | 563 | goto free_out; |
548 | } | 564 | } |
549 | 565 | ||
550 | node = (union jffs2_node_union *)bufstart; | 566 | node = (union jffs2_node_union *)bufstart; |
551 | 567 | ||
568 | /* No need to mask in the valid bit; it shouldn't be invalid */ | ||
569 | if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) { | ||
570 | JFFS2_NOTICE("Node header CRC failed at %#08x. {%04x,%04x,%08x,%08x}\n", | ||
571 | ref_offset(ref), je16_to_cpu(node->u.magic), | ||
572 | je16_to_cpu(node->u.nodetype), | ||
573 | je32_to_cpu(node->u.totlen), | ||
574 | je32_to_cpu(node->u.hdr_crc)); | ||
575 | jffs2_dbg_dump_node(c, ref_offset(ref)); | ||
576 | jffs2_mark_node_obsolete(c, ref); | ||
577 | goto cont; | ||
578 | } | ||
579 | |||
552 | switch (je16_to_cpu(node->u.nodetype)) { | 580 | switch (je16_to_cpu(node->u.nodetype)) { |
553 | 581 | ||
554 | case JFFS2_NODETYPE_DIRENT: | 582 | case JFFS2_NODETYPE_DIRENT: |
@@ -606,6 +634,7 @@ static int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_inf | |||
606 | goto free_out; | 634 | goto free_out; |
607 | 635 | ||
608 | } | 636 | } |
637 | cont: | ||
609 | spin_lock(&c->erase_completion_lock); | 638 | spin_lock(&c->erase_completion_lock); |
610 | } | 639 | } |
611 | 640 | ||
@@ -679,12 +708,12 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
679 | jffs2_mark_node_obsolete(c, fn->raw); | 708 | jffs2_mark_node_obsolete(c, fn->raw); |
680 | 709 | ||
681 | BUG_ON(rb->rb_left); | 710 | BUG_ON(rb->rb_left); |
682 | if (rb->rb_parent && rb->rb_parent->rb_left == rb) { | 711 | if (rb_parent(rb) && rb_parent(rb)->rb_left == rb) { |
683 | /* We were then left-hand child of our parent. We need | 712 | /* We were then left-hand child of our parent. We need |
684 | * to move our own right-hand child into our place. */ | 713 | * to move our own right-hand child into our place. */ |
685 | repl_rb = rb->rb_right; | 714 | repl_rb = rb->rb_right; |
686 | if (repl_rb) | 715 | if (repl_rb) |
687 | repl_rb->rb_parent = rb->rb_parent; | 716 | rb_set_parent(repl_rb, rb_parent(rb)); |
688 | } else | 717 | } else |
689 | repl_rb = NULL; | 718 | repl_rb = NULL; |
690 | 719 | ||
@@ -692,14 +721,14 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, | |||
692 | 721 | ||
693 | /* Remove the spent tn from the tree; don't bother rebalancing | 722 | /* Remove the spent tn from the tree; don't bother rebalancing |
694 | * but put our right-hand child in our own place. */ | 723 | * but put our right-hand child in our own place. */ |
695 | if (tn->rb.rb_parent) { | 724 | if (rb_parent(&tn->rb)) { |
696 | if (tn->rb.rb_parent->rb_left == &tn->rb) | 725 | if (rb_parent(&tn->rb)->rb_left == &tn->rb) |
697 | tn->rb.rb_parent->rb_left = repl_rb; | 726 | rb_parent(&tn->rb)->rb_left = repl_rb; |
698 | else if (tn->rb.rb_parent->rb_right == &tn->rb) | 727 | else if (rb_parent(&tn->rb)->rb_right == &tn->rb) |
699 | tn->rb.rb_parent->rb_right = repl_rb; | 728 | rb_parent(&tn->rb)->rb_right = repl_rb; |
700 | else BUG(); | 729 | else BUG(); |
701 | } else if (tn->rb.rb_right) | 730 | } else if (tn->rb.rb_right) |
702 | tn->rb.rb_right->rb_parent = NULL; | 731 | rb_set_parent(tn->rb.rb_right, NULL); |
703 | 732 | ||
704 | jffs2_free_tmp_dnode_info(tn); | 733 | jffs2_free_tmp_dnode_info(tn); |
705 | if (ret) { | 734 | if (ret) { |