Commit dae6227f authored by Artem B. Bityutskiy's avatar Artem B. Bityutskiy Committed by Thomas Gleixner

[JFFS2] Split a large routine on several smaller.

Signed-off-by: default avatarArtem B. Bityutskiy <dedekind@infradead.org>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 2fc29911
......@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: nodelist.c,v 1.98 2005/07/10 15:15:32 dedekind Exp $
* $Id: nodelist.c,v 1.99 2005/07/15 10:13:54 dedekind Exp $
*
*/
......@@ -137,239 +137,191 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r
return NULL;
}
/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
with this ino, returning the former in order of version */
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct rb_root *tnp, struct jffs2_full_dirent **fdp,
uint32_t *highest_version, uint32_t *latest_mctime,
/*
* 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;
* negative error code on failure.
*/
static inline int
read_direntry(struct jffs2_sb_info *c,
struct jffs2_raw_node_ref *ref,
struct jffs2_raw_dirent *rd,
uint32_t read,
struct jffs2_full_dirent **fdp,
int32_t *latest_mctime,
uint32_t *mctime_ver)
{
struct jffs2_raw_node_ref *ref, *valid_ref;
struct jffs2_tmp_dnode_info *tn;
struct rb_root ret_tn = RB_ROOT;
struct jffs2_full_dirent *fd, *ret_fd = NULL;
union jffs2_node_union node;
size_t retlen;
int err;
*mctime_ver = 0;
D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
spin_lock(&c->erase_completion_lock);
valid_ref = jffs2_first_valid_node(f->inocache->nodes);
if (!valid_ref && (f->inocache->ino != 1))
printk(KERN_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_ nodes may disappear at any time, if the block
they're in gets erased. So if we mark 'ref' obsolete while we're
not holding the lock, it can go away immediately. For that reason,
we find the next valid node first, before processing 'ref'.
*/
ref = valid_ref;
valid_ref = jffs2_first_valid_node(ref->next_in_ino);
spin_unlock(&c->erase_completion_lock);
cond_resched();
/* FIXME: point() */
err = jffs2_flash_read(c, (ref_offset(ref)),
min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
&retlen, (void *)&node);
if (err) {
printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
goto free_out;
}
struct jffs2_full_dirent *fd;
/* The direntry nodes are checked during the flash scanning */
BUG_ON(ref_flags(ref) == REF_UNCHECKED);
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
BUG_ON(ref_obsolete(ref));
/* Check we've managed to read at least the common node header */
if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) {
printk(KERN_WARNING "short read in get_inode_nodes()\n");
err = -EIO;
goto free_out;
/* Sanity check */
if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
printk(KERN_ERR "Error! Illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
return 1;
}
switch (je16_to_cpu(node.u.nodetype)) {
case JFFS2_NODETYPE_DIRENT:
D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
if (ref_flags(ref) == REF_UNCHECKED) {
printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref));
BUG();
}
if (retlen < sizeof(node.d)) {
printk(KERN_WARNING "short read in get_inode_nodes()\n");
err = -EIO;
goto free_out;
}
/* sanity check */
if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n",
ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen));
jffs2_mark_node_obsolete(c, ref);
spin_lock(&c->erase_completion_lock);
continue;
}
if (je32_to_cpu(node.d.version) > *highest_version)
*highest_version = je32_to_cpu(node.d.version);
if (ref_obsolete(ref)) {
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n",
ref_offset(ref));
BUG();
}
fd = jffs2_alloc_full_dirent(rd->nsize + 1);
if (unlikely(!fd))
return -ENOMEM;
fd = jffs2_alloc_full_dirent(node.d.nsize+1);
if (!fd) {
err = -ENOMEM;
goto free_out;
}
fd->raw = ref;
fd->version = je32_to_cpu(node.d.version);
fd->ino = je32_to_cpu(node.d.ino);
fd->type = node.d.type;
fd->version = je32_to_cpu(rd->version);
fd->ino = je32_to_cpu(rd->ino);
fd->type = rd->type;
/* Pick out the mctime of the latest dirent */
if(fd->version > *mctime_ver) {
*mctime_ver = fd->version;
*latest_mctime = je32_to_cpu(node.d.mctime);
*latest_mctime = je32_to_cpu(rd->mctime);
}
/* memcpy as much of the name as possible from the raw
dirent we've already read from the flash
/*
* Copy as much of the name as possible from the raw
* dirent we've already read from the flash.
*/
if (retlen > sizeof(struct jffs2_raw_dirent))
memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent))));
if (read > sizeof(*rd))
memcpy(&fd->name[0], &rd->name[0],
min_t(uint32_t, rd->nsize, (read - sizeof(*rd)) ));
/* Do we need to copy any more of the name directly
from the flash?
*/
if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) {
/* Do we need to copy any more of the name directly from the flash? */
if (rd->nsize + sizeof(*rd) > read) {
/* FIXME: point() */
int already = retlen - sizeof(struct jffs2_raw_dirent);
int err;
int already = read - sizeof(*rd);
err = jffs2_flash_read(c, (ref_offset(ref)) + retlen,
node.d.nsize - already, &retlen, &fd->name[already]);
if (!err && retlen != node.d.nsize - already)
err = -EIO;
err = jffs2_flash_read(c, (ref_offset(ref)) + read,
rd->nsize - already, &read, &fd->name[already]);
if (unlikely(read != rd->nsize - already) && likely(!err))
return -EIO;
if (err) {
if (unlikely(err)) {
printk(KERN_WARNING "Read remainder of name in jffs2_get_inode_nodes(): error %d\n", err);
jffs2_free_full_dirent(fd);
goto free_out;
return -EIO;
}
}
fd->nhash = full_name_hash(fd->name, node.d.nsize);
fd->nhash = full_name_hash(fd->name, rd->nsize);
fd->next = NULL;
fd->name[node.d.nsize] = '\0';
/* Wheee. We now have a complete jffs2_full_dirent structure, with
the name in it and everything. Link it into the list
fd->name[rd->nsize] = '\0';
/*
* Wheee. We now have a complete jffs2_full_dirent structure, with
* the name in it and everything. Link it into the list
*/
D1(printk(KERN_DEBUG "Adding fd \"%s\", ino #%u\n", fd->name, fd->ino));
jffs2_add_fd_to_list(c, fd, &ret_fd);
break;
case JFFS2_NODETYPE_INODE:
D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
if (retlen < sizeof(node.i)) {
printk(KERN_WARNING "read too short for dnode\n");
err = -EIO;
goto free_out;
}
if (je32_to_cpu(node.i.version) > *highest_version)
*highest_version = je32_to_cpu(node.i.version);
D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version));
jffs2_add_fd_to_list(c, fd, fdp);
return 0;
}
/*
* Helper function for jffs2_get_inode_nodes().
* It is called every time an inode node is found.
*
* Returns: 0 on succes;
* 1 if the node should be marked obsolete;
* negative error code on failure.
*/
static inline int
read_dnode(struct jffs2_sb_info *c,
struct jffs2_raw_node_ref *ref,
struct jffs2_raw_inode *rd,
uint32_t read,
struct rb_root *tnp,
int32_t *latest_mctime,
uint32_t *mctime_ver)
{
struct jffs2_eraseblock *jeb;
struct jffs2_tmp_dnode_info *tn;
if (ref_obsolete(ref)) {
/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n",
ref_offset(ref));
BUG();
}
BUG_ON(ref_obsolete(ref));
/* If we've never checked the CRCs on this node, check them now. */
/* If we've never checked the CRCs on this node, check them now */
if (ref_flags(ref) == REF_UNCHECKED) {
uint32_t crc, len;
struct jffs2_eraseblock *jeb;
crc = crc32(0, &node, sizeof(node.i)-8);
if (crc != je32_to_cpu(node.i.node_crc)) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ref_offset(ref), je32_to_cpu(node.i.node_crc), crc);
jffs2_mark_node_obsolete(c, ref);
spin_lock(&c->erase_completion_lock);
continue;
crc = crc32(0, rd, sizeof(*rd) - 8);
if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
printk(KERN_WARNING "Header CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
return 1;
}
/* sanity checks */
if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) ||
PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n",
ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino),
je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize),
je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize));
jffs2_mark_node_obsolete(c, ref);
spin_lock(&c->erase_completion_lock);
continue;
/* 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)))) {
printk(KERN_WARNING "Inode corrupted at %#08x, totlen %d, #ino %d, version %d, "
"isize %d, csize %d, dsize %d \n",
ref_offset(ref), je32_to_cpu(rd->totlen), je32_to_cpu(rd->ino),
je32_to_cpu(rd->version), je32_to_cpu(rd->isize),
je32_to_cpu(rd->csize), je32_to_cpu(rd->dsize));
return 1;
}
if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) {
unsigned char *buf=NULL;
if (rd->compr != JFFS2_COMPR_ZERO && je32_to_cpu(rd->csize)) {
unsigned char *buf = NULL;
uint32_t pointed = 0;
int err;
#ifndef __ECOS
if (c->mtd->point) {
err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
&retlen, &buf);
if (!err && retlen < je32_to_cpu(node.i.csize)) {
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
} else if (err){
err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize),
&read, &buf);
if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) {
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", read));
c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd),
je32_to_cpu(rd->csize));
} else if (unlikely(err)){
D1(printk(KERN_DEBUG "MTD point failed %d\n", err));
} else
pointed = 1; /* succefully pointed to device */
}
#endif
if(!pointed){
buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL);
buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL);
if (!buf)
return -ENOMEM;
err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize),
&retlen, buf);
if (!err && retlen != je32_to_cpu(node.i.csize))
err = jffs2_flash_read(c, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize),
&read, buf);
if (unlikely(read != je32_to_cpu(rd->csize)) && likely(!err))
err = -EIO;
if (err) {
kfree(buf);
return err;
}
}
crc = crc32(0, buf, je32_to_cpu(node.i.csize));
crc = crc32(0, buf, je32_to_cpu(rd->csize));
if(!pointed)
kfree(buf);
#ifndef __ECOS
else
c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize));
c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize));
#endif
if (crc != je32_to_cpu(node.i.data_crc)) {
printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
ref_offset(ref), je32_to_cpu(node.i.data_crc), crc);
jffs2_mark_node_obsolete(c, ref);
spin_lock(&c->erase_completion_lock);
continue;
if (crc != je32_to_cpu(rd->data_crc)) {
printk(KERN_NOTICE "Data CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
ref_offset(ref), je32_to_cpu(rd->data_crc), crc);
return 1;
}
}
/* Mark the node as having been checked and fix the accounting accordingly */
spin_lock(&c->erase_completion_lock);
jeb = &c->blocks[ref->flash_offset / c->sector_size];
len = ref_totlen(c, jeb, ref);
spin_lock(&c->erase_completion_lock);
jeb->used_size += len;
jeb->unchecked_size -= len;
c->used_size += len;
......@@ -382,13 +334,13 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
If it's actually overlapped, it'll get made NORMAL (or OBSOLETE)
when the overlapping node(s) get added to the tree anyway.
*/
if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) ||
( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) &&
(je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) {
D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref)));
if ((je32_to_cpu(rd->dsize) >= PAGE_CACHE_SIZE) ||
( ((je32_to_cpu(rd->offset) & (PAGE_CACHE_SIZE-1))==0) &&
(je32_to_cpu(rd->dsize) + je32_to_cpu(rd->offset) == je32_to_cpu(rd->isize)))) {
D1(printk(KERN_DEBUG "Marking node at %#08x REF_PRISTINE\n", ref_offset(ref)));
ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
} else {
D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref)));
D1(printk(KERN_DEBUG "Marking node at %#08x REF_NORMAL\n", ref_offset(ref)));
ref->flash_offset = ref_offset(ref) | REF_NORMAL;
}
spin_unlock(&c->erase_completion_lock);
......@@ -397,82 +349,205 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
tn = jffs2_alloc_tmp_dnode_info();
if (!tn) {
D1(printk(KERN_DEBUG "alloc tn failed\n"));
err = -ENOMEM;
goto free_out;
return -ENOMEM;
}
tn->fn = jffs2_alloc_full_dnode();
if (!tn->fn) {
D1(printk(KERN_DEBUG "alloc fn failed\n"));
err = -ENOMEM;
jffs2_free_tmp_dnode_info(tn);
goto free_out;
return -ENOMEM;
}
tn->version = je32_to_cpu(node.i.version);
tn->fn->ofs = je32_to_cpu(node.i.offset);
tn->version = je32_to_cpu(rd->version);
tn->fn->ofs = je32_to_cpu(rd->offset);
tn->fn->raw = ref;
/* There was a bug where we wrote hole nodes out with
csize/dsize swapped. Deal with it */
if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize))
tn->fn->size = je32_to_cpu(node.i.csize);
if (rd->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(rd->dsize) && je32_to_cpu(rd->csize))
tn->fn->size = je32_to_cpu(rd->csize);
else // normal case...
tn->fn->size = je32_to_cpu(node.i.dsize);
tn->fn->raw = ref;
D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n",
ref_offset(ref), je32_to_cpu(node.i.version),
je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize)));
jffs2_add_tn_to_tree(tn, &ret_tn);
break;
tn->fn->size = je32_to_cpu(rd->dsize);
default:
if (ref_flags(ref) == REF_UNCHECKED) {
struct jffs2_eraseblock *jeb;
uint32_t len;
D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %#04x, dsize %#04x\n",
ref_offset(ref), je32_to_cpu(rd->version),
je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize)));
printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n",
je16_to_cpu(node.u.nodetype), ref_offset(ref));
jffs2_add_tn_to_tree(tn, tnp);
/* Mark the node as having been checked and fix the accounting accordingly */
spin_lock(&c->erase_completion_lock);
jeb = &c->blocks[ref->flash_offset / c->sector_size];
len = ref_totlen(c, jeb, ref);
return 0;
}
jeb->used_size += len;
jeb->unchecked_size -= len;
c->used_size += len;
c->unchecked_size -= len;
/*
* Helper function for jffs2_get_inode_nodes().
* It is called every time an unknown node is found.
*
* Returns: 0 on succes;
* 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,
uint32_t read)
{
/* We don't mark unknown nodes as REF_UNCHECKED */
BUG_ON(ref_flags(ref) == REF_UNCHECKED);
un->nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(un->nodetype));
if (crc32(0, un, sizeof(struct jffs2_unknown_node) - 4) != je32_to_cpu(un->hdr_crc)) {
mark_ref_normal(ref);
spin_unlock(&c->erase_completion_lock);
}
node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype));
if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) {
/* Hmmm. This should have been caught at scan time. */
printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n",
ref_offset(ref));
printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n",
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_mark_node_obsolete(c, ref);
} else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) {
printk(KERN_WARNING "Warning! Node header CRC failed at %#08x. "
"But it must have been OK earlier.\n", ref_offset(ref));
D1(printk(KERN_DEBUG "Node was: { %#04x, %#04x, %#08x, %#08x }\n",
je16_to_cpu(un->magic), je16_to_cpu(un->nodetype),
je32_to_cpu(un->totlen), je32_to_cpu(un->hdr_crc)));
return 1;
} else {
switch(je16_to_cpu(un->nodetype) & JFFS2_COMPAT_MASK) {
case JFFS2_FEATURE_INCOMPAT:
printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
printk(KERN_NOTICE "Unknown INCOMPAT nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
/* EEP */
BUG();
break;
case JFFS2_FEATURE_ROCOMPAT:
printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
if (!(c->flags & JFFS2_SB_FLAG_RO))
BUG();
printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
BUG_ON(!(c->flags & JFFS2_SB_FLAG_RO));
break;
case JFFS2_FEATURE_RWCOMPAT_COPY:
printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
break;
case JFFS2_FEATURE_RWCOMPAT_DELETE:
printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref));
printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %#04X at %#08x\n",
je16_to_cpu(un->nodetype), ref_offset(ref));
return 1;
}
}
return 0;
}
/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
with this ino, returning the former in order of version */
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct rb_root *tnp, struct jffs2_full_dirent **fdp,
uint32_t *highest_version, uint32_t *latest_mctime,
uint32_t *mctime_ver)
{
struct jffs2_raw_node_ref *ref, *valid_ref;
struct rb_root ret_tn = RB_ROOT;
struct jffs2_full_dirent *ret_fd = NULL;
union jffs2_node_union node;
size_t retlen;
int err;
*mctime_ver = 0;
D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
spin_lock(&c->erase_completion_lock);
valid_ref = jffs2_first_valid_node(f->inocache->nodes);
if (!valid_ref && (f->inocache->ino != 1))
printk(KERN_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_ nodes may disappear at any time, if the block
they're in gets erased. So if we mark 'ref' obsolete while we're
not holding the lock, it can go away immediately. For that reason,
we find the next valid node first, before processing 'ref'.
*/
ref = valid_ref;
valid_ref = jffs2_first_valid_node(ref->next_in_ino);
spin_unlock(&c->erase_completion_lock);
cond_resched();
/* FIXME: point() */
err = jffs2_flash_read(c, (ref_offset(ref)),
min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)),
&retlen, (void *)&node);
if (err) {
printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref));
goto free_out;
}
switch (je16_to_cpu(node.u.nodetype)) {
case JFFS2_NODETYPE_DIRENT:
D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref)));
if (retlen < sizeof(node.d)) {
printk(KERN_WARNING "Warning! Short read dirent at %#08x\n", ref_offset(ref));
err = -EIO;
goto free_out;
}
err = read_direntry(c, ref, &node.d, retlen, &ret_fd, latest_mctime, mctime_ver);
if (err == 1) {
jffs2_mark_node_obsolete(c, ref);
break;
} else if (unlikely(err))
goto free_out;
if (je32_to_cpu(node.d.version) > *highest_version)
*highest_version = je32_to_cpu(node.d.version);
break;
case JFFS2_NODETYPE_INODE:
D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref)));
if (retlen < sizeof(node.i)) {
printk(KERN_WARNING "Warning! Short read dnode at %#08x\n", ref_offset(ref));
err = -EIO;
goto free_out;
}
err = read_dnode(c, ref, &node.i, retlen, &ret_tn, latest_mctime, mctime_ver);
if (err == 1) {
jffs2_mark_node_obsolete(c, ref);
break;
} else if (unlikely(err))
goto free_out;
if (je32_to_cpu(node.i.version) > *highest_version)
*highest_version = je32_to_cpu(node.i.version);
D1(printk(KERN_DEBUG "version %d, highest_version now %d\n",
je32_to_cpu(node.i.version), *highest_version));
break;
default:
/* Check we've managed to read at least the common node header */
if (retlen < sizeof(struct jffs2_unknown_node)) {
printk(KERN_WARNING "Warning! Short read unknown node at %#08x\n",
ref_offset(ref));
return -EIO;
}
err = read_unknown(c, ref, &node.u, retlen);
if (err == 1) {
jffs2_mark_node_obsolete(c, ref);
break;
} else if (unlikely(err))
goto free_out;
}
spin_lock(&c->erase_completion_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment