uint32_t fn_end = tn->fn->ofs + tn->fn->size;
struct jffs2_tmp_dnode_info *this;
- dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version);
+ dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
/* If a node has zero dsize, we only have to keep if it if it might be the
node with highest version -- i.e. the one which will end up as f->metadata.
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;
} else {
/* Who cares if the new one is good; keep it for now anyway. */
+ dbg_readinode("Like new node. Throw away old\n");
rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
- /* Same overlapping from in front and behind */
jffs2_kill_tn(c, this);
- dbg_readinode("Like new node. Throw away old\n");
- goto calc_overlaps;
+ /* Same overlapping from in front and behind */
+ return 0;
}
}
if (this->version < tn->version &&
jffs2_kill_tn(c, tn);
return 0;
}
- /* ... and is good. Kill 'this'... */
- rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
- jffs2_kill_tn(c, this);
- /* ... and any subsequent nodes which are also overlapped */
- this = tn_next(tn);
- while (this && this->fn->ofs + this->fn->size < fn_end) {
+ /* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */
+ 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 inserting new\n");
- goto calc_overlaps;
+ dbg_readinode("Done killing overlapped nodes\n");
+ continue;
}
if (this->version > tn->version &&
this->fn->ofs <= tn->fn->ofs &&
return 0;
}
/* ... but 'this' was bad. Replace it... */
- tn->overlapped = this->overlapped;
- rb_replace_node(&this->rb, &tn->rb, &rii->tn_root);
dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
+ tn_erase(this, &rii->tn_root);
jffs2_kill_tn(c, this);
- return 0;
+ break;
}
this = tn_next(this);
{
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) {
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;