Beispiel #1
0
/* Scan plan:
 - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go
 - Scan directory tree from top down, setting nlink in inocaches
 - Scan inocaches for inodes with nlink==0
*/
static int jffs2_build_filesystem(struct jffs2_sb_info *c)
{
	int ret;
	int i;
	struct jffs2_inode_cache *ic;
	struct jffs2_full_dirent *fd;
	struct jffs2_full_dirent *dead_fds = NULL;

	dbg_fsbuild("build FS data structures\n");

	/* First, scan the medium and build all the inode caches with
	   lists of physical nodes */

	c->flags |= JFFS2_SB_FLAG_SCANNING;
	ret = jffs2_scan_medium(c);
	c->flags &= ~JFFS2_SB_FLAG_SCANNING;
	if (ret)
		goto exit;

	dbg_fsbuild("scanned flash completely\n");
	jffs2_dbg_dump_block_lists_nolock(c);

	if (c->flags & (1 << 7)) {
		printk("%s(): unlocking the mtd device... ", __func__);
		if (c->mtd->unlock)
			c->mtd->unlock(c->mtd, 0, c->mtd->size);
		printk("done.\n");

		printk("%s(): erasing all blocks after the end marker... ", __func__);
		jffs2_erase_pending_blocks(c, -1);
		printk("done.\n");
	}

	dbg_fsbuild("pass 1 starting\n");
	c->flags |= JFFS2_SB_FLAG_BUILDING;
	/* Now scan the directory tree, increasing nlink according to every dirent found. */
	for_each_inode(i, c, ic) {
		if (ic->scan_dents) {
			jffs2_build_inode_pass1(c, ic);
			cond_resched();
		}
	}

	dbg_fsbuild("pass 1 complete\n");

	/* Next, scan for inodes with nlink == 0 and remove them. If
	   they were directories, then decrement the nlink of their
	   children too, and repeat the scan. As that's going to be
	   a fairly uncommon occurrence, it's not so evil to do it this
	   way. Recursion bad. */
	dbg_fsbuild("pass 2 starting\n");

	for_each_inode(i, c, ic) {
		if (ic->pino_nlink)
			continue;

		jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
		cond_resched();
	}

	dbg_fsbuild("pass 2a starting\n");

	while (dead_fds) {
		fd = dead_fds;
		dead_fds = fd->next;

		ic = jffs2_get_ino_cache(c, fd->ino);

		if (ic)
			jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
		jffs2_free_full_dirent(fd);
	}

	dbg_fsbuild("pass 2a complete\n");
	dbg_fsbuild("freeing temporary data structures\n");

	/* Finally, we can scan again and free the dirent structs */
	for_each_inode(i, c, ic) {
		while(ic->scan_dents) {
			fd = ic->scan_dents;
			ic->scan_dents = fd->next;
			jffs2_free_full_dirent(fd);
		}
		ic->scan_dents = NULL;
		cond_resched();
	}
	jffs2_build_xattr_subsystem(c);
	c->flags &= ~JFFS2_SB_FLAG_BUILDING;

	dbg_fsbuild("FS build complete\n");

	/* Rotate the lists by some number to ensure wear levelling */
	jffs2_rotate_lists(c);

	ret = 0;

exit:
	if (ret) {
		for_each_inode(i, c, ic) {
			while(ic->scan_dents) {
				fd = ic->scan_dents;
				ic->scan_dents = fd->next;
				jffs2_free_full_dirent(fd);
			}
		}
		jffs2_clear_xattr_subsystem(c);
	}

	return ret;
}
Beispiel #2
0
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				  struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
{
	struct jffs2_full_dirent *fd;
	struct jffs2_inode_cache *ic;
	uint32_t checkedlen;
	uint32_t crc;
	int err;

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

	/* We don't get here unless the node is still valid, so we don't have to
	   mask in the ACCURATE bit any more. */
	crc = crc32(0, rd, sizeof(*rd)-8);

	if (crc != je32_to_cpu(rd->node_crc)) {
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       ofs, je32_to_cpu(rd->node_crc), crc);
		/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
		if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
			return err;
		return 0;
	}

	pseudo_random += je32_to_cpu(rd->version);

	/* Should never happen. Did. (OLPC trac #4184)*/
	checkedlen = strnlen(rd->name, rd->nsize);
	if (checkedlen < rd->nsize) {
		printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
		       ofs, checkedlen);
	}
	fd = jffs2_alloc_full_dirent(checkedlen+1);
	if (!fd) {
		return -ENOMEM;
	}
	memcpy(&fd->name, rd->name, checkedlen);
	fd->name[checkedlen] = 0;

	crc = crc32(0, fd->name, rd->nsize);
	if (crc != je32_to_cpu(rd->name_crc)) {
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       ofs, je32_to_cpu(rd->name_crc), crc);
		D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
		jffs2_free_full_dirent(fd);
		/* FIXME: Why do we believe totlen? */
		/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
		if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
			return err;
		return 0;
	}
	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
	if (!ic) {
		jffs2_free_full_dirent(fd);
		return -ENOMEM;
	}

	fd->raw = jffs2_link_node_ref(c, jeb, ofs | dirent_node_state(rd),
				      PAD(je32_to_cpu(rd->totlen)), ic);

	fd->next = NULL;
	fd->version = je32_to_cpu(rd->version);
	fd->ino = je32_to_cpu(rd->ino);
	fd->nhash = full_name_hash(fd->name, checkedlen);
	fd->type = rd->type;
	jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

	if (jffs2_sum_active()) {
		jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset);
	}

	return 0;
}
Beispiel #3
0
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 
				  struct jffs2_raw_dirent *rd, uint32_t ofs)
{
	struct jffs2_raw_node_ref *raw;
	struct jffs2_full_dirent *fd;
	struct jffs2_inode_cache *ic;
	uint32_t crc;

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

	/* We don't get here unless the node is still valid, so we don't have to
	   mask in the ACCURATE bit any more. */
	crc = crc32(0, rd, sizeof(*rd)-8);

	if (crc != je32_to_cpu(rd->node_crc)) {
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       ofs, je32_to_cpu(rd->node_crc), crc);
		/* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */
		DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
		return 0;
	}

	pseudo_random += je32_to_cpu(rd->version);

	fd = jffs2_alloc_full_dirent(rd->nsize+1);
	if (!fd) {
		return -ENOMEM;
	}
	memcpy(&fd->name, rd->name, rd->nsize);
	fd->name[rd->nsize] = 0;

	crc = crc32(0, fd->name, rd->nsize);
	if (crc != je32_to_cpu(rd->name_crc)) {
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       ofs, je32_to_cpu(rd->name_crc), crc);	
		D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino)));
		jffs2_free_full_dirent(fd);
		/* FIXME: Why do we believe totlen? */
		/* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */
		DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen)));
		return 0;
	}
	raw = jffs2_alloc_raw_node_ref();
	if (!raw) {
		jffs2_free_full_dirent(fd);
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
		return -ENOMEM;
	}
	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
	if (!ic) {
		jffs2_free_full_dirent(fd);
		jffs2_free_raw_node_ref(raw);
		return -ENOMEM;
	}
	
	raw->totlen = PAD(je32_to_cpu(rd->totlen));
	raw->flash_offset = ofs | REF_PRISTINE;
	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;

	fd->raw = raw;
	fd->next = NULL;
	fd->version = je32_to_cpu(rd->version);
	fd->ino = je32_to_cpu(rd->ino);
	fd->nhash = full_name_hash(fd->name, rd->nsize);
	fd->type = rd->type;
	USED_SPACE(PAD(je32_to_cpu(rd->totlen)));
	jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

	return 0;
}
Beispiel #4
0
static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c,
					struct jffs2_inode_cache *ic,
					struct jffs2_full_dirent **dead_fds)
{
	struct jffs2_raw_node_ref *raw;
	struct jffs2_full_dirent *fd;

	dbg_fsbuild("removing ino #%u with nlink == zero.\n", ic->ino);

	raw = ic->nodes;
	while (raw != (void *)ic) {
		struct jffs2_raw_node_ref *next = raw->next_in_ino;
		dbg_fsbuild("obsoleting node at 0x%08x\n", ref_offset(raw));
		jffs2_mark_node_obsolete(c, raw);
		raw = next;
	}

	if (ic->scan_dents) {
		int whinged = 0;
		dbg_fsbuild("inode #%u was a directory which may have children...\n", ic->ino);

		while(ic->scan_dents) {
			struct jffs2_inode_cache *child_ic;

			fd = ic->scan_dents;
			ic->scan_dents = fd->next;

			if (!fd->ino) {
				/* It's a deletion dirent. Ignore it */
				dbg_fsbuild("child \"%s\" is a deletion dirent, skipping...\n", fd->name);
				jffs2_free_full_dirent(fd);
				continue;
			}
			if (!whinged)
				whinged = 1;

			dbg_fsbuild("removing child \"%s\", ino #%u\n", fd->name, fd->ino);

			child_ic = jffs2_get_ino_cache(c, fd->ino);
			if (!child_ic) {
				dbg_fsbuild("cannot remove child \"%s\", ino #%u, because it doesn't exist\n",
						fd->name, fd->ino);
				jffs2_free_full_dirent(fd);
				continue;
			}

			/* Reduce nlink of the child. If it's now zero, stick it on the
			   dead_fds list to be cleaned up later. Else just free the fd */

			if (fd->type == DT_DIR)
				child_ic->pino_nlink = 0;
			else
				child_ic->pino_nlink--;

			if (!child_ic->pino_nlink) {
				dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
					  fd->ino, fd->name);
				fd->next = *dead_fds;
				*dead_fds = fd;
			} else {
				dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
					  fd->ino, fd->name, child_ic->pino_nlink);
				jffs2_free_full_dirent(fd);
			}
		}
	}

	/*
	   We don't delete the inocache from the hash list and free it yet.
	   The erase code will do that, when all the nodes are completely gone.
	*/
}
Beispiel #5
0
/*
 * 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, size_t read, struct jffs2_full_dirent **fdp,
				uint32_t *latest_mctime, uint32_t *mctime_ver)
{
	struct jffs2_full_dirent *fd;
	uint32_t crc;

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

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

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

		/* Sanity check */
		if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
			JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
				    ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
			return 1;
		}

		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_PRISTINE;
		spin_unlock(&c->erase_completion_lock);
	}

	fd = jffs2_alloc_full_dirent(rd->nsize + 1);
	if (unlikely(!fd))
		return -ENOMEM;

	fd->raw = ref;
	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 && je32_to_cpu(rd->mctime)) {
		*mctime_ver = fd->version;
		*latest_mctime = je32_to_cpu(rd->mctime);
	}

	/*
	 * Copy as much of the name as possible from the raw
	 * dirent we've already read from the flash.
	 */
	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 (rd->nsize + sizeof(*rd) > read) {
		/* FIXME: point() */
		int err;
		int already = read - sizeof(*rd);

		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 (unlikely(err)) {
			JFFS2_ERROR("read remainder of name: error %d\n", err);
			jffs2_free_full_dirent(fd);
			return -EIO;
		}
	}

	fd->nhash = full_name_hash(fd->name, rd->nsize);
	fd->next = NULL;
	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
	 */
	jffs2_add_fd_to_list(c, fd, fdp);

	return 0;
}
Beispiel #6
0
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs)
{
	struct jffs2_raw_node_ref *raw;
	struct jffs2_full_dirent *fd;
	struct jffs2_inode_cache *ic;
	struct jffs2_raw_dirent rd;
	__u16 oldnodetype;
	int ret;
	__u32 crc;
	ssize_t retlen;

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

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

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

	if (crc != rd.node_crc) {
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       *ofs, rd.node_crc, crc);
		/* FIXME: Why do we believe totlen? */
		DIRTY_SPACE(4);
		*ofs += 4;
		return 0;
	}

	pseudo_random += rd.version;

	fd = jffs2_alloc_full_dirent(rd.nsize+1);
	if (!fd) {
		return -ENOMEM;
}
	ret = c->mtd->read(c->mtd, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]);
	if (ret) {
		jffs2_free_full_dirent(fd);
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", 
		       *ofs + sizeof(rd), ret);
		return ret;
	}
	if (retlen != rd.nsize) {
		jffs2_free_full_dirent(fd);
		printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", 
		       retlen, *ofs + sizeof(rd), rd.nsize);
		return -EIO;
	}
	crc = crc32(0, fd->name, rd.nsize);
	if (crc != rd.name_crc) {
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
		       *ofs, rd.name_crc, crc);	
		fd->name[rd.nsize]=0;
		D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino));
		jffs2_free_full_dirent(fd);
		/* FIXME: Why do we believe totlen? */
		DIRTY_SPACE(PAD(rd.totlen));
		*ofs += PAD(rd.totlen);
		return 0;
	}
	raw = jffs2_alloc_raw_node_ref();
	if (!raw) {
		jffs2_free_full_dirent(fd);
		printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n");
		return -ENOMEM;
	}
	ic = jffs2_scan_make_ino_cache(c, rd.pino);
	if (!ic) {
		jffs2_free_full_dirent(fd);
		jffs2_free_raw_node_ref(raw);
		return -ENOMEM;
	}
	
	raw->totlen = PAD(rd.totlen);
	raw->flash_offset = *ofs;
	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;

	if (rd.nodetype & JFFS2_NODE_ACCURATE) {
		fd->raw = raw;
		fd->next = NULL;
		fd->version = rd.version;
		fd->ino = rd.ino;
		fd->name[rd.nsize]=0;
		fd->nhash = full_name_hash(fd->name, rd.nsize);
		fd->type = rd.type;

		USED_SPACE(PAD(rd.totlen));
		jffs2_add_fd_to_list(c, fd, &ic->scan->dents);
	} else {
		raw->flash_offset |= 1;
		jffs2_free_full_dirent(fd);

		DIRTY_SPACE(PAD(rd.totlen));
	} 
	*ofs += PAD(rd.totlen);
	return 0;
}
Beispiel #7
0
static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename)
{
	struct jffs2_inode_info *dir_f, *f;
	struct jffs2_sb_info *c;
	struct jffs2_raw_dirent *rd;
	struct jffs2_full_dirent *fd;
	__u32 alloclen, phys_ofs;
	int ret;

	c = JFFS2_SB_INFO(dir_i->i_sb);

	rd = jffs2_alloc_raw_dirent();
	if (!rd)
		return -ENOMEM;

	ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION);
	if (ret) {
		jffs2_free_raw_dirent(rd);
		return ret;
	}

	dir_f = JFFS2_INODE_INFO(dir_i);
	down(&dir_f->sem);

	/* Build a deletion node */
	rd->magic = JFFS2_MAGIC_BITMASK;
	rd->nodetype = JFFS2_NODETYPE_DIRENT;
	rd->totlen = sizeof(*rd) + dentry->d_name.len;
	rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4);

	rd->pino = dir_i->i_ino;
	rd->version = ++dir_f->highest_version;
	rd->ino = 0;
	rd->mctime = CURRENT_TIME;
	rd->nsize = dentry->d_name.len;
	rd->type = DT_UNKNOWN;
	rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
	rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len);

	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL);
	
	jffs2_complete_reservation(c);
	jffs2_free_raw_dirent(rd);

	if (IS_ERR(fd)) {
		up(&dir_f->sem);
		return PTR_ERR(fd);
	}

	/* File it. This will mark the old one obsolete. */
	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
	up(&dir_f->sem);
	
	if (!rename) {
		f = JFFS2_INODE_INFO(dentry->d_inode);
		down(&f->sem);

		while (f->dents) {
			/* There can be only deleted ones */
			fd = f->dents;
			
			f->dents = fd->next;
			
			if (fd->ino) {
				printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
				       f->inocache->ino, fd->name, fd->ino);
			} else {
				D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino));
			}
			jffs2_mark_node_obsolete(c, fd->raw);
			jffs2_free_full_dirent(fd);
		}
		/* Don't oops on unlinking a bad inode */
		if (f->inocache)
			f->inocache->nlink--;
		dentry->d_inode->i_nlink--;
		up(&f->sem);
	}

	return 0;
}
static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				  struct jffs2_raw_dirent *rd, uint32_t ofs, struct jffs2_summary *s)
{
	struct jffs2_full_dirent *fd;
	struct jffs2_inode_cache *ic;
	uint32_t checkedlen;
	uint32_t crc;
	int err;

	jffs2_dbg(1, "%s(): Node at 0x%08x\n", __func__, ofs);

	crc = crc32(0, rd, sizeof(*rd)-8);

	if (crc != je32_to_cpu(rd->node_crc)) {
		pr_notice("%s(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
			  __func__, ofs, je32_to_cpu(rd->node_crc), crc);
		
		if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
			return err;
		return 0;
	}

	pseudo_random += je32_to_cpu(rd->version);

	
	checkedlen = strnlen(rd->name, rd->nsize);
	if (checkedlen < rd->nsize) {
		pr_err("Dirent at %08x has zeroes in name. Truncating to %d chars\n",
		       ofs, checkedlen);
	}
	fd = jffs2_alloc_full_dirent(checkedlen+1);
	if (!fd) {
		return -ENOMEM;
	}
	memcpy(&fd->name, rd->name, checkedlen);
	fd->name[checkedlen] = 0;

	crc = crc32(0, fd->name, rd->nsize);
	if (crc != je32_to_cpu(rd->name_crc)) {
		pr_notice("%s(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",
			  __func__, ofs, je32_to_cpu(rd->name_crc), crc);
		jffs2_dbg(1, "Name for which CRC failed is (now) '%s', ino #%d\n",
			  fd->name, je32_to_cpu(rd->ino));
		jffs2_free_full_dirent(fd);
		
		
		if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(rd->totlen)))))
			return err;
		return 0;
	}
	ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino));
	if (!ic) {
		jffs2_free_full_dirent(fd);
		return -ENOMEM;
	}

	fd->raw = jffs2_link_node_ref(c, jeb, ofs | dirent_node_state(rd),
				      PAD(je32_to_cpu(rd->totlen)), ic);

	fd->next = NULL;
	fd->version = je32_to_cpu(rd->version);
	fd->ino = je32_to_cpu(rd->ino);
	fd->nhash = full_name_hash(fd->name, checkedlen);
	fd->type = rd->type;
	jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

	if (jffs2_sum_active()) {
		jffs2_sum_add_dirent_mem(s, rd, ofs - jeb->offset);
	}

	return 0;
}
Beispiel #9
0
static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				struct jffs2_raw_summary *summary, uint32_t *pseudo_random)
{
	struct jffs2_raw_node_ref *raw;
	struct jffs2_inode_cache *ic;
	struct jffs2_full_dirent *fd;
	void *sp;
	int i, ino;

	sp = summary->sum;

	for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
		dbg_summary("processing summary index %d\n", i);

		switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
			case JFFS2_NODETYPE_INODE: {
				struct jffs2_sum_inode_flash *spi;
				spi = sp;

				ino = je32_to_cpu(spi->inode);

				dbg_summary("Inode at 0x%08x\n",
							jeb->offset + je32_to_cpu(spi->offset));

				raw = jffs2_alloc_raw_node_ref();
				if (!raw) {
					JFFS2_NOTICE("allocation of node reference failed\n");
					kfree(summary);
					return -ENOMEM;
				}

				ic = jffs2_scan_make_ino_cache(c, ino);
				if (!ic) {
					JFFS2_NOTICE("scan_make_ino_cache failed\n");
					jffs2_free_raw_node_ref(raw);
					kfree(summary);
					return -ENOMEM;
				}

				raw->flash_offset = (jeb->offset + je32_to_cpu(spi->offset)) | REF_UNCHECKED;
				raw->__totlen = PAD(je32_to_cpu(spi->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;
				*pseudo_random += je32_to_cpu(spi->version);

				UNCHECKED_SPACE(PAD(je32_to_cpu(spi->totlen)));

				sp += JFFS2_SUMMARY_INODE_SIZE;

				break;
			}

			case JFFS2_NODETYPE_DIRENT: {
				struct jffs2_sum_dirent_flash *spd;
				spd = sp;

				dbg_summary("Dirent at 0x%08x\n",
							jeb->offset + je32_to_cpu(spd->offset));

				fd = jffs2_alloc_full_dirent(spd->nsize+1);
				if (!fd) {
					kfree(summary);
					return -ENOMEM;
				}

				memcpy(&fd->name, spd->name, spd->nsize);
				fd->name[spd->nsize] = 0;

				raw = jffs2_alloc_raw_node_ref();
				if (!raw) {
					jffs2_free_full_dirent(fd);
					JFFS2_NOTICE("allocation of node reference failed\n");
					kfree(summary);
					return -ENOMEM;
				}

				ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
				if (!ic) {
					jffs2_free_full_dirent(fd);
					jffs2_free_raw_node_ref(raw);
					kfree(summary);
					return -ENOMEM;
				}

				raw->__totlen = PAD(je32_to_cpu(spd->totlen));
				raw->flash_offset = (jeb->offset + je32_to_cpu(spd->offset)) | REF_PRISTINE;
				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;

				fd->raw = raw;
				fd->next = NULL;
				fd->version = je32_to_cpu(spd->version);
				fd->ino = je32_to_cpu(spd->ino);
				fd->nhash = full_name_hash(fd->name, spd->nsize);
				fd->type = spd->type;
				USED_SPACE(PAD(je32_to_cpu(spd->totlen)));
				jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

				*pseudo_random += je32_to_cpu(spd->version);

				sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);

				break;
			}

			default : {
				JFFS2_WARNING("Unsupported node type found in summary! Exiting...");
				kfree(summary);
				return -EIO;
			}
		}
	}

	kfree(summary);
	return 0;
}
Beispiel #10
0
static int jffs2_sum_process_sum_data(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				struct jffs2_raw_summary *summary, uint32_t *pseudo_random)
{
	struct jffs2_inode_cache *ic;
	struct jffs2_full_dirent *fd;
	void *sp;
	int i, ino;
	int err;

	sp = summary->sum;

	for (i=0; i<je32_to_cpu(summary->sum_num); i++) {
		dbg_summary("processing summary index %d\n", i);

		cond_resched();

		/* Make sure there's a spare ref for dirty space */
		err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
		if (err)
			return err;

		switch (je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype)) {
			case JFFS2_NODETYPE_INODE: {
				struct jffs2_sum_inode_flash *spi;
				spi = sp;

				ino = je32_to_cpu(spi->inode);

				dbg_summary("Inode at 0x%08x-0x%08x\n",
					    jeb->offset + je32_to_cpu(spi->offset),
					    jeb->offset + je32_to_cpu(spi->offset) + je32_to_cpu(spi->totlen));

				ic = jffs2_scan_make_ino_cache(c, ino);
				if (!ic) {
					JFFS2_NOTICE("scan_make_ino_cache failed\n");
					return -ENOMEM;
				}

				sum_link_node_ref(c, jeb, je32_to_cpu(spi->offset) | REF_UNCHECKED,
						  PAD(je32_to_cpu(spi->totlen)), ic);

				*pseudo_random += je32_to_cpu(spi->version);

				sp += JFFS2_SUMMARY_INODE_SIZE;

				break;
			}

			case JFFS2_NODETYPE_DIRENT: {
				struct jffs2_sum_dirent_flash *spd;
				int checkedlen;
				spd = sp;

				dbg_summary("Dirent at 0x%08x-0x%08x\n",
					    jeb->offset + je32_to_cpu(spd->offset),
					    jeb->offset + je32_to_cpu(spd->offset) + je32_to_cpu(spd->totlen));


				/* This should never happen, but https://dev.laptop.org/ticket/4184 */
				checkedlen = strnlen(spd->name, spd->nsize);
				if (!checkedlen) {
					printk(KERN_ERR "Dirent at %08x has zero at start of name. Aborting mount.\n",
					       jeb->offset + je32_to_cpu(spd->offset));
					return -EIO;
				}
				if (checkedlen < spd->nsize) {
					printk(KERN_ERR "Dirent at %08x has zeroes in name. Truncating to %d chars\n",
					       jeb->offset + je32_to_cpu(spd->offset), checkedlen);
				}


				fd = jffs2_alloc_full_dirent(checkedlen+1);
				if (!fd)
					return -ENOMEM;

				memcpy(&fd->name, spd->name, checkedlen);
				fd->name[checkedlen] = 0;

				ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(spd->pino));
				if (!ic) {
					jffs2_free_full_dirent(fd);
					return -ENOMEM;
				}

				fd->raw = sum_link_node_ref(c, jeb,  je32_to_cpu(spd->offset) | REF_UNCHECKED,
							    PAD(je32_to_cpu(spd->totlen)), ic);

				fd->next = NULL;
				fd->version = je32_to_cpu(spd->version);
				fd->ino = je32_to_cpu(spd->ino);
				fd->nhash = full_name_hash(fd->name, checkedlen);
				fd->type = spd->type;

				jffs2_add_fd_to_list(c, fd, &ic->scan_dents);

				*pseudo_random += je32_to_cpu(spd->version);

				sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize);

				break;
			}
#ifdef CONFIG_JFFS2_FS_XATTR
			case JFFS2_NODETYPE_XATTR: {
				struct jffs2_xattr_datum *xd;
				struct jffs2_sum_xattr_flash *spx;

				spx = (struct jffs2_sum_xattr_flash *)sp;
				dbg_summary("xattr at %#08x-%#08x (xid=%u, version=%u)\n", 
					    jeb->offset + je32_to_cpu(spx->offset),
					    jeb->offset + je32_to_cpu(spx->offset) + je32_to_cpu(spx->totlen),
					    je32_to_cpu(spx->xid), je32_to_cpu(spx->version));

				xd = jffs2_setup_xattr_datum(c, je32_to_cpu(spx->xid),
								je32_to_cpu(spx->version));
				if (IS_ERR(xd))
					return PTR_ERR(xd);
				if (xd->version > je32_to_cpu(spx->version)) {
					/* node is not the newest one */
					struct jffs2_raw_node_ref *raw
						= sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
								    PAD(je32_to_cpu(spx->totlen)), NULL);
					raw->next_in_ino = xd->node->next_in_ino;
					xd->node->next_in_ino = raw;
				} else {
					xd->version = je32_to_cpu(spx->version);
					sum_link_node_ref(c, jeb, je32_to_cpu(spx->offset) | REF_UNCHECKED,
							  PAD(je32_to_cpu(spx->totlen)), (void *)xd);
				}
				*pseudo_random += je32_to_cpu(spx->xid);
				sp += JFFS2_SUMMARY_XATTR_SIZE;

				break;
			}
			case JFFS2_NODETYPE_XREF: {
				struct jffs2_xattr_ref *ref;
				struct jffs2_sum_xref_flash *spr;

				spr = (struct jffs2_sum_xref_flash *)sp;
				dbg_summary("xref at %#08x-%#08x\n",
					    jeb->offset + je32_to_cpu(spr->offset),
					    jeb->offset + je32_to_cpu(spr->offset) + 
					    (uint32_t)PAD(sizeof(struct jffs2_raw_xref)));

				ref = jffs2_alloc_xattr_ref();
				if (!ref) {
					JFFS2_NOTICE("allocation of xattr_datum failed\n");
					return -ENOMEM;
				}
				ref->next = c->xref_temp;
				c->xref_temp = ref;

				sum_link_node_ref(c, jeb, je32_to_cpu(spr->offset) | REF_UNCHECKED,
						  PAD(sizeof(struct jffs2_raw_xref)), (void *)ref);

				*pseudo_random += ref->node->flash_offset;
				sp += JFFS2_SUMMARY_XREF_SIZE;

				break;
			}
#endif
			default : {
				uint16_t nodetype = je16_to_cpu(((struct jffs2_sum_unknown_flash *)sp)->nodetype);
				JFFS2_WARNING("Unsupported node type %x found in summary! Exiting...\n", nodetype);
				if ((nodetype & JFFS2_COMPAT_MASK) == JFFS2_FEATURE_INCOMPAT)
					return -EIO;

				/* For compatible node types, just fall back to the full scan */
				c->wasted_size -= jeb->wasted_size;
				c->free_size += c->sector_size - jeb->free_size;
				c->used_size -= jeb->used_size;
				c->dirty_size -= jeb->dirty_size;
				jeb->wasted_size = jeb->used_size = jeb->dirty_size = 0;
				jeb->free_size = c->sector_size;

				jffs2_free_jeb_node_refs(c, jeb);
				return -ENOTRECOVERABLE;
			}
		}
	}
	return 0;
}
Beispiel #11
0
/*
 * 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,
				uint32_t *latest_mctime, uint32_t *mctime_ver)
{
	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));

	/* Sanity check */
	if (unlikely(PAD((rd->nsize + sizeof(*rd))) != PAD(je32_to_cpu(rd->totlen)))) {
		JFFS2_ERROR("illegal nsize in node at %#08x: nsize %#02x, totlen %#04x\n",
		       ref_offset(ref), rd->nsize, je32_to_cpu(rd->totlen));
		return 1;
	}

	fd = jffs2_alloc_full_dirent(rd->nsize + 1);
	if (unlikely(!fd))
		return -ENOMEM;

	fd->raw = ref;
	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 && je32_to_cpu(rd->mctime)) {
		*mctime_ver = fd->version;
		*latest_mctime = je32_to_cpu(rd->mctime);
	}

	/*
	 * Copy as much of the name as possible from the raw
	 * dirent we've already read from the flash.
	 */
	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 (rd->nsize + sizeof(*rd) > read) {
		/* FIXME: point() */
		int err;
		int already = read - sizeof(*rd);

		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 (unlikely(err)) {
			JFFS2_ERROR("read remainder of name: error %d\n", err);
			jffs2_free_full_dirent(fd);
			return -EIO;
		}
	}

	fd->nhash = full_name_hash(fd->name, rd->nsize);
	fd->next = NULL;
	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
	 */
	jffs2_add_fd_to_list(c, fd, fdp);

	return 0;
}