diff options
Diffstat (limited to 'fs/jffs2/nodelist.c')
-rw-r--r-- | fs/jffs2/nodelist.c | 183 |
1 files changed, 176 insertions, 7 deletions
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c index 1d46677afd17..927dfe42ba76 100644 --- a/fs/jffs2/nodelist.c +++ b/fs/jffs2/nodelist.c | |||
@@ -438,8 +438,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
438 | if (c->mtd->point) { | 438 | if (c->mtd->point) { |
439 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); | 439 | err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer); |
440 | if (!err && retlen < tn->csize) { | 440 | if (!err && retlen < tn->csize) { |
441 | JFFS2_WARNING("MTD point returned len too short: %zu " | 441 | JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize); |
442 | "instead of %u.\n", retlen, tn->csize); | ||
443 | c->mtd->unpoint(c->mtd, buffer, ofs, len); | 442 | c->mtd->unpoint(c->mtd, buffer, ofs, len); |
444 | } else if (err) | 443 | } else if (err) |
445 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); | 444 | JFFS2_WARNING("MTD point failed: error code %d.\n", err); |
@@ -462,8 +461,7 @@ static int check_node_data(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info | |||
462 | } | 461 | } |
463 | 462 | ||
464 | if (retlen != len) { | 463 | if (retlen != len) { |
465 | JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", | 464 | JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len); |
466 | ofs, retlen, len); | ||
467 | err = -EIO; | 465 | err = -EIO; |
468 | goto free_out; | 466 | goto free_out; |
469 | } | 467 | } |
@@ -940,6 +938,7 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c) | |||
940 | this = c->inocache_list[i]; | 938 | this = c->inocache_list[i]; |
941 | while (this) { | 939 | while (this) { |
942 | next = this->next; | 940 | next = this->next; |
941 | jffs2_xattr_free_inode(c, this); | ||
943 | jffs2_free_inode_cache(this); | 942 | jffs2_free_inode_cache(this); |
944 | this = next; | 943 | this = next; |
945 | } | 944 | } |
@@ -954,9 +953,13 @@ void jffs2_free_raw_node_refs(struct jffs2_sb_info *c) | |||
954 | 953 | ||
955 | for (i=0; i<c->nr_blocks; i++) { | 954 | for (i=0; i<c->nr_blocks; i++) { |
956 | this = c->blocks[i].first_node; | 955 | this = c->blocks[i].first_node; |
957 | while(this) { | 956 | while (this) { |
958 | next = this->next_phys; | 957 | if (this[REFS_PER_BLOCK].flash_offset == REF_LINK_NODE) |
959 | jffs2_free_raw_node_ref(this); | 958 | next = this[REFS_PER_BLOCK].next_in_ino; |
959 | else | ||
960 | next = NULL; | ||
961 | |||
962 | jffs2_free_refblock(this); | ||
960 | this = next; | 963 | this = next; |
961 | } | 964 | } |
962 | c->blocks[i].first_node = c->blocks[i].last_node = NULL; | 965 | c->blocks[i].first_node = c->blocks[i].last_node = NULL; |
@@ -1047,3 +1050,169 @@ void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) | |||
1047 | cond_resched(); | 1050 | cond_resched(); |
1048 | } | 1051 | } |
1049 | } | 1052 | } |
1053 | |||
1054 | struct jffs2_raw_node_ref *jffs2_link_node_ref(struct jffs2_sb_info *c, | ||
1055 | struct jffs2_eraseblock *jeb, | ||
1056 | uint32_t ofs, uint32_t len, | ||
1057 | struct jffs2_inode_cache *ic) | ||
1058 | { | ||
1059 | struct jffs2_raw_node_ref *ref; | ||
1060 | |||
1061 | BUG_ON(!jeb->allocated_refs); | ||
1062 | jeb->allocated_refs--; | ||
1063 | |||
1064 | ref = jeb->last_node; | ||
1065 | |||
1066 | dbg_noderef("Last node at %p is (%08x,%p)\n", ref, ref->flash_offset, | ||
1067 | ref->next_in_ino); | ||
1068 | |||
1069 | while (ref->flash_offset != REF_EMPTY_NODE) { | ||
1070 | if (ref->flash_offset == REF_LINK_NODE) | ||
1071 | ref = ref->next_in_ino; | ||
1072 | else | ||
1073 | ref++; | ||
1074 | } | ||
1075 | |||
1076 | dbg_noderef("New ref is %p (%08x becomes %08x,%p) len 0x%x\n", ref, | ||
1077 | ref->flash_offset, ofs, ref->next_in_ino, len); | ||
1078 | |||
1079 | ref->flash_offset = ofs; | ||
1080 | |||
1081 | if (!jeb->first_node) { | ||
1082 | jeb->first_node = ref; | ||
1083 | BUG_ON(ref_offset(ref) != jeb->offset); | ||
1084 | } else if (unlikely(ref_offset(ref) != jeb->offset + c->sector_size - jeb->free_size)) { | ||
1085 | uint32_t last_len = ref_totlen(c, jeb, jeb->last_node); | ||
1086 | |||
1087 | JFFS2_ERROR("Adding new ref %p at (0x%08x-0x%08x) not immediately after previous (0x%08x-0x%08x)\n", | ||
1088 | ref, ref_offset(ref), ref_offset(ref)+len, | ||
1089 | ref_offset(jeb->last_node), | ||
1090 | ref_offset(jeb->last_node)+last_len); | ||
1091 | BUG(); | ||
1092 | } | ||
1093 | jeb->last_node = ref; | ||
1094 | |||
1095 | if (ic) { | ||
1096 | ref->next_in_ino = ic->nodes; | ||
1097 | ic->nodes = ref; | ||
1098 | } else { | ||
1099 | ref->next_in_ino = NULL; | ||
1100 | } | ||
1101 | |||
1102 | switch(ref_flags(ref)) { | ||
1103 | case REF_UNCHECKED: | ||
1104 | c->unchecked_size += len; | ||
1105 | jeb->unchecked_size += len; | ||
1106 | break; | ||
1107 | |||
1108 | case REF_NORMAL: | ||
1109 | case REF_PRISTINE: | ||
1110 | c->used_size += len; | ||
1111 | jeb->used_size += len; | ||
1112 | break; | ||
1113 | |||
1114 | case REF_OBSOLETE: | ||
1115 | c->dirty_size += len; | ||
1116 | jeb->dirty_size += len; | ||
1117 | break; | ||
1118 | } | ||
1119 | c->free_size -= len; | ||
1120 | jeb->free_size -= len; | ||
1121 | |||
1122 | #ifdef TEST_TOTLEN | ||
1123 | /* Set (and test) __totlen field... for now */ | ||
1124 | ref->__totlen = len; | ||
1125 | ref_totlen(c, jeb, ref); | ||
1126 | #endif | ||
1127 | return ref; | ||
1128 | } | ||
1129 | |||
1130 | /* No locking, no reservation of 'ref'. Do not use on a live file system */ | ||
1131 | int jffs2_scan_dirty_space(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
1132 | uint32_t size) | ||
1133 | { | ||
1134 | if (!size) | ||
1135 | return 0; | ||
1136 | if (unlikely(size > jeb->free_size)) { | ||
1137 | printk(KERN_CRIT "Dirty space 0x%x larger then free_size 0x%x (wasted 0x%x)\n", | ||
1138 | size, jeb->free_size, jeb->wasted_size); | ||
1139 | BUG(); | ||
1140 | } | ||
1141 | /* REF_EMPTY_NODE is !obsolete, so that works OK */ | ||
1142 | if (jeb->last_node && ref_obsolete(jeb->last_node)) { | ||
1143 | #ifdef TEST_TOTLEN | ||
1144 | jeb->last_node->__totlen += size; | ||
1145 | #endif | ||
1146 | c->dirty_size += size; | ||
1147 | c->free_size -= size; | ||
1148 | jeb->dirty_size += size; | ||
1149 | jeb->free_size -= size; | ||
1150 | } else { | ||
1151 | uint32_t ofs = jeb->offset + c->sector_size - jeb->free_size; | ||
1152 | ofs |= REF_OBSOLETE; | ||
1153 | |||
1154 | jffs2_link_node_ref(c, jeb, ofs, size, NULL); | ||
1155 | } | ||
1156 | |||
1157 | return 0; | ||
1158 | } | ||
1159 | |||
1160 | /* Calculate totlen from surrounding nodes or eraseblock */ | ||
1161 | static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, | ||
1162 | struct jffs2_eraseblock *jeb, | ||
1163 | struct jffs2_raw_node_ref *ref) | ||
1164 | { | ||
1165 | uint32_t ref_end; | ||
1166 | struct jffs2_raw_node_ref *next_ref = ref_next(ref); | ||
1167 | |||
1168 | if (next_ref) | ||
1169 | ref_end = ref_offset(next_ref); | ||
1170 | else { | ||
1171 | if (!jeb) | ||
1172 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
1173 | |||
1174 | /* Last node in block. Use free_space */ | ||
1175 | if (unlikely(ref != jeb->last_node)) { | ||
1176 | printk(KERN_CRIT "ref %p @0x%08x is not jeb->last_node (%p @0x%08x)\n", | ||
1177 | ref, ref_offset(ref), jeb->last_node, jeb->last_node?ref_offset(jeb->last_node):0); | ||
1178 | BUG(); | ||
1179 | } | ||
1180 | ref_end = jeb->offset + c->sector_size - jeb->free_size; | ||
1181 | } | ||
1182 | return ref_end - ref_offset(ref); | ||
1183 | } | ||
1184 | |||
1185 | uint32_t __jffs2_ref_totlen(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, | ||
1186 | struct jffs2_raw_node_ref *ref) | ||
1187 | { | ||
1188 | uint32_t ret; | ||
1189 | |||
1190 | ret = __ref_totlen(c, jeb, ref); | ||
1191 | |||
1192 | #ifdef TEST_TOTLEN | ||
1193 | if (unlikely(ret != ref->__totlen)) { | ||
1194 | if (!jeb) | ||
1195 | jeb = &c->blocks[ref->flash_offset / c->sector_size]; | ||
1196 | |||
1197 | printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", | ||
1198 | ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, | ||
1199 | ret, ref->__totlen); | ||
1200 | if (ref_next(ref)) { | ||
1201 | printk(KERN_CRIT "next %p (0x%08x-0x%08x)\n", ref_next(ref), ref_offset(ref_next(ref)), | ||
1202 | ref_offset(ref_next(ref))+ref->__totlen); | ||
1203 | } else | ||
1204 | printk(KERN_CRIT "No next ref. jeb->last_node is %p\n", jeb->last_node); | ||
1205 | |||
1206 | printk(KERN_CRIT "jeb->wasted_size %x, dirty_size %x, used_size %x, free_size %x\n", jeb->wasted_size, jeb->dirty_size, jeb->used_size, jeb->free_size); | ||
1207 | |||
1208 | #if defined(JFFS2_DBG_DUMPS) || defined(JFFS2_DBG_PARANOIA_CHECKS) | ||
1209 | __jffs2_dbg_dump_node_refs_nolock(c, jeb); | ||
1210 | #endif | ||
1211 | |||
1212 | WARN_ON(1); | ||
1213 | |||
1214 | ret = ref->__totlen; | ||
1215 | } | ||
1216 | #endif /* TEST_TOTLEN */ | ||
1217 | return ret; | ||
1218 | } | ||