Beispiel #1
0
static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
{
	struct rb_node *this;
	struct jffs2_tmp_dnode_info *tn;

	this = list->rb_node;

	/* Now at bottom of tree */
	while (this) {
		if (this->rb_left)
			this = this->rb_left;
		else if (this->rb_right)
			this = this->rb_right;
		else {
			tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
			jffs2_free_full_dnode(tn->fn);
			jffs2_free_tmp_dnode_info(tn);

			this = this->rb_parent;
			if (!this)
				break;

			if (this->rb_left == &tn->rb)
				this->rb_left = NULL;
			else if (this->rb_right == &tn->rb)
				this->rb_right = NULL;
			else BUG();
		}
	}
	list->rb_node = NULL;
}
Beispiel #2
0
void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
{
	struct jffs2_tmp_dnode_info *next;

	while (tn) {
		next = tn;
		tn = tn->next;
		jffs2_free_full_dnode(next->fn);
		jffs2_free_tmp_dnode_info(next);
	}
}
Beispiel #3
0
static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
					struct jffs2_inode_info *f,
					struct jffs2_raw_inode *latest_node)
{
	struct jffs2_tmp_dnode_info *tn;
	struct rb_root tn_list;
	struct rb_node *rb, *repl_rb;
	struct jffs2_full_dirent *fd_list;
	struct jffs2_full_dnode *fn, *first_fn = NULL;
	uint32_t crc;
	uint32_t latest_mctime, mctime_ver;
	size_t retlen;
	int ret;

	dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);

	/* Grab all nodes relevant to this ino */
	ret = jffs2_get_inode_nodes(c, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver);

	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;
	}
	f->dents = fd_list;

	rb = rb_first(&tn_list);

	while (rb) {
		cond_resched();
		tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb);
		fn = tn->fn;
		ret = 1;
		dbg_readinode("consider node ver %u, phys offset "
			"%#08x(%d), range %u-%u.\n", tn->version,
			ref_offset(fn->raw), ref_flags(fn->raw),
			fn->ofs, fn->ofs + fn->size);

		if (fn->size) {
			ret = jffs2_add_older_frag_to_fragtree(c, f, tn);
			/* TODO: the error code isn't checked, check it */
			jffs2_dbg_fragtree_paranoia_check_nolock(f);
			BUG_ON(ret < 0);
			if (!first_fn && ret == 0)
				first_fn = fn;
		} else if (!first_fn) {
			first_fn = fn;
			f->metadata = fn;
			ret = 0; /* Prevent freeing the metadata update node */
		} else
			jffs2_mark_node_obsolete(c, fn->raw);

		BUG_ON(rb->rb_left);
		if (rb->rb_parent && rb->rb_parent->rb_left == rb) {
			/* We were then left-hand child of our parent. We need
			 * to move our own right-hand child into our place. */
			repl_rb = rb->rb_right;
			if (repl_rb)
				repl_rb->rb_parent = rb->rb_parent;
		} else
			repl_rb = NULL;

		rb = rb_next(rb);

		/* Remove the spent tn from the tree; don't bother rebalancing
		 * but put our right-hand child in our own place. */
		if (tn->rb.rb_parent) {
			if (tn->rb.rb_parent->rb_left == &tn->rb)
				tn->rb.rb_parent->rb_left = repl_rb;
			else if (tn->rb.rb_parent->rb_right == &tn->rb)
				tn->rb.rb_parent->rb_right = repl_rb;
			else BUG();
		} else if (tn->rb.rb_right)
			tn->rb.rb_right->rb_parent = NULL;

		jffs2_free_tmp_dnode_info(tn);
		if (ret) {
			dbg_readinode("delete dnode %u-%u.\n",
				fn->ofs, fn->ofs + fn->size);
			jffs2_free_full_dnode(fn);
		}
	}
	jffs2_dbg_fragtree_paranoia_check_nolock(f);

	BUG_ON(first_fn && ref_obsolete(first_fn->raw));

	fn = first_fn;
	if (unlikely(!first_fn)) {
		/* 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 (!fd_list) {
				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);
		return 0;
	}

	ret = jffs2_flash_read(c, ref_offset(fn->raw), 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. */
		up(&f->sem);
		jffs2_do_clear_inode(c, f);
		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(fn->raw));
		up(&f->sem);
		jffs2_do_clear_inode(c, f);
		return -EIO;
	}

	switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {
	case S_IFDIR:
		if (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(latest_mctime);
		}
		break;


	case S_IFREG:
		/* If it was a regular file, truncate it to the latest node's isize */
		jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));
		break;

	case S_IFLNK:
		/* Hack to work around broken isize in old symlink code.
		   Remove this when dwmw2 comes to his senses and stops
		   symlinks from being an entirely gratuitous special
		   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
			 * keep in RAM to facilitate quick follow symlink
			 * operation. */
			f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
			if (!f->target) {
				JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));
				up(&f->sem);
				jffs2_do_clear_inode(c, f);
				return -ENOMEM;
			}

			ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
						je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);

			if (ret  || retlen != je32_to_cpu(latest_node->csize)) {
				if (retlen != je32_to_cpu(latest_node->csize))
					ret = -EIO;
				kfree(f->target);
				f->target = NULL;
				up(&f->sem);
				jffs2_do_clear_inode(c, f);
				return -ret;
			}

			f->target[je32_to_cpu(latest_node->csize)] = '\0';
			dbg_readinode("symlink's target '%s' cached\n", f->target);
		}

		/* fall through... */

	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));
			up(&f->sem);
			jffs2_do_clear_inode(c, f);
			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));
			up(&f->sem);
			jffs2_do_clear_inode(c, f);
			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 */
			up(&f->sem);
			jffs2_do_clear_inode(c, f);
			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);

	return 0;
}
Beispiel #4
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, struct rb_root *tnp, int rdlen,
			     uint32_t *latest_mctime, uint32_t *mctime_ver)
{
	struct jffs2_tmp_dnode_info *tn;
	uint32_t len, csize;
	int ret = 1;

	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
	BUG_ON(ref_obsolete(ref));

	tn = jffs2_alloc_tmp_dnode_info();
	if (!tn) {
		JFFS2_ERROR("failed to allocate tn (%d bytes).\n", sizeof(*tn));
		return -ENOMEM;
	}

	tn->partial_crc = 0;
	csize = je32_to_cpu(rd->csize);

	/* If we've never checked the CRCs on this node, check them now */
	if (ref_flags(ref) == REF_UNCHECKED) {
		uint32_t crc;

		crc = crc32(0, rd, sizeof(*rd) - 8);
		if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
			JFFS2_NOTICE("header CRC failed on node at %#08x: read %#08x, calculated %#08x\n",
					ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
			goto free_out;
		}

		/* Sanity checks */
		if (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
		    unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
				JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));
				jffs2_dbg_dump_node(c, ref_offset(ref));
			goto free_out;
		}

		if (jffs2_is_writebuffered(c) && csize != 0) {
			/* At this point we are supposed to check the data CRC
			 * of our unchecked node. But thus far, we do not
			 * know whether the node is valid or obsolete. To
			 * figure this out, we need to walk all the nodes of
			 * the inode and build the inode fragtree. We don't
			 * want to spend time checking data of nodes which may
			 * later be found to be obsolete. So we put off the full
			 * data CRC checking until we have read all the inode
			 * nodes and have started building the fragtree.
			 *
			 * The fragtree is being built starting with nodes
			 * having the highest version number, so we'll be able
			 * to detect whether a node is valid (i.e., it is not
			 * overlapped by a node with higher version) or not.
			 * And we'll be able to check only those nodes, which
			 * are not obsolete.
			 *
			 * Of course, this optimization only makes sense in case
			 * of NAND flashes (or other flashes whith
			 * !jffs2_can_mark_obsolete()), since on NOR flashes
			 * nodes are marked obsolete physically.
			 *
			 * Since NAND flashes (or other flashes with
			 * jffs2_is_writebuffered(c)) are anyway read by
			 * fractions of c->wbuf_pagesize, and we have just read
			 * the node header, it is likely that the starting part
			 * of the node data is also read when we read the
			 * header. So we don't mind to check the CRC of the
			 * starting part of the data of the node now, and check
			 * the second part later (in jffs2_check_node_data()).
			 * Of course, we will not need to re-read and re-check
			 * the NAND page which we have just read. This is why we
			 * read the whole NAND page at jffs2_get_inode_nodes(),
			 * while we needed only the node header.
			 */
			unsigned char *buf;

			/* 'buf' will point to the start of data */
			buf = (unsigned char *)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);

			dbg_readinode("Calculates CRC (%#08x) for %d bytes, csize %d\n", tn->partial_crc, len, csize);

			/* 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));
				goto free_out;
			}

		} else if (csize == 0) {
			/*
			 * We checked the header CRC. If the node has no data, adjust
			 * the space accounting now. For other nodes this will be done
			 * later either when the node is marked obsolete or when its
			 * data is checked.
			 */
			struct jffs2_eraseblock *jeb;

			dbg_readinode("the node has no data.\n");
			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;
			c->unchecked_size -= len;
			ref->flash_offset = ref_offset(ref) | REF_NORMAL;
			spin_unlock(&c->erase_completion_lock);
		}
	}

	tn->fn = jffs2_alloc_full_dnode();
	if (!tn->fn) {
		JFFS2_ERROR("alloc fn failed\n");
		ret = -ENOMEM;
		goto free_out;
	}

	tn->version = je32_to_cpu(rd->version);
	tn->fn->ofs = je32_to_cpu(rd->offset);
	tn->data_crc = je32_to_cpu(rd->data_crc);
	tn->csize = csize;
	tn->fn->raw = ref;

	/* 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);

	dbg_readinode("dnode @%08x: ver %u, offset %#04x, dsize %#04x, csize %#04x\n",
		  ref_offset(ref), je32_to_cpu(rd->version), je32_to_cpu(rd->offset), je32_to_cpu(rd->dsize), csize);

	jffs2_add_tn_to_tree(tn, tnp);

	return 0;

free_out:
	jffs2_free_tmp_dnode_info(tn);
	return ret;
}
Beispiel #5
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;
	
	/* Obsoleted. This cannot happen, surely? dwmw2 20020308 */
	BUG_ON(ref_obsolete(ref));

	/* If we've never checked the CRCs on this node, check them now */
	if (ref_flags(ref) == REF_UNCHECKED) {
		uint32_t crc, len;

		crc = crc32(0, rd, sizeof(*rd) - 8);
		if (unlikely(crc != je32_to_cpu(rd->node_crc))) {
			JFFS2_NOTICE("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 (unlikely(je32_to_cpu(rd->offset) > je32_to_cpu(rd->isize)) ||
		    unlikely(PAD(je32_to_cpu(rd->csize) + sizeof(*rd)) != PAD(je32_to_cpu(rd->totlen)))) {
				JFFS2_WARNING("inode node header CRC is corrupted at %#08x\n", ref_offset(ref));
				jffs2_dbg_dump_node(c, ref_offset(ref));
			return 1;
		}

		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(*rd), je32_to_cpu(rd->csize),
						     &read, &buf);
				if (unlikely(read < je32_to_cpu(rd->csize)) && likely(!err)) {
					JFFS2_ERROR("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)){
					JFFS2_ERROR("MTD point failed %d\n", err);
				} else
					pointed = 1; /* succefully pointed to device */
			}
#endif					
			if(!pointed){
				buf = kmalloc(je32_to_cpu(rd->csize), GFP_KERNEL);
				if (!buf)
					return -ENOMEM;
				
				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(rd->csize));
			if(!pointed)
				kfree(buf);
#ifndef __ECOS
			else
				c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(*rd), je32_to_cpu(rd->csize));
#endif

			if (crc != je32_to_cpu(rd->data_crc)) {
				JFFS2_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 */
		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;
		c->unchecked_size -= len;

		/* If node covers at least a whole page, or if it starts at the 
		   beginning of a page and runs to the end of the file, or if 
		   it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. 

		   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(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)))) {
			JFFS2_DBG_READINODE("marking node at %#08x REF_PRISTINE\n", ref_offset(ref));
			ref->flash_offset = ref_offset(ref) | REF_PRISTINE;
		} else {
			JFFS2_DBG_READINODE("marking node at %#08x REF_NORMAL\n", ref_offset(ref));
			ref->flash_offset = ref_offset(ref) | REF_NORMAL;
		}
		spin_unlock(&c->erase_completion_lock);
	}

	tn = jffs2_alloc_tmp_dnode_info();
	if (!tn) {
		JFFS2_ERROR("alloc tn failed\n");
		return -ENOMEM;
	}

	tn->fn = jffs2_alloc_full_dnode();
	if (!tn->fn) {
		JFFS2_ERROR("alloc fn failed\n");
		jffs2_free_tmp_dnode_info(tn);
		return -ENOMEM;
	}
	
	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 (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(rd->dsize);

	JFFS2_DBG_READINODE("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));
	
	jffs2_add_tn_to_tree(tn, tnp);

	return 0;
}
Beispiel #6
0
/* Build final, normal fragtree from tn tree. It doesn't matter which order
   we add nodes to the real fragtree, as long as they don't overlap. And
   having thrown away the majority of overlapped nodes as we went, there
   really shouldn't be many sets of nodes which do overlap. If we start at
   the end, we can use the overlap markers -- we can just eat nodes which
   aren't overlapped, and when we encounter nodes which _do_ overlap we
   sort them all into a temporary tree in version order before replaying them. */
static int 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);

		eat_last(&rii->tn_root, &last->rb);
		ver_insert(&ver_root, last);

		if (unlikely(last->overlapped)) {
			if (pen)
				continue;
			/*
			 * We killed a node which set the overlapped
			 * flags during the scan. Fix it up.
			 */
			last->overlapped = 0;
		}

		/* Now we have a bunch of nodes in reverse version
		   order, in the tree at ver_root. Most of the time,
		   there'll actually be only one node in the '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, because this one is only
					   counting _valid_ nodes which could give the
					   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;
		}
	}
	return 0;
}
Beispiel #7
0
static void jffs2_kill_tn(struct jffs2_sb_info *c, struct jffs2_tmp_dnode_info *tn)
{
	jffs2_mark_node_obsolete(c, tn->fn->raw);
	jffs2_free_full_dnode(tn->fn);
	jffs2_free_tmp_dnode_info(tn);
}
Beispiel #8
0
static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
					struct jffs2_inode_info *f,
					struct jffs2_raw_inode *latest_node)
{
	struct jffs2_readinode_info rii;
	uint32_t crc, new_size;
	size_t retlen;
	int ret;

	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 (rii.mdata_tn) {
		if (rii.mdata_tn->fn->raw == rii.latest_ref) {
			f->metadata = rii.mdata_tn->fn;
			jffs2_free_tmp_dnode_info(rii.mdata_tn);
		} else {
			jffs2_kill_tn(c, rii.mdata_tn);
		}
		rii.mdata_tn = NULL;
	}

	f->dents = rii.fds;

	jffs2_dbg_fragtree_paranoia_check_nolock(f);

	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);
		return 0;
	}

	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. */
		mutex_unlock(&f->sem);
		jffs2_do_clear_inode(c, f);
		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));
		mutex_unlock(&f->sem);
		jffs2_do_clear_inode(c, f);
		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.
		   Remove this when dwmw2 comes to his senses and stops
		   symlinks from being an entirely gratuitous special
		   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
			 * keep in RAM to facilitate quick follow symlink
			 * operation. */
			f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
			if (!f->target) {
				JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));
				mutex_unlock(&f->sem);
				jffs2_do_clear_inode(c, f);
				return -ENOMEM;
			}

			ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),
						je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);

			if (ret  || retlen != je32_to_cpu(latest_node->csize)) {
				if (retlen != je32_to_cpu(latest_node->csize))
					ret = -EIO;
				kfree(f->target);
				f->target = NULL;
				mutex_unlock(&f->sem);
				jffs2_do_clear_inode(c, f);
				return ret;
			}

			f->target[je32_to_cpu(latest_node->csize)] = '\0';
			dbg_readinode("symlink's target '%s' cached\n", f->target);
		}

		/* fall through... */

	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));
			mutex_unlock(&f->sem);
			jffs2_do_clear_inode(c, f);
			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));
			mutex_unlock(&f->sem);
			jffs2_do_clear_inode(c, f);
			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 */
			mutex_unlock(&f->sem);
			jffs2_do_clear_inode(c, f);
			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);

	return 0;
}
Beispiel #9
0
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs)
{
	struct jffs2_raw_node_ref *raw;
	struct jffs2_full_dnode *fn;
	struct jffs2_tmp_dnode_info *tn, **tn_list;
	struct jffs2_inode_cache *ic;
	struct jffs2_raw_inode ri;
	__u32 crc;
	__u16 oldnodetype;
	int ret;
	ssize_t retlen;

	D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs));

	ret = c->mtd->read(c->mtd, *ofs, sizeof(ri), &retlen, (char *)&ri);
	if (ret) {
		printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret);
		return ret;
	}
	if (retlen != sizeof(ri)) {
		printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
		       retlen, *ofs, sizeof(ri));
		return -EIO;
	}

	/* We sort of assume that the node was accurate when it was 
	   first written to the medium :) */
	oldnodetype = ri.nodetype;
	ri.nodetype |= JFFS2_NODE_ACCURATE;
	crc = crc32(0, &ri, sizeof(ri)-8);
	ri.nodetype = oldnodetype;

	if(crc != ri.node_crc) {
		printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       *ofs, ri.node_crc, crc);
		/* FIXME: Why do we believe totlen? */
		DIRTY_SPACE(4);
		*ofs += 4;
		return 0;
	}
	/* There was a bug where we wrote hole nodes out with csize/dsize
	   swapped. Deal with it */
	if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) {
		ri.dsize = ri.csize;
		ri.csize = 0;
	}

	if (ri.csize) {
		/* Check data CRC too */
		unsigned char *dbuf;
		__u32 crc;

		dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL);
		if (!dbuf) {
			printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n");
			return -ENOMEM;
		}
		ret = c->mtd->read(c->mtd, *ofs+sizeof(ri), ri.csize, &retlen, dbuf);
		if (ret) {
			printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret);
			kfree(dbuf);
			return ret;
		}
		if (retlen != ri.csize) {
			printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
			       retlen, *ofs+ sizeof(ri), ri.csize);
			kfree(dbuf);
			return -EIO;
		}
		crc = crc32(0, dbuf, ri.csize);
		kfree(dbuf);
		if (crc != ri.data_crc) {
			printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
			       *ofs, ri.data_crc, crc);
			DIRTY_SPACE(PAD(ri.totlen));
			*ofs += PAD(ri.totlen);
			return 0;
		}
	}

	/* Wheee. It worked */
	raw = jffs2_alloc_raw_node_ref();
	if (!raw) {
		printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n");
		return -ENOMEM;
	}
	tn = jffs2_alloc_tmp_dnode_info();
	if (!tn) {
		jffs2_free_raw_node_ref(raw);
		return -ENOMEM;
	}
	fn = jffs2_alloc_full_dnode();
	if (!fn) {
		jffs2_free_tmp_dnode_info(tn);
		jffs2_free_raw_node_ref(raw);
		return -ENOMEM;
	}
	ic = jffs2_scan_make_ino_cache(c, ri.ino);
	if (!ic) {
		jffs2_free_full_dnode(fn);
		jffs2_free_tmp_dnode_info(tn);
		jffs2_free_raw_node_ref(raw);
		return -ENOMEM;
	}

	/* Build the data structures and file them for later */
	raw->flash_offset = *ofs;
	raw->totlen = PAD(ri.totlen);
	raw->next_phys = NULL;
	raw->next_in_ino = ic->nodes;
	ic->nodes = raw;
	if (!jeb->first_node)
		jeb->first_node = raw;
	if (jeb->last_node)
		jeb->last_node->next_phys = raw;
	jeb->last_node = raw;

	D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", 
		  ri.ino, ri.version, ri.offset, ri.offset+ri.dsize));

	pseudo_random += ri.version;

	for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) {
		if ((*tn_list)->version < ri.version)
			continue;
		if ((*tn_list)->version > ri.version) 
			break;
		/* Wheee. We've found another instance of the same version number.
		   We should obsolete one of them. 
		*/
		D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n", ri.version, ic->ino, (*tn_list)->fn->raw->flash_offset &~3));
		if (!jeb->used_size) {
			D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n", 
				  jeb->offset, raw->flash_offset & ~3));
			ri.nodetype &= ~JFFS2_NODE_ACCURATE;
			/* Perhaps we could also mark it as such on the medium. Maybe later */
		}
		break;
	}

	if (ri.nodetype & JFFS2_NODE_ACCURATE) {
		memset(fn,0,sizeof(*fn));

		fn->ofs = ri.offset;
		fn->size = ri.dsize;
		fn->frags = 0;
		fn->raw = raw;

		tn->next = NULL;
		tn->fn = fn;
		tn->version = ri.version;

		USED_SPACE(PAD(ri.totlen));
		jffs2_add_tn_to_list(tn, &ic->scan->tmpnodes);
		/* Make sure the one we just added is the _last_ in the list
		   with this version number, so the older ones get obsoleted */
		while (tn->next && tn->next->version == tn->version) {

			D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n",
				  fn->raw->flash_offset&~3, tn->next->fn->raw->flash_offset &~3, ri.version));

			if(tn->fn != fn)
				BUG();
			tn->fn = tn->next->fn;
			tn->next->fn = fn;
			tn = tn->next;
		}
	} else {
		jffs2_free_full_dnode(fn);
		jffs2_free_tmp_dnode_info(tn);
		raw->flash_offset |= 1;
		DIRTY_SPACE(PAD(ri.totlen));
	}		
	*ofs += PAD(ri.totlen);
	return 0;
}