diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-05-20 19:02:06 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-20 19:02:06 -0400 |
commit | 6171586a7ae5198988774e8480631e8d15f65dfe (patch) | |
tree | eef74bde60005c4e39c0c213030b27cb07a5c236 | |
parent | fb9fbbcc9389edabb172ac1b6419c01e32046787 (diff) |
[JFFS2] Correct handling of JFFS2_FEATURE_RWCOMPAT_COPY nodes.
We should preserve these when we come to garbage collect them, not let
them get erased. Use jffs2_garbage_collect_pristine() for this, and make
sure the summary code copes -- just refrain from writing a summary for any
block which contains a node we don't understand.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r-- | fs/jffs2/gc.c | 49 | ||||
-rw-r--r-- | fs/jffs2/nodelist.h | 5 | ||||
-rw-r--r-- | fs/jffs2/scan.c | 15 | ||||
-rw-r--r-- | fs/jffs2/summary.c | 9 |
4 files changed, 55 insertions, 23 deletions
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index 23587f8a221f..b0a5c407b476 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
@@ -256,10 +256,14 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) | |||
256 | 256 | ||
257 | if (!raw->next_in_ino) { | 257 | if (!raw->next_in_ino) { |
258 | /* Inode-less node. Clean marker, snapshot or something like that */ | 258 | /* Inode-less node. Clean marker, snapshot or something like that */ |
259 | /* FIXME: If it's something that needs to be copied, including something | ||
260 | we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ | ||
261 | spin_unlock(&c->erase_completion_lock); | 259 | spin_unlock(&c->erase_completion_lock); |
262 | jffs2_mark_node_obsolete(c, raw); | 260 | if (ref_flags(raw) == REF_PRISTINE) { |
261 | /* It's an unknown node with JFFS2_FEATURE_RWCOMPAT_COPY */ | ||
262 | jffs2_garbage_collect_pristine(c, NULL, raw); | ||
263 | } else { | ||
264 | /* Just mark it obsolete */ | ||
265 | jffs2_mark_node_obsolete(c, raw); | ||
266 | } | ||
263 | up(&c->alloc_sem); | 267 | up(&c->alloc_sem); |
264 | goto eraseit_lock; | 268 | goto eraseit_lock; |
265 | } | 269 | } |
@@ -533,15 +537,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
533 | 537 | ||
534 | D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); | 538 | D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); |
535 | 539 | ||
536 | rawlen = ref_totlen(c, c->gcblock, raw); | 540 | alloclen = rawlen = ref_totlen(c, c->gcblock, raw); |
537 | 541 | ||
538 | /* Ask for a small amount of space (or the totlen if smaller) because we | 542 | /* Ask for a small amount of space (or the totlen if smaller) because we |
539 | don't want to force wastage of the end of a block if splitting would | 543 | don't want to force wastage of the end of a block if splitting would |
540 | work. */ | 544 | work. */ |
541 | ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + | 545 | if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) |
542 | JFFS2_MIN_DATA_LEN, rawlen), &phys_ofs, &alloclen, rawlen); | 546 | alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN; |
543 | /* this is not the exact summary size of it, | 547 | |
544 | it is only an upper estimation */ | 548 | ret = jffs2_reserve_space_gc(c, alloclen, &phys_ofs, &alloclen, rawlen); |
549 | /* 'rawlen' is not the exact summary size; it is only an upper estimation */ | ||
545 | 550 | ||
546 | if (ret) | 551 | if (ret) |
547 | return ret; | 552 | return ret; |
@@ -605,9 +610,12 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
605 | } | 610 | } |
606 | break; | 611 | break; |
607 | default: | 612 | default: |
608 | printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", | 613 | /* If it's inode-less, we don't _know_ what it is. Just copy it intact */ |
609 | ref_offset(raw), je16_to_cpu(node->u.nodetype)); | 614 | if (ic) { |
610 | goto bail; | 615 | printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", |
616 | ref_offset(raw), je16_to_cpu(node->u.nodetype)); | ||
617 | goto bail; | ||
618 | } | ||
611 | } | 619 | } |
612 | 620 | ||
613 | nraw = jffs2_alloc_raw_node_ref(); | 621 | nraw = jffs2_alloc_raw_node_ref(); |
@@ -674,15 +682,16 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, | |||
674 | nraw->flash_offset |= REF_PRISTINE; | 682 | nraw->flash_offset |= REF_PRISTINE; |
675 | jffs2_add_physical_node_ref(c, nraw); | 683 | jffs2_add_physical_node_ref(c, nraw); |
676 | 684 | ||
677 | /* Link into per-inode list. This is safe because of the ic | 685 | if (ic) { |
678 | state being INO_STATE_GC. Note that if we're doing this | 686 | /* Link into per-inode list. This is safe because of the ic |
679 | for an inode which is in-core, the 'nraw' pointer is then | 687 | state being INO_STATE_GC. Note that if we're doing this |
680 | going to be fetched from ic->nodes by our caller. */ | 688 | for an inode which is in-core, the 'nraw' pointer is then |
681 | spin_lock(&c->erase_completion_lock); | 689 | going to be fetched from ic->nodes by our caller. */ |
682 | nraw->next_in_ino = ic->nodes; | 690 | spin_lock(&c->erase_completion_lock); |
683 | ic->nodes = nraw; | 691 | nraw->next_in_ino = ic->nodes; |
684 | spin_unlock(&c->erase_completion_lock); | 692 | ic->nodes = nraw; |
685 | 693 | spin_unlock(&c->erase_completion_lock); | |
694 | } | ||
686 | jffs2_mark_node_obsolete(c, raw); | 695 | jffs2_mark_node_obsolete(c, raw); |
687 | D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); | 696 | D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); |
688 | 697 | ||
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index bac4ec35bbd0..1f5d5b0100aa 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
@@ -97,6 +97,11 @@ struct jffs2_raw_node_ref | |||
97 | #define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) | 97 | #define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) |
98 | #define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) | 98 | #define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) |
99 | 99 | ||
100 | /* NB: REF_PRISTINE for an inode-less node (ref->next_in_ino == NULL) indicates | ||
101 | it is an unknown node of type JFFS2_NODETYPE_RWCOMPAT_COPY, so it'll get | ||
102 | copied. If you need to do anything different to GC inode-less nodes, then | ||
103 | you need to modify gc.c accordingly. */ | ||
104 | |||
100 | /* For each inode in the filesystem, we need to keep a record of | 105 | /* For each inode in the filesystem, we need to keep a record of |
101 | nlink, because it would be a PITA to scan the whole directory tree | 106 | nlink, because it would be a PITA to scan the whole directory tree |
102 | at read_inode() time to calculate it, and to keep sufficient information | 107 | at read_inode() time to calculate it, and to keep sufficient information |
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 3cbe9f029e01..06637050749d 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c | |||
@@ -851,11 +851,22 @@ scan_more: | |||
851 | ofs += PAD(je32_to_cpu(node->totlen)); | 851 | ofs += PAD(je32_to_cpu(node->totlen)); |
852 | break; | 852 | break; |
853 | 853 | ||
854 | case JFFS2_FEATURE_RWCOMPAT_COPY: | 854 | case JFFS2_FEATURE_RWCOMPAT_COPY: { |
855 | struct jffs2_raw_node_ref *ref; | ||
855 | D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); | 856 | D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); |
856 | USED_SPACE(PAD(je32_to_cpu(node->totlen))); | 857 | |
858 | ref = jffs2_alloc_raw_node_ref(); | ||
859 | if (!ref) | ||
860 | return -ENOMEM; | ||
861 | ref->flash_offset = ofs | REF_PRISTINE; | ||
862 | ref->next_in_ino = 0; | ||
863 | jffs2_link_node_ref(c, jeb, ref, PAD(je32_to_cpu(node->totlen))); | ||
864 | |||
865 | /* We can't summarise nodes we don't grok */ | ||
866 | jffs2_sum_disable_collecting(s); | ||
857 | ofs += PAD(je32_to_cpu(node->totlen)); | 867 | ofs += PAD(je32_to_cpu(node->totlen)); |
858 | break; | 868 | break; |
869 | } | ||
859 | } | 870 | } |
860 | } | 871 | } |
861 | } | 872 | } |
diff --git a/fs/jffs2/summary.c b/fs/jffs2/summary.c index 95b5bf8f4a99..53a84b468cfe 100644 --- a/fs/jffs2/summary.c +++ b/fs/jffs2/summary.c | |||
@@ -760,7 +760,14 @@ static int jffs2_sum_write_data(struct jffs2_sb_info *c, struct jffs2_eraseblock | |||
760 | } | 760 | } |
761 | #endif | 761 | #endif |
762 | default : { | 762 | default : { |
763 | BUG(); /* unknown node in summary information */ | 763 | if ((je16_to_cpu(temp->u.nodetype) & JFFS2_COMPAT_MASK) |
764 | == JFFS2_FEATURE_RWCOMPAT_COPY) { | ||
765 | dbg_summary("Writing unknown RWCOMPAT_COPY node type %x\n", | ||
766 | je16_to_cpu(temp->u.nodetype)); | ||
767 | jffs2_sum_disable_collecting(c->summary); | ||
768 | } else { | ||
769 | BUG(); /* unknown node in summary information */ | ||
770 | } | ||
764 | } | 771 | } |
765 | } | 772 | } |
766 | 773 | ||