/* Calculate how many bytes were already checked */
ofs = ref_offset(ref) + sizeof(struct jffs2_raw_inode);
len = tn->csize;
if (jffs2_is_writebuffered(c)) { int adj = ofs % c->wbuf_pagesize; if (likely(adj))
adj = c->wbuf_pagesize - adj;
if (adj >= tn->csize) {
dbg_readinode("no need to check node at %#08x, data length %u, data starts at %#08x - it has already been checked.\n",
ref_offset(ref), tn->csize, ofs); goto adj_acc;
}
ofs += adj;
len -= adj;
}
dbg_readinode("check node at %#08x, data length %u, partial CRC %#08x, correct CRC %#08x, data starts at %#08x, start checking from %#08x - %u bytes.\n",
ref_offset(ref), tn->csize, tn->partial_crc, tn->data_crc, ofs - len, ofs, len);
#ifndef __ECOS /* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
* adding and jffs2_flash_read_end() interface. */
err = mtd_point(c->mtd, ofs, len, &retlen, (void **)&buffer, NULL); if (!err && retlen < len) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
mtd_unpoint(c->mtd, ofs, retlen);
} elseif (err) { if (err != -EOPNOTSUPP)
JFFS2_WARNING("MTD point failed: error code %d.\n", err);
} else
pointed = 1; /* successfully pointed to device */ #endif
if (!pointed) {
buffer = kmalloc(len, GFP_KERNEL); if (unlikely(!buffer)) return -ENOMEM;
/* TODO: this is very frequent pattern, make it a separate
* routine */
err = jffs2_flash_read(c, ofs, len, &retlen, buffer); if (err) {
JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ofs, err); goto free_out;
}
if (retlen != len) {
JFFS2_ERROR("short read at %#08x: %zd instead of %d.\n", ofs, retlen, len);
err = -EIO; goto free_out;
}
}
if (crc != tn->data_crc) {
JFFS2_NOTICE("wrong data CRC in data node at 0x%08x: read %#08x, calculated %#08x.\n",
ref_offset(ref), tn->data_crc, crc); return1;
}
adj_acc:
jeb = &c->blocks[ref->flash_offset / c->sector_size];
len = ref_totlen(c, jeb, ref); /* If it should be REF_NORMAL, it'll get marked as such when webuildthefragtree,shortly.NoneedtoworryaboutGC movingitwhileit'smarkedREF_PRISTINE--GCwon'thappen
till we've finished checking every inode anyway. */
ref->flash_offset |= REF_PRISTINE; /* *Markthenodeashavingbeencheckedandfixthe *accountingaccordingly.
*/
spin_lock(&c->erase_completion_lock);
jeb->used_size += len;
jeb->unchecked_size -= len;
c->used_size += len;
c->unchecked_size -= len;
jffs2_dbg_acct_paranoia_check_nolock(c, jeb);
spin_unlock(&c->erase_completion_lock);
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 it if it might be the nodewithhighestversion--i.e.theonewhichwillendupasf->metadata. Notethatsuchnodeswon'tbeREF_UNCHECKEDsincetherearenodatato
check anyway. */ if (!tn->fn->size) { if (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); return0;
}
}
rii->mdata_tn = tn;
dbg_readinode("keep new mdata with ver %d\n", tn->version); return0;
}
/* Find the earliest node which _may_ be relevant to this one */ this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs); 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) {
ptn = tn_prev(this); if (!ptn) { /* *Wekilledanodewhichsettheoverlapped *flagsduringthescan.Fixitup.
*/ this->overlapped = 0; break;
} this = ptn;
}
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) break;
dbg_readinode("Ponder this ver %d, 0x%x-0x%x\n", this->version, this->fn->ofs, this->fn->size);
if (this->version == tn->version) { /* Version number collision means REF_PRISTINE GC. Accept either of them
as long as the CRC is correct. Check the one we have already... */ if (!check_tn_node(c, this)) { /* The one we already had was OK. Keep it and throw away the new one */
dbg_readinode("Like old node. Throw away new\n");
jffs2_kill_tn(c, tn); return0;
} 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);
jffs2_kill_tn(c, this); /* Same overlapping from in front and behind */ return0;
}
} if (this->version < tn->version && this->fn->ofs >= tn->fn->ofs && this->fn->ofs + this->fn->size <= fn_end) { /* New node entirely overlaps 'this' */ if (check_tn_node(c, tn)) {
dbg_readinode("new node bad CRC\n");
jffs2_kill_tn(c, tn); return0;
} /* ... 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);
dbg_readinode("Kill overlapped ver %d, 0x%x-0x%x\n", this->version, this->fn->ofs, this->fn->ofs+this->fn->size);
jffs2_kill_tn(c, this);
} this = next;
}
dbg_readinode("Done killing overlapped nodes\n"); continue;
} if (this->version > tn->version && this->fn->ofs <= tn->fn->ofs && this->fn->ofs+this->fn->size >= fn_end) { /* New node entirely overlapped by 'this' */ if (!check_tn_node(c, this)) {
dbg_readinode("Good CRC on old node. Kill new\n");
jffs2_kill_tn(c, tn); return0;
} /* ... but 'this' was bad. Replace it... */
dbg_readinode("Bad CRC on old overlapping node. Kill it\n");
tn_erase(this, &rii->tn_root);
jffs2_kill_tn(c, this); break;
}
this = tn_next(this);
}
/* We neither completely obsoleted nor were completely
obsoleted by an earlier node. Insert into the tree */
{ struct rb_node *parent; struct rb_node **link = &rii->tn_root.rb_node; struct jffs2_tmp_dnode_info *insert_point = NULL;
while (*link) {
parent = *link;
insert_point = rb_entry(parent, struct jffs2_tmp_dnode_info, rb); if (tn->fn->ofs > insert_point->fn->ofs)
link = &insert_point->rb.rb_right; elseif (tn->fn->ofs < insert_point->fn->ofs ||
tn->fn->size < insert_point->fn->size)
link = &insert_point->rb.rb_left; else
link = &insert_point->rb.rb_right;
}
rb_link_node(&tn->rb, &insert_point->rb, link);
rb_insert_color(&tn->rb, &rii->tn_root);
}
/* If there's anything behind that overlaps us, note it */ this = tn_prev(tn); if (this) { while (1) { if (this->fn->ofs + this->fn->size > tn->fn->ofs) {
dbg_readinode("Node is overlapped by %p (v %d, 0x%x-0x%x)\n", this, this->version, this->fn->ofs, this->fn->ofs+this->fn->size);
tn->overlapped = 1; break;
} if (!this->overlapped) break;
ptn = tn_prev(this); if (!ptn) { /* *Wekilledanodewhichsettheoverlapped *flagsduringthescan.Fixitup.
*/ this->overlapped = 0; break;
} this = ptn;
}
}
/* If the new node overlaps anything ahead, note it */ this = tn_next(tn); while (this && this->fn->ofs < fn_end) { this->overlapped = 1;
dbg_readinode("Node ver %d, 0x%x-0x%x is overlapped\n", this->version, this->fn->ofs, this->fn->ofs+this->fn->size); this = tn_next(this);
} return0;
}
/* Trivial function to remove the last node in the tree. Which by definition hasnoright-handchild—socanberemovedjustbymakingitsleft-hand child(ifany)takeitsplaceunderitsparent.Sincethisisonlydone whenwe'reconsumingthewholetree,there'snoneedtouserb_erase() andletitworryaboutadjustingcoloursandbalancingthetree.That
would just be a waste of time. */ staticvoid eat_last(struct rb_root *root, struct rb_node *node)
{ struct rb_node *parent = rb_parent(node); struct rb_node **link;
/* LAST! */
BUG_ON(node->rb_right);
if (!parent)
link = &root->rb_node; elseif (node == parent->rb_left)
link = &parent->rb_left; else
link = &parent->rb_right;
*link = node->rb_left; if (node->rb_left)
node->rb_left->__rb_parent_color = node->__rb_parent_color;
}
/* We put the version tree in reverse order, so we can use the same eat_last()
function that we use to consume the tmpnode tree (tn_root). */ staticvoid ver_insert(struct rb_root *ver_root, struct jffs2_tmp_dnode_info *tn)
{ struct rb_node **link = &ver_root->rb_node; struct rb_node *parent = NULL; struct jffs2_tmp_dnode_info *this_tn;
if (tn->version > this_tn->version)
link = &parent->rb_left; else
link = &parent->rb_right;
}
dbg_readinode("Link new node at %p (root is %p)\n", link, ver_root);
rb_link_node(&tn->rb, parent, link);
rb_insert_color(&tn->rb, ver_root);
}
/* Build final, normal fragtree from tn tree. It doesn't matter which order weaddnodestotherealfragtree,aslongastheydon'toverlap.And havingthrownawaythemajorityofoverlappednodesaswewent,there reallyshouldn'tbemanysetsofnodeswhichdooverlap.Ifwestartat theend,wecanusetheoverlapmarkers--wecanjusteatnodeswhich aren'toverlapped,andwhenweencounternodeswhich_do_overlapwe
sort them all into a temporary tree in version order before replaying them. */ staticint jffs2_build_inode_fragtree(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_readinode_info *rii)
{ struct jffs2_tmp_dnode_info *pen, *last, *this; struct rb_root ver_root = RB_ROOT;
uint32_t high_ver = 0;
if (rii->mdata_tn) {
dbg_readinode("potential mdata is ver %d at %p\n", rii->mdata_tn->version, rii->mdata_tn);
high_ver = rii->mdata_tn->version;
rii->latest_ref = rii->mdata_tn->fn->raw;
} #ifdef JFFS2_DBG_READINODE_MESSAGES this = tn_last(&rii->tn_root); while (this) {
dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, this->fn->ofs+this->fn->size, this->overlapped); this = tn_prev(this);
} #endif
pen = tn_last(&rii->tn_root); while ((last = pen)) {
pen = tn_prev(last);
if (unlikely(last->overlapped)) { if (pen) continue; /* *Wekilledanodewhichsettheoverlapped *flagsduringthescan.Fixitup.
*/
last->overlapped = 0;
}
/* Now we have a bunch of nodes in reverse version order,inthetreeatver_root.Mostofthetime, there'llactuallybeonlyonenodeinthe'tree',
in fact. */ this = tn_last(&ver_root);
while (this) { struct jffs2_tmp_dnode_info *vers_next; int ret;
vers_next = tn_prev(this);
eat_last(&ver_root, &this->rb); if (check_tn_node(c, this)) {
dbg_readinode("node ver %d, 0x%x-0x%x failed CRC\n", this->version, this->fn->ofs, this->fn->ofs+this->fn->size);
jffs2_kill_tn(c, this);
} else { if (this->version > high_ver) { /* Note that this is different from the other highest_version,becausethisoneisonly counting_valid_nodeswhichcouldgivethe
latest inode metadata */
high_ver = this->version;
rii->latest_ref = this->fn->raw;
}
dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n", this, this->version, this->fn->ofs, this->fn->ofs+this->fn->size, this->overlapped);
ret = jffs2_add_full_dnode_to_inode(c, f, this->fn); if (ret) { /* Free the nodes in vers_root; let the caller
deal with the rest */
JFFS2_ERROR("Add node to tree failed %d\n", ret); while (1) {
vers_next = tn_prev(this); if (check_tn_node(c, this))
jffs2_mark_node_obsolete(c, this->fn->raw);
jffs2_free_full_dnode(this->fn);
jffs2_free_tmp_dnode_info(this); this = vers_next; if (!this) break;
eat_last(&ver_root, &vers_next->rb);
} return ret;
}
jffs2_free_tmp_dnode_info(this);
} this = vers_next;
}
} return0;
}
/* Do we need to copy any more of the name directly from the flash? */ if (rd->nsize + sizeof(*rd) > read) { /* FIXME: point() */ int err; int already = read - sizeof(*rd);
if (jffs2_is_writebuffered(c) && csize != 0) { /* At this point we are supposed to check the data CRC *ofouruncheckednode.Butthusfar,wedonot *knowwhetherthenodeisvalidorobsolete.To *figurethisout,weneedtowalkallthenodesof *theinodeandbuildtheinodefragtree.Wedon't *wanttospendtimecheckingdataofnodeswhichmay *laterbefoundtobeobsolete.Soweputoffthefull *dataCRCcheckinguntilwehavereadalltheinode *nodesandhavestartedbuildingthefragtree. * *Thefragtreeisbeingbuiltstartingwithnodes *havingthehighestversionnumber,sowe'llbeable *todetectwhetheranodeisvalid(i.e.,itisnot *overlappedbyanodewithhigherversion)ornot. *Andwe'llbeabletocheckonlythosenodes,which *arenotobsolete. * *Ofcourse,thisoptimizationonlymakessenseincase *ofNANDflashes(orotherflasheswith *!jffs2_can_mark_obsolete()),sinceonNORflashes *nodesaremarkedobsoletephysically. * *SinceNANDflashes(orotherflasheswith *jffs2_is_writebuffered(c))areanywayreadby *fractionsofc->wbuf_pagesize,andwehavejustread *thenodeheader,itislikelythatthestartingpart *ofthenodedataisalsoreadwhenwereadthe *header.Sowedon'tmindtochecktheCRCofthe *startingpartofthedataofthenodenow,andcheck *thesecondpartlater(injffs2_check_node_data()). *Ofcourse,wewillnotneedtore-readandre-check *theNANDpagewhichwehavejustread.Thisiswhywe *readthewholeNANDpageatjffs2_get_inode_nodes(), *whileweneededonlythenodeheader.
*/ unsignedchar *buf;
/* 'buf' will point to the start of data */
buf = (unsignedchar *)rd + sizeof(*rd); /* len will be the read data length */
len = min_t(uint32_t, rdlen - sizeof(*rd), csize);
tn->partial_crc = crc32(0, buf, len);
/* If we actually calculated the whole data CRC
* and it is wrong, drop the node. */ 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;
}
if (tn->version > rii->highest_version)
rii->highest_version = tn->version;
/* There was a bug where we wrote hole nodes out with
csize/dsize swapped. Deal with it */ if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && csize)
tn->fn->size = csize; else// normal case...
tn->fn->size = je32_to_cpu(rd->dsize);
if (jffs2_is_writebuffered(c)) { int rem = to_read % c->wbuf_pagesize;
if (rem)
to_read += c->wbuf_pagesize - rem;
}
/* We need to read more data */
offs = ref_offset(ref) + *rdlen;
dbg_readinode("read more %d bytes\n", to_read);
err = jffs2_flash_read(c, offs, to_read, &retlen, buf + *rdlen); if (err) {
JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", to_read, offs, err); return err;
}
if (retlen < to_read) {
JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n",
offs, retlen, to_read); return -EIO;
}
*rdlen += to_read; return0;
}
/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated withthisino.Performapreliminaryorderingondatanodes,throwingaway thosewhicharecompletelyobsoletedbynewerones.Thenaïveapproachwe usetotakeofjustreturningthem_all_inversionorderwillcauseusto
run out of memory in certain degenerate cases. */ staticint jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_readinode_info *rii)
{ struct jffs2_raw_node_ref *ref, *valid_ref; unsignedchar *buf = NULL; union jffs2_node_union *node;
size_t retlen; int len, err;
rii->mctime_ver = 0;
dbg_readinode("ino #%u\n", f->inocache->ino);
/* FIXME: in case of NOR and available ->point() this
* needs to be fixed. */
len = sizeof(union jffs2_node_union) + c->wbuf_pagesize;
buf = kmalloc(len, GFP_KERNEL); if (!buf) return -ENOMEM;
spin_lock(&c->erase_completion_lock);
valid_ref = jffs2_first_valid_node(f->inocache->nodes); if (!valid_ref && f->inocache->ino != 1)
JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino); while (valid_ref) { /* We can hold a pointer to a non-obsolete node without the spinlock, but_obsolete_nodesmaydisappearatanytime,iftheblock they'reingetserased.Soifwemark'ref'obsoletewhilewe're notholdingthelock,itcangoawayimmediately.Forthatreason, wefindthenextvalidnodefirst,beforeprocessing'ref'.
*/
ref = valid_ref;
valid_ref = jffs2_first_valid_node(ref->next_in_ino);
spin_unlock(&c->erase_completion_lock);
cond_resched();
/* *Atthispointwedon'tknowthetypeofthenodewe'regoing *toread,sowedonotknowthesizeofitsheader.Inorder *tominimizetheamountofflashIOweassumetheheaderis *ofsize=JFFS2_MIN_NODE_HEADER.
*/
len = JFFS2_MIN_NODE_HEADER; if (jffs2_is_writebuffered(c)) { int end, rem;
/* *WeareabouttoreadJFFS2_MIN_NODE_HEADERbytes, *butthisflashhassomeminimalI/Ounit.Itis *possiblethatwe'llneedtoreadmoresoon,soread *uptothenextmin.I/Ounit,inordernotto *re-readthesamemin.I/Ounittwice.
*/
end = ref_offset(ref) + len;
rem = end % c->wbuf_pagesize; if (rem)
end += c->wbuf_pagesize - rem;
len = end - ref_offset(ref);
}
dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref));
/* FIXME: point() */
err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf); if (err) {
JFFS2_ERROR("can not read %d bytes from 0x%08x, error code: %d.\n", len, ref_offset(ref), err); goto free_out;
}
if (retlen < len) {
JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", ref_offset(ref), retlen, len);
err = -EIO; goto free_out;
}
node = (union jffs2_node_union *)buf;
/* No need to mask in the valid bit; it shouldn't be invalid */ if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) {
JFFS2_NOTICE("Node header CRC failed at %#08x. {%04x,%04x,%08x,%08x}\n",
ref_offset(ref), je16_to_cpu(node->u.magic),
je16_to_cpu(node->u.nodetype),
je32_to_cpu(node->u.totlen),
je32_to_cpu(node->u.hdr_crc));
jffs2_dbg_dump_node(c, ref_offset(ref));
jffs2_mark_node_obsolete(c, ref); goto cont;
} if (je16_to_cpu(node->u.magic) != JFFS2_MAGIC_BITMASK) { /* Not a JFFS2 node, whinge and move on */
JFFS2_NOTICE("Wrong magic bitmask 0x%04x in node header at %#08x.\n",
je16_to_cpu(node->u.magic), ref_offset(ref));
jffs2_mark_node_obsolete(c, ref); goto cont;
}
switch (je16_to_cpu(node->u.nodetype)) {
case JFFS2_NODETYPE_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;
}
dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n",
f->inocache->ino, rii->highest_version, rii->latest_mctime,
rii->mctime_ver); return0;
dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
f->inocache->pino_nlink);
memset(&rii, 0, sizeof(rii));
/* Grab all nodes relevant to this ino */
ret = jffs2_get_inode_nodes(c, f, &rii);
if (ret) {
JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret); if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return ret;
}
ret = jffs2_build_inode_fragtree(c, f, &rii); if (ret) {
JFFS2_ERROR("Failed to build final fragtree for inode #%u: error %d\n",
f->inocache->ino, ret); if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
jffs2_free_tmp_dnode_info_list(&rii.tn_root); /* FIXME: We could at least crc-check them all */ if (rii.mdata_tn) {
jffs2_free_full_dnode(rii.mdata_tn->fn);
jffs2_free_tmp_dnode_info(rii.mdata_tn);
rii.mdata_tn = NULL;
} return ret;
}
if (unlikely(!rii.latest_ref)) { /* No data nodes for this inode. */ if (f->inocache->ino != 1) {
JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino); if (!rii.fds) { if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return -EIO;
}
JFFS2_NOTICE("but it has children so we fake some modes for it\n");
}
latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);
latest_node->version = cpu_to_je32(0);
latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);
latest_node->isize = cpu_to_je32(0);
latest_node->gid = cpu_to_je16(0);
latest_node->uid = cpu_to_je16(0); if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return0;
}
ret = jffs2_flash_read(c, ref_offset(rii.latest_ref), sizeof(*latest_node), &retlen, (void *)latest_node); if (ret || retlen != sizeof(*latest_node)) {
JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",
ret, retlen, sizeof(*latest_node)); /* FIXME: If this fails, there seems to be a memory leak. Find it. */ return ret ? ret : -EIO;
}
crc = crc32(0, latest_node, sizeof(*latest_node)-8); if (crc != je32_to_cpu(latest_node->node_crc)) {
JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",
f->inocache->ino, ref_offset(rii.latest_ref)); return -EIO;
}
switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { case S_IFDIR: if (rii.mctime_ver > je32_to_cpu(latest_node->version)) { /* The times in the latest_node are actually older than
mctime in the latest dirent. Cheat. */
latest_node->ctime = latest_node->mtime = cpu_to_je32(rii.latest_mctime);
} break;
case S_IFREG: /* If it was a regular file, truncate it to the latest node's isize */
new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize)); if (new_size != je32_to_cpu(latest_node->isize)) {
JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n",
f->inocache->ino, je32_to_cpu(latest_node->isize), new_size);
latest_node->isize = cpu_to_je32(new_size);
} break;
case S_IFLNK: /* Hack to work around broken isize in old symlink code. Removethiswhendwmw2comestohissensesandstops symlinksfrombeinganentirelygratuitousspecial
case. */ if (!je32_to_cpu(latest_node->isize))
latest_node->isize = latest_node->dsize;
if (f->inocache->state != INO_STATE_CHECKING) { /* Symlink's inode data is the target path. Read it and *keepinRAMtofacilitatequickfollowsymlink
* operation. */
uint32_t csize = je32_to_cpu(latest_node->csize); if (csize > JFFS2_MAX_NAME_LEN) return -ENAMETOOLONG;
f->target = kmalloc(csize + 1, GFP_KERNEL); if (!f->target) {
JFFS2_ERROR("can't allocate %u bytes of memory for the symlink target path cache\n", csize); return -ENOMEM;
}
ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),
csize, &retlen, (char *)f->target);
if (ret || retlen != csize) { if (retlen != csize)
ret = -EIO;
kfree(f->target);
f->target = NULL; return ret;
}
case S_IFBLK: case S_IFCHR: /* Certain inode types should have only one data node, and it's
kept as the metadata node */ if (f->metadata) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode)); return -EIO;
} if (!frag_first(&f->fragtree)) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode)); return -EIO;
} /* ASSERT: f->fraglist != NULL */ if (frag_next(frag_first(&f->fragtree))) {
JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n",
f->inocache->ino, jemode_to_cpu(latest_node->mode)); /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ return -EIO;
} /* OK. We're happy */
f->metadata = frag_first(&f->fragtree)->node;
jffs2_free_node_frag(frag_first(&f->fragtree));
f->fragtree = RB_ROOT; break;
} if (f->inocache->state == INO_STATE_READING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);
return0;
}
/* Scan the list of all nodes present for this ino, build map of versions, etc. */ int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
uint32_t ino, struct jffs2_raw_inode *latest_node)
{
dbg_readinode("read inode #%u\n", ino);
if (f->inocache) { /* Check its state. We may need to wait before we can use it */ switch(f->inocache->state) { case INO_STATE_UNCHECKED: case INO_STATE_CHECKEDABSENT:
f->inocache->state = INO_STATE_READING; break;
case INO_STATE_CHECKING: case INO_STATE_GC: /* If it's in either of these states, we need towaitforwhoever'sgotittofinishand
put it back. */
dbg_readinode("waiting for ino #%u in state %d\n", ino, f->inocache->state);
sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); goto retry_inocache;
case INO_STATE_READING: case INO_STATE_PRESENT: /* Eep. This should never happen. It can happenifLinuxcallsread_inode()again
before clear_inode() has finished though. */
JFFS2_ERROR("Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); /* Fail. That's probably better than allowing it to succeed */
f->inocache = NULL; break;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.