if (crc != tn->data_crc) {
JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
- ofs, tn->data_crc, crc);
+ ref_offset(ref), tn->data_crc, crc);
return 1;
}
* offset, and the one with the smallest length will come first in the
* ordering.
*
- * Returns 0 if the node was inserted
- * 1 if the node is obsolete (because we can't mark it so yet)
+ * Returns 0 if the node was handled (including marking it obsolete)
* < 0 an if error occurred
*/
static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
check anyway. */
if (!tn->fn->size) {
if (rii->mdata_tn) {
- /* We had a candidate mdata node already */
- dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version);
- jffs2_kill_tn(c, rii->mdata_tn);
+ if (rii->mdata_tn->version < tn->version) {
+ /* We had a candidate mdata node already */
+ dbg_readinode("kill old mdata with ver %d\n", rii->mdata_tn->version);
+ jffs2_kill_tn(c, rii->mdata_tn);
+ } else {
+ dbg_readinode("kill new mdata with ver %d (older than existing %d\n",
+ tn->version, rii->mdata_tn->version);
+ jffs2_kill_tn(c, tn);
+ return 0;
+ }
}
rii->mdata_tn = tn;
dbg_readinode("keep new mdata with ver %d\n", tn->version);
/* Find the earliest node which _may_ be relevant to this one */
this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs);
- if (!this) {
- /* First addition to empty tree. $DEITY how I love the easy cases */
- rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node);
- rb_insert_color(&tn->rb, &rii->tn_root);
- dbg_readinode("keep new frag\n");
- return 0;
- }
-
- /* If the node is coincident with another at a lower address,
- back up until the other node is found. It may be relevant */
- while (tn->overlapped)
- tn = tn_prev(tn);
+ if (this) {
+ /* If the node is coincident with another at a lower address,
+ back up until the other node is found. It may be relevant */
+ while (this->overlapped)
+ this = tn_prev(this);
- dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+ /* First node should never be marked overlapped */
+ BUG_ON(!this);
+ dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
+ }
while (this) {
if (this->fn->ofs > fn_end)
return 0;
}
/* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
- while (this && this->fn->ofs + this->fn->size < fn_end) {
+ while (this && this->fn->ofs + this->fn->size <= fn_end) {
struct jffs2_tmp_dnode_info *next = tn_next(this);
if (this->version < tn->version) {
tn_erase(this, &rii->tn_root);
this = next;
}
dbg_readinode("Done killing overlapped nodes\n");
- break;
+ continue;
}
if (this->version > tn->version &&
this->fn->ofs <= tn->fn->ofs &&
{
struct rb_node *parent;
struct rb_node **link = &rii->tn_root.rb_node;
- struct jffs2_tmp_dnode_info *insert_point;
+ struct jffs2_tmp_dnode_info *insert_point = NULL;
while (*link) {
parent = *link;
rb_insert_color(&tn->rb, &rii->tn_root);
}
- calc_overlaps:
/* If there's anything behind that overlaps us, note it */
this = tn_prev(tn);
if (this) {
* Helper function for jffs2_get_inode_nodes().
* It is called every time an directory entry node is found.
*
- * Returns: 0 on succes;
- * 1 if the node should be marked obsolete;
+ * Returns: 0 on success;
* negative error code on failure.
*/
static inline int read_direntry(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
jeb->unchecked_size -= len;
c->used_size += len;
c->unchecked_size -= len;
- ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
+ ref->flash_offset = ref_offset(ref) | dirent_node_state(rd);
spin_unlock(&c->erase_completion_lock);
}
* Helper function for jffs2_get_inode_nodes().
* It is called every time an inode node is found.
*
- * Returns: 0 on success;
- * 1 if the node should be marked obsolete;
+ * Returns: 0 on success (possibly after marking a bad node obsolete);
* negative error code on failure.
*/
static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref,
{
struct jffs2_tmp_dnode_info *tn;
uint32_t len, csize;
- int ret = 1;
+ int ret = 0;
uint32_t crc;
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
/* Sanity checks */
if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
- JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));
- jffs2_dbg_dump_node(c, ref_offset(ref));
+ JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));
+ jffs2_dbg_dump_node(c, ref_offset(ref));
+ jffs2_mark_node_obsolete(c, ref);
goto free_out;
}
if (len >= csize && unlikely(tn->partial_crc != je32_to_cpu(rd->data_crc))) {
JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
ref_offset(ref), tn->partial_crc, je32_to_cpu(rd->data_crc));
+ jffs2_mark_node_obsolete(c, ref);
goto free_out;
}
* It is called every time an unknown node is found.
*
* Returns: 0 on success;
- * 1 if the node should be marked obsolete;
* negative error code on failure.
*/
static inline int read_unknown(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref, struct jffs2_unknown_node *un)
case JFFS2_NODETYPE_DIRENT:
- if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent)) {
+ if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) &&
+ len < sizeof(struct jffs2_raw_dirent)) {
err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf);
if (unlikely(err))
goto free_out;
case JFFS2_NODETYPE_INODE:
- if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode)) {
+ if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) &&
+ len < sizeof(struct jffs2_raw_inode)) {
err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf);
if (unlikely(err))
goto free_out;
break;
default:
- if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node)) {
+ if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node) &&
+ len < sizeof(struct jffs2_unknown_node)) {
err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf);
if (unlikely(err))
goto free_out;
}
err = read_unknown(c, ref, &node->u);
- if (err == 1) {
- jffs2_mark_node_obsolete(c, ref);
- break;
- } else if (unlikely(err))
+ if (unlikely(err))
goto free_out;
}