Loading fs/jffs2/nodelist.c +336 −261 Original line number Diff line number Diff line Loading @@ -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 $ * */ Loading Loading @@ -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; jffs2_add_fd_to_list(c, fd, fdp); return 0; } 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)); if (ref_obsolete(ref)) { /* * 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; /* 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)) { 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; Loading @@ -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); Loading @@ -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); Loading Loading
fs/jffs2/nodelist.c +336 −261 Original line number Diff line number Diff line Loading @@ -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 $ * */ Loading Loading @@ -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; jffs2_add_fd_to_list(c, fd, fdp); return 0; } 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)); if (ref_obsolete(ref)) { /* * 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; /* 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)) { 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; Loading @@ -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); Loading @@ -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); Loading