Beispiel #1
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;
}
/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash,
   fill in the raw_inode while you're at it. */
struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri)
{
	struct inode *inode;
	struct super_block *sb = dir_i->i_sb;
	struct jffs2_inode_cache *ic;
	struct jffs2_sb_info *c;
	struct jffs2_inode_info *f;

	D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode));

	c = JFFS2_SB_INFO(sb);
	memset(ri, 0, sizeof(*ri));

	ic = jffs2_alloc_inode_cache();
	if (!ic) {
		return ERR_PTR(-ENOMEM);
	}
	memset(ic, 0, sizeof(*ic));
	
	inode = new_inode(sb);
	
	if (!inode) {
		jffs2_free_inode_cache(ic);
		return ERR_PTR(-ENOMEM);
	}

	/* Alloc jffs2_inode_info when that's split in 2.5 */

	f = JFFS2_INODE_INFO(inode);
	memset(f, 0, sizeof(*f));
	init_MUTEX_LOCKED(&f->sem);
	f->inocache = ic;
	inode->i_nlink = f->inocache->nlink = 1;
	f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
	f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino;
	D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino));
	jffs2_add_ino_cache(c, f->inocache);

	ri->magic = JFFS2_MAGIC_BITMASK;
	ri->nodetype = JFFS2_NODETYPE_INODE;
	ri->totlen = PAD(sizeof(*ri));
	ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4);
	ri->mode = mode;
	f->highest_version = ri->version = 1;
	ri->uid = current->fsuid;
	if (dir_i->i_mode & S_ISGID) {
		ri->gid = dir_i->i_gid;
		if (S_ISDIR(mode))
			ri->mode |= S_ISGID;
	} else {
		ri->gid = current->fsgid;
	}
	inode->i_mode = ri->mode;
	inode->i_gid = ri->gid;
	inode->i_uid = ri->uid;
	inode->i_atime = inode->i_ctime = inode->i_mtime = 
		ri->atime = ri->mtime = ri->ctime = CURRENT_TIME;
	inode->i_blksize = PAGE_SIZE;
	inode->i_blocks = 0;
	inode->i_size = 0;

	insert_inode_hash(inode);

	return inode;
}
Beispiel #3
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 #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;
	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("node CRC failed on dnode at %#08x: read %#08x, calculated %#08x\n",
			     ref_offset(ref), je32_to_cpu(rd->node_crc), crc);
		return 1;
	}

	tn = jffs2_alloc_tmp_dnode_info();
	if (!tn) {
		JFFS2_ERROR("failed to allocate tn (%zu 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) {

		/* 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
void create_summed_image(int inp_size)
{
	uint8_t *p = file_buffer;
	union jffs2_node_union *node;
	uint32_t crc, length;
	uint16_t type;
	int bitchbitmask = 0;
	int obsolete;
	char name[256];

	while ( p < (file_buffer + inp_size)) {

		node = (union jffs2_node_union *) p;

		/* Skip empty space */
		if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
			p += 4;
			continue;
		}

		if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
			if (!bitchbitmask++)
				printf ("Wrong bitmask  at  0x%08x, 0x%04x\n", p - file_buffer, je16_to_cpu (node->u.magic));
			p += 4;
			continue;
		}

		bitchbitmask = 0;

		type = je16_to_cpu(node->u.nodetype);
		if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
			obsolete = 1;
			type |= JFFS2_NODE_ACCURATE;
		} else {
			obsolete = 0;
		}

		node->u.nodetype = cpu_to_je16(type);

		crc = crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
		if (crc != je32_to_cpu (node->u.hdr_crc)) {
			printf ("Wrong hdr_crc  at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
			p += 4;
			continue;
		}

		switch(je16_to_cpu(node->u.nodetype)) {
			case JFFS2_NODETYPE_INODE:
				if (verbose)
					printf ("%8s Inode      node at 0x%08x, totlen 0x%08x, #ino  %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, 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), je32_to_cpu (node->i.offset));

				crc = crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
				if (crc != je32_to_cpu (node->i.node_crc)) {
					printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
					p += PAD(je32_to_cpu (node->i.totlen));
					continue;
				}

				crc = crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
				if (crc != je32_to_cpu(node->i.data_crc)) {
					printf ("Wrong data_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
					p += PAD(je32_to_cpu (node->i.totlen));
					continue;
				}

				write_inode_to_buff(node);

				p += PAD(je32_to_cpu (node->i.totlen));
				break;

			case JFFS2_NODETYPE_DIRENT:
				memcpy (name, node->d.name, node->d.nsize);
				name [node->d.nsize] = 0x0;

				if (verbose)
					printf ("%8s Dirent     node at 0x%08x, totlen 0x%08x, #pino %5d, version %5d, #ino  %8d, nsize %8d, name %s\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
							je32_to_cpu ( node->d.version), je32_to_cpu (node->d.ino),
							node->d.nsize, name);

				crc = crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
				if (crc != je32_to_cpu (node->d.node_crc)) {
					printf ("Wrong node_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
					p += PAD(je32_to_cpu (node->d.totlen));
					continue;
				}

				crc = crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
				if (crc != je32_to_cpu(node->d.name_crc)) {
					printf ("Wrong name_crc at  0x%08x, 0x%08x instead of 0x%08x\n", p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
					p += PAD(je32_to_cpu (node->d.totlen));
					continue;
				}

				write_dirent_to_buff(node);

				p += PAD(je32_to_cpu (node->d.totlen));
				break;

			case JFFS2_NODETYPE_XATTR:
				if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
					obsolete = 1;
				if (verbose)
					printf("%8s Xdatum     node at 0x%08x, totlen 0x%08x, "
							"#xid  %5u, version %5u\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, je32_to_cpu (node->x.totlen),
							je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
				crc = crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
				if (crc != je32_to_cpu(node->x.node_crc)) {
					printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
							p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
					p += PAD(je32_to_cpu (node->x.totlen));
					continue;
				}
				length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
				crc = crc32(0, node->x.data, length);
				if (crc != je32_to_cpu(node->x.data_crc)) {
					printf("Wrong data_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
							p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
					p += PAD(je32_to_cpu (node->x.totlen));
					continue;
				}

				write_xattr_to_buff(node);
				p += PAD(je32_to_cpu (node->x.totlen));
				break;

			case JFFS2_NODETYPE_XREF:
				if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
					obsolete = 1;
				if (verbose)
					printf("%8s Xref       node at 0x%08x, totlen 0x%08x, "
							"#ino  %5u, xid     %5u\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, je32_to_cpu(node->r.totlen),
							je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
				crc = crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
				if (crc != je32_to_cpu(node->r.node_crc)) {
					printf("Wrong node_crc at 0x%08x, 0x%08x instead of 0x%08x\n",
							p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
					p += PAD(je32_to_cpu (node->r.totlen));
					continue;
				}

				write_xref_to_buff(node);
				p += PAD(je32_to_cpu (node->r.totlen));
				break;

			case JFFS2_NODETYPE_CLEANMARKER:
				if (verbose) {
					printf ("%8s Cleanmarker     at 0x%08x, totlen 0x%08x\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, je32_to_cpu (node->u.totlen));
				}

				if (!found_cleanmarkers) {
					found_cleanmarkers = 1;

					if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1){
						cleanmarker_size = je32_to_cpu (node->u.totlen);
						setup_cleanmarker();
					}
				}

				p += PAD(je32_to_cpu (node->u.totlen));
				break;

			case JFFS2_NODETYPE_PADDING:
				if (verbose) {
					printf ("%8s Padding    node at 0x%08x, totlen 0x%08x\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, je32_to_cpu (node->u.totlen));
				}
				p += PAD(je32_to_cpu (node->u.totlen));
				break;

			case 0xffff:
				p += 4;
				break;

			default:
				if (verbose) {
					printf ("%8s Unknown    node at 0x%08x, totlen 0x%08x\n",
							obsolete ? "Obsolete" : "",
							p - file_buffer, je32_to_cpu (node->u.totlen));
				}

				p += PAD(je32_to_cpu (node->u.totlen));
		}
	}
}
Beispiel #6
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;
}
/*
=================
R_LoadIQModel

Load an IQM model and compute the joint matrices for every frame.
=================
*/
bool R_LoadIQModel( model_t *mod, void *buffer, int filesize,
			const char *mod_name ) {
	iqmHeader_t		*header;
	iqmVertexArray_t	*vertexarray;
	iqmTriangle_t		*triangle;
	iqmMesh_t		*mesh;
	iqmJoint_t		*joint;
	iqmPose_t		*pose;
	iqmAnim_t		*anim;
	unsigned short		*framedata;
	char			*str, *name;
	int		len;
	transform_t		*trans, *poses;
	float			*bounds;
	size_t			size, len_names;
	IQModel_t		*IQModel;
	IQAnim_t		*IQAnim;
	srfIQModel_t		*surface;
	vboData_t               vboData;
	float                   *weightbuf;
	int                     *indexbuf;
	i16vec4_t               *qtangentbuf;
	VBO_t                   *vbo;
	IBO_t                   *ibo;
	void                    *ptr;
	u8vec4_t                *weights;

	if( !LoadIQMFile( buffer, filesize, mod_name, &len_names ) ) {
		return false;
	}

	header = (iqmHeader_t *)buffer;

	// compute required space
	size = sizeof(IQModel_t);
	size += header->num_meshes * sizeof( srfIQModel_t );
	size += header->num_anims * sizeof( IQAnim_t );
	size += header->num_joints * sizeof( transform_t );
	size = PAD( size, 16 );
	size += header->num_joints * header->num_frames * sizeof( transform_t );
	if(header->ofs_bounds)
		size += header->num_frames * 6 * sizeof(float);	// model bounds
	size += header->num_vertexes * 3 * sizeof(float);	// positions
	size += header->num_vertexes * 3 * sizeof(float);	// normals
	size += header->num_vertexes * 3 * sizeof(float);	// tangents
	size += header->num_vertexes * 3 * sizeof(float);	// bitangents
	size += header->num_vertexes * 2 * sizeof(int16_t);	// texcoords
	size += header->num_vertexes * 4 * sizeof(byte);	// blendIndexes
	size += header->num_vertexes * 4 * sizeof(byte);	// blendWeights
	size += header->num_vertexes * 4 * sizeof(byte);	// colors
	size += header->num_triangles * 3 * sizeof(int);	// triangles
	size += header->num_joints * sizeof(int);		// parents
	size += len_names;					// joint and anim names

	IQModel = (IQModel_t *)ri.Hunk_Alloc( size, ha_pref::h_low );
	mod->type = modtype_t::MOD_IQM;
	mod->iqm = IQModel;
	ptr = IQModel + 1;

	// fill header and setup pointers
	IQModel->num_vertexes = header->num_vertexes;
	IQModel->num_triangles = header->num_triangles;
	IQModel->num_frames   = header->num_frames;
	IQModel->num_surfaces = header->num_meshes;
	IQModel->num_joints   = header->num_joints;
	IQModel->num_anims    = header->num_anims;

	IQModel->surfaces = (srfIQModel_t *)ptr;
	ptr = IQModel->surfaces + header->num_meshes;

	if( header->ofs_anims ) {
		IQModel->anims = (IQAnim_t *)ptr;
		ptr = IQModel->anims + header->num_anims;
	} else {
		IQModel->anims = nullptr;
	}

	IQModel->joints = (transform_t *)PADP(ptr, 16);
	ptr = IQModel->joints + header->num_joints;

	if( header->ofs_poses ) {
		poses = (transform_t *)ptr;
		ptr = poses + header->num_poses * header->num_frames;
	} else {
		poses = nullptr;
	}

	if( header->ofs_bounds ) {
		bounds = (float *)ptr;
		ptr = bounds + 6 * header->num_frames;
	} else {
		bounds = nullptr;
	}

	IQModel->positions = (float *)ptr;
	ptr = IQModel->positions + 3 * header->num_vertexes;

	IQModel->normals = (float *)ptr;
	ptr = IQModel->normals + 3 * header->num_vertexes;

	IQModel->tangents = (float *)ptr;
	ptr = IQModel->tangents + 3 * header->num_vertexes;

	IQModel->bitangents = (float *)ptr;
	ptr = IQModel->bitangents + 3 * header->num_vertexes;

	IQModel->texcoords = (int16_t *)ptr;
	ptr = IQModel->texcoords + 2 * header->num_vertexes;

	IQModel->blendIndexes = (byte *)ptr;
	ptr = IQModel->blendIndexes + 4 * header->num_vertexes;

	IQModel->blendWeights = (byte *)ptr;
	ptr = IQModel->blendWeights + 4 * header->num_vertexes;

	IQModel->colors = (byte *)ptr;
	ptr = IQModel->colors + 4 * header->num_vertexes;

	IQModel->jointParents = (int *)ptr;
	ptr = IQModel->jointParents + header->num_joints;

	IQModel->triangles = (int *)ptr;
	ptr = IQModel->triangles + 3 * header->num_triangles;

	str                   = (char *)ptr;
	IQModel->jointNames   = str;

	// copy joint names
	joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints );
	for(unsigned i = 0; i < header->num_joints; i++, joint++ ) {
		name = ( char* )IQMPtr( header, header->ofs_text + joint->name );
		len = strlen( name ) + 1;
		Com_Memcpy( str, name, len );
		str += len;
	}

	// setup animations
	IQAnim = IQModel->anims;
	anim = ( iqmAnim_t* )IQMPtr( header, header->ofs_anims );
	for(int i = 0; i < IQModel->num_anims; i++, IQAnim++, anim++ ) {
		IQAnim->num_frames   = anim->num_frames;
		IQAnim->framerate    = anim->framerate;
		IQAnim->num_joints   = header->num_joints;
		IQAnim->flags        = anim->flags;
		IQAnim->jointParents = IQModel->jointParents;
		if( poses ) {
			IQAnim->poses    = poses + anim->first_frame * header->num_poses;
		} else {
			IQAnim->poses    = nullptr;
		}
		if( bounds ) {
			IQAnim->bounds   = bounds + anim->first_frame * 6;
		} else {
			IQAnim->bounds    = nullptr;
		}
		IQAnim->name         = str;
		IQAnim->jointNames   = IQModel->jointNames;

		name = ( char* )IQMPtr( header, header->ofs_text + anim->name );
		len = strlen( name ) + 1;
		Com_Memcpy( str, name, len );
		str += len;
	}

	// calculate joint transforms
	trans = IQModel->joints;
	joint = ( iqmJoint_t* )IQMPtr( header, header->ofs_joints );
	for(unsigned i = 0; i < header->num_joints; i++, joint++, trans++ ) {
		if( joint->parent >= (int) i ) {
			Log::Warn("R_LoadIQModel: file %s contains an invalid parent joint number.",
				  mod_name );
			return false;
		}

		TransInitRotationQuat( joint->rotate, trans );
		TransAddScale( joint->scale[0], trans );
		TransAddTranslation( joint->translate, trans );

		if( joint->parent >= 0 ) {
			TransCombine( trans, &IQModel->joints[ joint->parent ],
				      trans );
		}

		IQModel->jointParents[i] = joint->parent;
	}

	// calculate pose transforms
	framedata = ( short unsigned int* )IQMPtr( header, header->ofs_frames );
	trans = poses;
	for(unsigned i = 0; i < header->num_frames; i++ ) {
		pose = ( iqmPose_t* )IQMPtr( header, header->ofs_poses );
		for(unsigned j = 0; j < header->num_poses; j++, pose++, trans++ ) {
			vec3_t	translate;
			quat_t	rotate;
			vec3_t	scale;

			translate[0] = pose->channeloffset[0];
			if( pose->mask & 0x001)
				translate[0] += *framedata++ * pose->channelscale[0];
			translate[1] = pose->channeloffset[1];
			if( pose->mask & 0x002)
				translate[1] += *framedata++ * pose->channelscale[1];
			translate[2] = pose->channeloffset[2];
			if( pose->mask & 0x004)
				translate[2] += *framedata++ * pose->channelscale[2];
			rotate[0] = pose->channeloffset[3];
			if( pose->mask & 0x008)
				rotate[0] += *framedata++ * pose->channelscale[3];
			rotate[1] = pose->channeloffset[4];
			if( pose->mask & 0x010)
				rotate[1] += *framedata++ * pose->channelscale[4];
			rotate[2] = pose->channeloffset[5];
			if( pose->mask & 0x020)
				rotate[2] += *framedata++ * pose->channelscale[5];
			rotate[3] = pose->channeloffset[6];
			if( pose->mask & 0x040)
				rotate[3] += *framedata++ * pose->channelscale[6];
			scale[0] = pose->channeloffset[7];
			if( pose->mask & 0x080)
				scale[0] += *framedata++ * pose->channelscale[7];
			scale[1] = pose->channeloffset[8];
			if( pose->mask & 0x100)
				scale[1] += *framedata++ * pose->channelscale[8];
			scale[2] = pose->channeloffset[9];
			if( pose->mask & 0x200)
				scale[2] += *framedata++ * pose->channelscale[9];

			if( scale[0] < 0.0f ||
			    (int)( scale[0] - scale[1] ) ||
			    (int)( scale[1] - scale[2] ) ) {
				Log::Warn("R_LoadIQM: file %s contains an invalid scale.", mod_name );
				return false;
			    }

			// construct transformation
			TransInitRotationQuat( rotate, trans );
			TransAddScale( scale[0], trans );
			TransAddTranslation( translate, trans );
		}
	}

	// copy vertexarrays and indexes
	vertexarray = ( iqmVertexArray_t* )IQMPtr( header, header->ofs_vertexarrays );
	for(unsigned i = 0; i < header->num_vertexarrays; i++, vertexarray++ ) {
		int	n;

		// total number of values
		n = header->num_vertexes * vertexarray->size;

		switch( vertexarray->type ) {
		case IQM_POSITION:
			ClearBounds( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
			Com_Memcpy( IQModel->positions,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(float) );
			for( int j = 0; j < n; j += vertexarray->size ) {
				AddPointToBounds( &IQModel->positions[ j ],
						  IQModel->bounds[ 0 ],
						  IQModel->bounds[ 1 ] );
			}
			IQModel->internalScale = BoundsMaxExtent( IQModel->bounds[ 0 ], IQModel->bounds[ 1 ] );
			if( IQModel->internalScale > 0.0f ) {
				float inverseScale = 1.0f / IQModel->internalScale;
				for( int j = 0; j < n; j += vertexarray->size ) {
					VectorScale( &IQModel->positions[ j ],
						     inverseScale,
						     &IQModel->positions[ j ] );
				}
			}

			break;
		case IQM_NORMAL:
			Com_Memcpy( IQModel->normals,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(float) );
			break;
		case IQM_TANGENT:
			BuildTangents( header->num_vertexes,
				       ( float* )IQMPtr( header, vertexarray->offset ),
				       IQModel->normals, IQModel->tangents,
				       IQModel->bitangents );
			break;
		case IQM_TEXCOORD:
			for( int j = 0; j < n; j++ ) {
				IQModel->texcoords[ j ] = floatToHalf( ((float *)IQMPtr( header, vertexarray->offset ))[ j ] );
			}
			break;
		case IQM_BLENDINDEXES:
			Com_Memcpy( IQModel->blendIndexes,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(byte) );
			break;
		case IQM_BLENDWEIGHTS:
			weights = (u8vec4_t *)IQMPtr( header, vertexarray->offset );
			for(unsigned j = 0; j < header->num_vertexes; j++ ) {
				IQModel->blendWeights[ 4 * j + 0 ] = 255 - weights[ j ][ 1 ] - weights[ j ][ 2 ] - weights[ j ][ 3 ];
				IQModel->blendWeights[ 4 * j + 1 ] = weights[ j ][ 1 ];
				IQModel->blendWeights[ 4 * j + 2 ] = weights[ j ][ 2 ];
				IQModel->blendWeights[ 4 * j + 3 ] = weights[ j ][ 3 ];
			}
			break;
		case IQM_COLOR:
			Com_Memcpy( IQModel->colors,
				    IQMPtr( header, vertexarray->offset ),
				    n * sizeof(byte) );
			break;
		}
	}

	// copy triangles
	triangle = ( iqmTriangle_t* )IQMPtr( header, header->ofs_triangles );
	for(unsigned i = 0; i < header->num_triangles; i++, triangle++ ) {
		IQModel->triangles[3*i+0] = triangle->vertex[0];
		IQModel->triangles[3*i+1] = triangle->vertex[1];
		IQModel->triangles[3*i+2] = triangle->vertex[2];
	}

	// convert data where necessary and create VBO
	if( r_vboModels->integer && glConfig2.vboVertexSkinningAvailable
	    && IQModel->num_joints <= glConfig2.maxVertexSkinningBones ) {

		if( IQModel->blendIndexes ) {
			indexbuf = (int *)ri.Hunk_AllocateTempMemory( sizeof(int[4]) * IQModel->num_vertexes );
			for(int i = 0; i < IQModel->num_vertexes; i++ ) {
				indexbuf[ 4 * i + 0 ] = IQModel->blendIndexes[ 4 * i + 0 ];
				indexbuf[ 4 * i + 1 ] = IQModel->blendIndexes[ 4 * i + 1 ];
				indexbuf[ 4 * i + 2 ] = IQModel->blendIndexes[ 4 * i + 2 ];
				indexbuf[ 4 * i + 3 ] = IQModel->blendIndexes[ 4 * i + 3 ];
			}
		} else {
			indexbuf = nullptr;
		}
		if( IQModel->blendWeights ) {
			const float weightscale = 1.0f / 255.0f;

			weightbuf = (float *)ri.Hunk_AllocateTempMemory( sizeof(vec4_t) * IQModel->num_vertexes );
			for(int i = 0; i < IQModel->num_vertexes; i++ ) {
				if( IQModel->blendWeights[ 4 * i + 0 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 1 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 2 ] == 0 &&
				    IQModel->blendWeights[ 4 * i + 3 ] == 0 )
					IQModel->blendWeights[ 4 * i + 0 ] = 255;

				weightbuf[ 4 * i + 0 ] = weightscale * IQModel->blendWeights[ 4 * i + 0 ];
				weightbuf[ 4 * i + 1 ] = weightscale * IQModel->blendWeights[ 4 * i + 1 ];
				weightbuf[ 4 * i + 2 ] = weightscale * IQModel->blendWeights[ 4 * i + 2 ];
				weightbuf[ 4 * i + 3 ] = weightscale * IQModel->blendWeights[ 4 * i + 3 ];
			}
		} else {
			weightbuf = nullptr;
		}

		qtangentbuf = (i16vec4_t *)ri.Hunk_AllocateTempMemory( sizeof( i16vec4_t ) * IQModel->num_vertexes );

		for(int i = 0; i < IQModel->num_vertexes; i++ ) {
			R_TBNtoQtangents( &IQModel->tangents[ 3 * i ],
					  &IQModel->bitangents[ 3 * i ],
					  &IQModel->normals[ 3 * i ],
					  qtangentbuf[ i ] );
		}

		vboData.xyz = (vec3_t *)IQModel->positions;
		vboData.qtangent = qtangentbuf;
		vboData.numFrames = 0;
		vboData.color = (u8vec4_t *)IQModel->colors;
		vboData.st = (i16vec2_t *)IQModel->texcoords;
		vboData.noLightCoords = true;
		vboData.boneIndexes = (int (*)[4])indexbuf;
		vboData.boneWeights = (vec4_t *)weightbuf;
		vboData.numVerts = IQModel->num_vertexes;


		vbo = R_CreateStaticVBO( "IQM surface VBO", vboData,
					 vboLayout_t::VBO_LAYOUT_SKELETAL );

		if( qtangentbuf ) {
			ri.Hunk_FreeTempMemory( qtangentbuf );
		}
		if( weightbuf ) {
			ri.Hunk_FreeTempMemory( weightbuf );
		}
		if( indexbuf ) {
			ri.Hunk_FreeTempMemory( indexbuf );
		}

		// create IBO
		ibo = R_CreateStaticIBO( "IQM surface IBO", ( glIndex_t* )IQModel->triangles, IQModel->num_triangles * 3 );
	} else {
		vbo = nullptr;
		ibo = nullptr;
	}

	// register shaders
	// overwrite the material offset with the shader index
	mesh = ( iqmMesh_t* )IQMPtr( header, header->ofs_meshes );
	surface = IQModel->surfaces;
	for(unsigned i = 0; i < header->num_meshes; i++, mesh++, surface++ ) {
		surface->surfaceType = surfaceType_t::SF_IQM;

		if( mesh->name ) {
			surface->name = str;
			name = ( char* )IQMPtr( header, header->ofs_text + mesh->name );
			len = strlen( name ) + 1;
			Com_Memcpy( str, name, len );
			str += len;
		} else {
			surface->name = nullptr;
		}

		surface->shader = R_FindShader( ( char* )IQMPtr(header, header->ofs_text + mesh->material),
						shaderType_t::SHADER_3D_DYNAMIC, RSF_DEFAULT );
		if( surface->shader->defaultShader )
			surface->shader = tr.defaultShader;
		surface->data = IQModel;
		surface->first_vertex = mesh->first_vertex;
		surface->num_vertexes = mesh->num_vertexes;
		surface->first_triangle = mesh->first_triangle;
		surface->num_triangles = mesh->num_triangles;
		surface->vbo = vbo;
		surface->ibo = ibo;
	}

	// copy model bounds
	if(header->ofs_bounds)
	{
		iqmBounds_t *ptr = ( iqmBounds_t* )IQMPtr( header, header->ofs_bounds );
		for(unsigned i = 0; i < header->num_frames; i++)
		{
			VectorCopy( ptr->bbmin, bounds );
			bounds += 3;
			VectorCopy( ptr->bbmax, bounds );
			bounds += 3;

			ptr++;
		}
	}

	// register animations
	IQAnim = IQModel->anims;
	if( header->num_anims == 1 ) {
		RE_RegisterAnimationIQM( mod_name, IQAnim );
	}
	for(unsigned i = 0; i < header->num_anims; i++, IQAnim++ ) {
		char name[ MAX_QPATH ];

		Com_sprintf( name, MAX_QPATH, "%s:%s", mod_name, IQAnim->name );
		RE_RegisterAnimationIQM( name, IQAnim );
	}

	// build VBO

	return true;
}
Beispiel #8
0
static int ffmpeg_GetFrameBuf( struct AVCodecContext *p_context,
                               AVFrame *p_ff_pic )
{
    decoder_t *p_dec = (decoder_t *)p_context->opaque;
    decoder_sys_t *p_sys = p_dec->p_sys;
    picture_t *p_pic;

    /* Set picture PTS */
    ffmpeg_SetFrameBufferPts( p_dec, p_ff_pic );

    /* */
    p_ff_pic->opaque = NULL;

    if( p_sys->p_va )
    {
#ifdef HAVE_AVCODEC_VAAPI
        /* hwaccel_context is not present in old fffmpeg version */
        if( VaSetup( p_sys->p_va,
                     &p_sys->p_context->hwaccel_context, &p_dec->fmt_out.video.i_chroma,
                     p_sys->p_context->width, p_sys->p_context->height ) )
        {
            msg_Err( p_dec, "VaSetup failed" );
            return -1;
        }
#else
        assert(0);
#endif

        /* */
        p_ff_pic->type = FF_BUFFER_TYPE_USER;
        /* FIXME what is that, should give good value */
        p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg

        if( VaGrabSurface( p_sys->p_va, p_ff_pic ) )
        {
            msg_Err( p_dec, "VaGrabSurface failed" );
            return -1;
        }
        return 0;
    }
    else if( !p_sys->b_direct_rendering )
    {
        /* Not much to do in indirect rendering mode */
        return avcodec_default_get_buffer( p_context, p_ff_pic );
    }

    /* Some codecs set pix_fmt only after the 1st frame has been decoded,
     * so we need to check for direct rendering again. */

    int i_width = p_sys->p_context->width;
    int i_height = p_sys->p_context->height;
    avcodec_align_dimensions( p_sys->p_context, &i_width, &i_height );

    if( GetVlcChroma( &p_dec->fmt_out.video, p_context->pix_fmt ) != VLC_SUCCESS ||
        p_sys->p_context->width % 16 || p_sys->p_context->height % 16 ||
        /* We only pad picture up to 16 */
        PAD(p_sys->p_context->width,16) < i_width || PAD(p_sys->p_context->height,16) < i_height ||
        p_context->pix_fmt == PIX_FMT_PAL8 )
        return avcodec_default_get_buffer( p_context, p_ff_pic );

    p_dec->fmt_out.i_codec = p_dec->fmt_out.video.i_chroma;

    /* Get a new picture */
    p_pic = ffmpeg_NewPictBuf( p_dec, p_sys->p_context );
    if( !p_pic )
        return avcodec_default_get_buffer( p_context, p_ff_pic );

    p_sys->p_context->draw_horiz_band = NULL;

    p_ff_pic->opaque = (void*)p_pic;
    p_ff_pic->type = FF_BUFFER_TYPE_USER;
    p_ff_pic->data[0] = p_pic->p[0].p_pixels;
    p_ff_pic->data[1] = p_pic->p[1].p_pixels;
    p_ff_pic->data[2] = p_pic->p[2].p_pixels;
    p_ff_pic->data[3] = NULL; /* alpha channel but I'm not sure */

    p_ff_pic->linesize[0] = p_pic->p[0].i_pitch;
    p_ff_pic->linesize[1] = p_pic->p[1].i_pitch;
    p_ff_pic->linesize[2] = p_pic->p[2].i_pitch;
    p_ff_pic->linesize[3] = 0;

    decoder_LinkPicture( p_dec, p_pic );

    /* FIXME what is that, should give good value */
    p_ff_pic->age = 256*256*256*64; // FIXME FIXME from ffmpeg

    return 0;
}
        /// Run all benchmarking tests.
        static void RunAllTests()
        {
            Benchmarker& instance = Instance();
            
            // Initial output
            std::cout << std::fixed;
            std::cout << Console::TextGreen << "[==========]"
                      << Console::TextDefault << " Running "
                      << instance._tests.size()
                      << (instance._tests.size() == 1 ?
                          " benchmark." : 
                          " benchmarks.")
                      << std::endl;

            // Run through all the tests in ascending order.
#define PAD(x) std::cout << std::setw(34) << x << std::endl;
#define PAD_DEVIATION(description,                                      \
                      deviated,                                         \
                      average,                                          \
                      unit)                                             \
            {                                                           \
                double _d_ =                                            \
                    double(deviated) - double(average);                 \
                                                                        \
                PAD(description <<                                      \
                    deviated << " "unit" (" <<                          \
                    (deviated < average ?                               \
                     Console::TextRed :                                 \
                     Console::TextGreen) <<                             \
                    (deviated > average ? "+" : "") <<                  \
                    _d_ << " "unit" / " <<                              \
                    (deviated > average ? "+" : "") <<                  \
                    (_d_ * 100.0 / average) << " %" <<                  \
                    Console::TextDefault << ")");                       \
            }
            
#define PAD_DEVIATION_INVERSE(description,                              \
                              deviated,                                 \
                              average,                                  \
                              unit)                                     \
            {                                                           \
                double _d_ =                                            \
                    double(deviated) - double(average);                 \
                                                                        \
                PAD(description <<                                      \
                    deviated << " "unit" (" <<                          \
                    (deviated > average ?                               \
                     Console::TextRed :                                 \
                     Console::TextGreen) <<                             \
                    (deviated > average ? "+" : "") <<                  \
                    _d_ << " "unit" / " <<                              \
                    (deviated > average ? "+" : "") <<                  \
                    (_d_ * 100.0 / average) << " %" <<                  \
                    Console::TextDefault << ")");                       \
            }


            std::size_t index = 0;
            std::size_t ran = 0; /// Number of executed tests
            while (index < instance._tests.size())
            {
                // Get the test descriptor.
                TestDescriptor* descriptor = instance._tests[index++];

                // Check if test matches include filters
                if(instance._include.size() > 0) {
                	bool included = false;
                	std::string name = descriptor->FixtureName + "." + descriptor->TestName+descriptor->Parameters;

                	for(std::size_t i = 0; i <instance._include.size(); i++) {
                		if(name.find(instance._include[i]) != std::string::npos) {
                			included = true;
                			break;
                		}
                	}

                	if(!included) {
                		continue;
                	}
                }

                ran++;

                // Get test instance, which will handle BeforeTest() and AfterTest() hooks.
                Test* hooks = descriptor->Factory->CreateTest();
                hooks->BeforeTest(descriptor->FixtureName, descriptor->TestName, descriptor->Runs, descriptor->Iterations);
               
                // Describe the beginning of the run.
                std::cout << Console::TextGreen << "[ RUN      ]"
                          << Console::TextYellow << " "
                          << descriptor->FixtureName << "."
                          << descriptor->TestName
                          << descriptor->Parameters
                          << Console::TextDefault
                          << " (" << descriptor->Runs
                          << (descriptor->Runs == 1 ? " run, " : " runs, ") 
                          << descriptor->Iterations
                          << (descriptor->Iterations == 1 ?
                              " iteration per run)" :
                              " iterations per run)")
                          << std::endl;
                
                // Execute each individual run.
                int64_t timeTotal = 0,
                        timeRunMin = std::numeric_limits<int64_t>::max(),
                        timeRunMax = std::numeric_limits<int64_t>::min();

                std::size_t run = descriptor->Runs;
                while (run--)
                {
                    // Construct a test instance.
                    Test* test = descriptor->Factory->CreateTest();
                        
                    // Run the test.
                    int64_t time = test->Run(descriptor->Iterations);
                    
                    // Store the test time.
                    timeTotal += time;
                    if (timeRunMin > time)
                        timeRunMin = time;
                    if (timeRunMax < time)
                        timeRunMax = time;
                    
                    // Dispose of the test instance.
                    delete test;
                }
                
                // Calculate different metrics.
                double timeRunAverage = double(timeTotal) / double(descriptor->Runs);

                double runsPerSecondAverage = 1000000.0 / timeRunAverage;
                double runsPerSecondMax = 1000000.0 / double(timeRunMin);
                double runsPerSecondMin = 1000000.0 / double(timeRunMax);
                
                double timeIterationAverage = timeRunAverage / double(descriptor->Iterations);
                double timeIterationMin = double(timeRunMin) / double(descriptor->Iterations);
                double timeIterationMax = double(timeRunMax) / double(descriptor->Iterations);

                double iterationsPerSecondAverage = 1000000.0 / timeIterationAverage;
                double iterationsPerSecondMax = 1000000.0 / timeIterationMin;
                double iterationsPerSecondMin = 1000000.0 / timeIterationMax;

                // Describe the end of the run.
                std::cout << Console::TextGreen << "[     DONE ]"
                          << Console::TextYellow << " "
                          << descriptor->FixtureName << "."
                          << descriptor->TestName
                          << descriptor->Parameters
                          << Console::TextDefault << " ("
                          << (double(timeTotal) / 1000.0) << " ms)"
                          << std::endl;
                
                std::cout << Console::TextBlue << "[   RUNS   ] "
                          << Console::TextDefault
                          << "       Average time: " << timeRunAverage
                          << " us" << std::endl;
                
                PAD_DEVIATION_INVERSE("Fastest: ",
                              timeRunMin,
                              timeRunAverage,
                              "us");
                PAD_DEVIATION_INVERSE("Slowest: ",
                              timeRunMax,
                              timeRunAverage,
                              "us");
                PAD("");
                PAD("Average performance: " << runsPerSecondAverage << " runs/s");
                PAD_DEVIATION("Best performance: ",
                              runsPerSecondMax,
                              runsPerSecondAverage,
                              "runs/s");
                PAD_DEVIATION("Worst performance: ",
                              runsPerSecondMin,
                              runsPerSecondAverage,
                              "runs/s");

                std::cout << Console::TextBlue << "[ITERATIONS] "
                          << Console::TextDefault
                          << "       Average time: " << timeIterationAverage
                          << " us" << std::endl;
                
                PAD_DEVIATION_INVERSE("Fastest: ",
                              timeIterationMin,
                              timeIterationAverage,
                              "us");
                PAD_DEVIATION_INVERSE("Slowest: ",
                              timeIterationMax,
                              timeIterationAverage,
                              "us");
                PAD("");
                PAD("Average performance: " << iterationsPerSecondAverage << " iterations/s");
                PAD_DEVIATION("Best performance: ",
                              iterationsPerSecondMax,
                              iterationsPerSecondAverage,
                              "iterations/s");
                PAD_DEVIATION("Worst performance: ",
                              iterationsPerSecondMin,
                              iterationsPerSecondAverage,
                              "iterations/s");

                hooks->AfterRun(
                		timeRunAverage,
						runsPerSecondAverage, runsPerSecondMax, runsPerSecondMin,
						timeIterationAverage, timeIterationMax, timeIterationMin,
						iterationsPerSecondAverage, iterationsPerSecondMax, iterationsPerSecondMin
                		);
                delete hooks;
            }

#undef PAD

            // Final output.
            std::cout << Console::TextGreen << "[==========]"
                      << Console::TextDefault << " Ran "
                      << ran
                      << (ran == 1 ?
                          " benchmark." : 
                          " benchmarks.")
                      << std::endl;
        }
Beispiel #10
0
static int
parse_settings (unsigned char *prop,
                unsigned long bytes,
                struct xsettings *settings)
{
  Lisp_Object byteorder = Fbyteorder ();
  int my_bo = XFASTINT (byteorder) == 'B' ? MSBFirst : LSBFirst;
  int that_bo = prop[0];
  CARD32 n_settings;
  int bytes_parsed = 0;
  int settings_seen = 0;
  int i = 0;

  /* First 4 bytes is a serial number, skip that.  */

  if (bytes < 12) return settings_seen;
  memcpy (&n_settings, prop+8, 4);
  if (my_bo != that_bo) n_settings = bswap_32 (n_settings);
  bytes_parsed = 12;

  memset (settings, 0, sizeof (*settings));

  while (bytes_parsed+4 < bytes && settings_seen < 7
         && i < n_settings)
    {
      int type = prop[bytes_parsed++];
      CARD16 nlen;
      CARD32 vlen, ival = 0;
      char name[128]; /* The names we are looking for are not this long.  */
      char sval[128]; /* The values we are looking for are not this long.  */
      bool want_this;
      int to_cpy;

      sval[0] = '\0';
      ++i;
      ++bytes_parsed; /* Padding */

      memcpy (&nlen, prop+bytes_parsed, 2);
      bytes_parsed += 2;
      if (my_bo != that_bo) nlen = bswap_16 (nlen);
      if (bytes_parsed + nlen > bytes) return settings_seen;
      to_cpy = min (nlen, sizeof name - 1);
      memcpy (name, prop+bytes_parsed, to_cpy);
      name[to_cpy] = '\0';

      bytes_parsed += nlen;
      bytes_parsed = PAD (bytes_parsed);

      bytes_parsed += 4; /* Skip serial for this value */
      if (bytes_parsed > bytes) return settings_seen;

      want_this = strcmp (XSETTINGS_TOOL_BAR_STYLE, name) == 0;
#ifdef HAVE_XFT
      if ((nlen > 6 && memcmp (name, "Xft/", 4) == 0)
	  || strcmp (XSETTINGS_FONT_NAME, name) == 0)
	want_this = true;
#endif

      switch (type)
        {
        case 0: /* Integer */
          if (bytes_parsed + 4 > bytes) return settings_seen;
          if (want_this)
            {
              memcpy (&ival, prop+bytes_parsed, 4);
              if (my_bo != that_bo) ival = bswap_32 (ival);
            }
          bytes_parsed += 4;
          break;

        case 1: /* String */
          if (bytes_parsed + 4 > bytes) return settings_seen;
          memcpy (&vlen, prop+bytes_parsed, 4);
          bytes_parsed += 4;
          if (my_bo != that_bo) vlen = bswap_32 (vlen);
          if (want_this)
            {
              to_cpy = min (vlen, sizeof sval - 1);
              memcpy (sval, prop+bytes_parsed, to_cpy);
              sval[to_cpy] = '\0';
            }
          bytes_parsed += vlen;
          bytes_parsed = PAD (bytes_parsed);
          break;

        case 2: /* RGB value */
          /* No need to parse this */
          if (bytes_parsed + 8 > bytes) return settings_seen;
          bytes_parsed += 8; /* 4 values (r, b, g, alpha), 2 bytes each.  */
          break;

        default: /* Parse Error */
          return settings_seen;
        }

      if (want_this)
        {
          if (strcmp (name, XSETTINGS_TOOL_BAR_STYLE) == 0)
            {
              dupstring (&settings->tb_style, sval);
              settings->seen |= SEEN_TB_STYLE;
            }
#ifdef HAVE_XFT
          else if (strcmp (name, XSETTINGS_FONT_NAME) == 0)
            {
              dupstring (&settings->font, sval);
              settings->seen |= SEEN_FONT;
            }
          else if (strcmp (name, "Xft/Antialias") == 0)
            {
              settings->seen |= SEEN_AA;
              settings->aa = ival != 0;
            }
          else if (strcmp (name, "Xft/Hinting") == 0)
            {
              settings->seen |= SEEN_HINTING;
              settings->hinting = ival != 0;
            }
# ifdef FC_HINT_STYLE
          else if (strcmp (name, "Xft/HintStyle") == 0)
            {
              settings->seen |= SEEN_HINTSTYLE;
              if (strcmp (sval, "hintnone") == 0)
                settings->hintstyle = FC_HINT_NONE;
              else if (strcmp (sval, "hintslight") == 0)
                settings->hintstyle = FC_HINT_SLIGHT;
              else if (strcmp (sval, "hintmedium") == 0)
                settings->hintstyle = FC_HINT_MEDIUM;
              else if (strcmp (sval, "hintfull") == 0)
                settings->hintstyle = FC_HINT_FULL;
              else
                settings->seen &= ~SEEN_HINTSTYLE;
            }
# endif
          else if (strcmp (name, "Xft/RGBA") == 0)
            {
              settings->seen |= SEEN_RGBA;
              if (strcmp (sval, "none") == 0)
                settings->rgba = FC_RGBA_NONE;
              else if (strcmp (sval, "rgb") == 0)
                settings->rgba = FC_RGBA_RGB;
              else if (strcmp (sval, "bgr") == 0)
                settings->rgba = FC_RGBA_BGR;
              else if (strcmp (sval, "vrgb") == 0)
                settings->rgba = FC_RGBA_VRGB;
              else if (strcmp (sval, "vbgr") == 0)
                settings->rgba = FC_RGBA_VBGR;
              else
                settings->seen &= ~SEEN_RGBA;
            }
          else if (strcmp (name, "Xft/DPI") == 0 && ival != (CARD32) -1)
            {
              settings->seen |= SEEN_DPI;
              settings->dpi = ival / 1024.0;
            }
          else if (strcmp (name, "Xft/lcdfilter") == 0)
            {
              settings->seen |= SEEN_LCDFILTER;
              if (strcmp (sval, "none") == 0)
                settings->lcdfilter = FC_LCD_NONE;
              else if (strcmp (sval, "lcddefault") == 0)
                settings->lcdfilter = FC_LCD_DEFAULT;
              else
                settings->seen &= ~SEEN_LCDFILTER;
            }
#endif /* HAVE_XFT */
	  else
	    want_this = false;
	  settings_seen += want_this;
        }
    }

  return settings_seen;
}
Beispiel #11
0
/* do_graph_label:
 * Set characteristics of graph label if it exists.
 * 
 */
void do_graph_label(graph_t * sg)
{
    char *str, *pos, *just;
    int pos_ix;

    /* it would be nice to allow multiple graph labels in the future */
    if ((str = agget(sg, "label")) && (*str != '\0')) {
	char pos_flag;
	pointf dimen;

	GD_has_labels(sg->root) |= GRAPH_LABEL;

	GD_label(sg) = make_label((void*)sg, str, (aghtmlstr(str) ? LT_HTML : LT_NONE),
	    late_double(sg, agfindgraphattr(sg, "fontsize"),
			DEFAULT_FONTSIZE, MIN_FONTSIZE),
	    late_nnstring(sg, agfindgraphattr(sg, "fontname"),
			DEFAULT_FONTNAME),
	    late_nnstring(sg, agfindgraphattr(sg, "fontcolor"),
			DEFAULT_COLOR));

	/* set label position */
	pos = agget(sg, "labelloc");
	if (sg != agroot(sg)) {
	    if (pos && (pos[0] == 'b'))
		pos_flag = LABEL_AT_BOTTOM;
	    else
		pos_flag = LABEL_AT_TOP;
	} else {
	    if (pos && (pos[0] == 't'))
		pos_flag = LABEL_AT_TOP;
	    else
		pos_flag = LABEL_AT_BOTTOM;
	}
	just = agget(sg, "labeljust");
	if (just) {
	    if (just[0] == 'l')
		pos_flag |= LABEL_AT_LEFT;
	    else if (just[0] == 'r')
		pos_flag |= LABEL_AT_RIGHT;
	}
	GD_label_pos(sg) = pos_flag;

	if (sg == agroot(sg))
	    return;

	/* Set border information for cluster labels to allow space
	 */
	dimen = GD_label(sg)->dimen;
	PAD(dimen);
	if (!GD_flip(agroot(sg))) {
	    if (GD_label_pos(sg) & LABEL_AT_TOP)
		pos_ix = TOP_IX;
	    else
		pos_ix = BOTTOM_IX;
	    GD_border(sg)[pos_ix] = dimen;
	} else {
	    /* when rotated, the labels will be restored to TOP or BOTTOM  */
	    if (GD_label_pos(sg) & LABEL_AT_TOP)
		pos_ix = RIGHT_IX;
	    else
		pos_ix = LEFT_IX;
	    GD_border(sg)[pos_ix].x = dimen.y;
	    GD_border(sg)[pos_ix].y = dimen.x;
	}
    }
}
        /// Run all benchmarking tests.
        static void RunAllTests()
        {
            Benchmarker& instance = Instance();
            
            // Initial output
            std::cout << std::fixed;
            std::cout << Console::TextGreen << "[==========]"
                      << Console::TextDefault << " Running "
                      << instance._tests.size()
                      << (instance._tests.size() == 1 ?
                          " benchmark." : 
                          " benchmarks.")
                      << std::endl;

            // Run through all the tests in ascending order.
#define PAD(x) std::cout << std::setw(34) << x << std::endl;
#define PAD_DEVIATION(description,                                      \
                      deviated,                                         \
                      average,                                          \
                      unit)                                             \
            {                                                           \
                double _d_ =                                            \
                    double(deviated) - double(average);                 \
                                                                        \
                PAD(description <<                                      \
                    deviated << " " << unit << " (" <<                  \
                    (deviated < average ?                               \
                     Console::TextRed :                                 \
                     Console::TextGreen) <<                             \
                    (deviated > average ? "+" : "") <<                  \
                    _d_ << " " << unit << " / " <<                      \
                    (deviated > average ? "+" : "") <<                  \
                    (_d_ * 100.0 / average) << " %" <<                  \
                    Console::TextDefault << ")");                       \
            }
            
#define PAD_DEVIATION_INVERSE(description,                              \
                              deviated,                                 \
                              average,                                  \
                              unit)                                     \
            {                                                           \
                double _d_ =                                            \
                    double(deviated) - double(average);                 \
                                                                        \
                PAD(description <<                                      \
                    deviated << " " << unit << " (" <<                  \
                    (deviated > average ?                               \
                     Console::TextRed :                                 \
                     Console::TextGreen) <<                             \
                    (deviated > average ? "+" : "") <<                  \
                    _d_ << " " << unit << " / " <<                      \
                    (deviated > average ? "+" : "") <<                  \
                    (_d_ * 100.0 / average) << " %" <<                  \
                    Console::TextDefault << ")");                       \
            }


            std::size_t index = 0;
            while (index < instance._tests.size())
            {
                // Get the test descriptor.
                TestDescriptor* descriptor = instance._tests[index++];
               
                // Describe the beginning of the run.
                std::cout << Console::TextGreen << "[ RUN      ]"
                          << Console::TextDefault << " "
                          << descriptor->FixtureName << "."
                          << descriptor->TestName
                          << " (" << descriptor->Runs
                          << (descriptor->Runs == 1 ? " run, " : " runs, ") 
                          << descriptor->Iterations
                          << (descriptor->Iterations == 1 ?
                              " iteration per run)" :
                              " iterations per run)")
                          << std::endl;
                
                // Execute each individual run.
                int64_t timeTotal = 0,
                        timeRunMin = std::numeric_limits<int64_t>::max(),
                        timeRunMax = std::numeric_limits<int64_t>::min();

                std::size_t run = descriptor->Runs;
                while (run--)
                {
                    // Construct a test instance.
                    Test* test = descriptor->Factory->CreateTest();
                        
                    // Run the test.
                    int64_t time = test->Run(descriptor->Iterations);
                    
                    // Store the test time.
                    timeTotal += time;
                    if (timeRunMin > time)
                        timeRunMin = time;
                    if (timeRunMax < time)
                        timeRunMax = time;
                    
                    // Dispose of the test instance.
                    delete test;
                }
                
                // Calculate different metrics.
                double timeRunAverage = double(timeTotal) / double(descriptor->Runs);

                double runsPerSecondAverage = 1000000.0 / timeRunAverage;
                double runsPerSecondMax = 1000000.0 / double(timeRunMin);
                double runsPerSecondMin = 1000000.0 / double(timeRunMax);
                
                double timeIterationAverage = timeRunAverage / double(descriptor->Iterations);
                double timeIterationMin = double(timeRunMin) / double(descriptor->Iterations);
                double timeIterationMax = double(timeRunMax) / double(descriptor->Iterations);

                double iterationsPerSecondAverage = 1000000.0 / timeIterationAverage;
                double iterationsPerSecondMax = 1000000.0 / timeIterationMin;
                double iterationsPerSecondMin = 1000000.0 / timeIterationMax;

                // Describe the end of the run.
                std::cout << Console::TextGreen << "[     DONE ]"
                          << Console::TextDefault << " "
                          << descriptor->FixtureName << "."
                          << descriptor->TestName << " ("
                          << (double(timeTotal) / 1000.0) << " ms)"
                          << std::endl;
                
                std::cout << Console::TextYellow << "[   RUNS   ] "
                          << Console::TextDefault
                          << "       Average time: " << timeRunAverage
                          << " us" << std::endl;
                
                PAD_DEVIATION_INVERSE("Fastest: ",
                              timeRunMin,
                              timeRunAverage,
                              "us");
                PAD_DEVIATION_INVERSE("Slowest: ",
                              timeRunMax,
                              timeRunAverage,
                              "us");
                PAD("");
                PAD("Average performance: " << runsPerSecondAverage << " runs/s");
                PAD_DEVIATION("Best performance: ",
                              runsPerSecondMax,
                              runsPerSecondAverage,
                              "runs/s");
                PAD_DEVIATION("Worst performance: ",
                              runsPerSecondMin,
                              runsPerSecondAverage,
                              "runs/s");

                std::cout << Console::TextYellow << "[ITERATIONS] "
                          << Console::TextDefault
                          << "       Average time: " << timeIterationAverage
                          << " us" << std::endl;
                
                PAD_DEVIATION_INVERSE("Fastest: ",
                              timeIterationMin,
                              timeIterationAverage,
                              "us");
                PAD_DEVIATION_INVERSE("Slowest: ",
                              timeIterationMax,
                              timeIterationAverage,
                              "us");
                PAD("");
                PAD("Average performance: " << iterationsPerSecondAverage << " iterations/s");
                PAD_DEVIATION("Best performance: ",
                              iterationsPerSecondMax,
                              iterationsPerSecondAverage,
                              "iterations/s");
                PAD_DEVIATION("Worst performance: ",
                              iterationsPerSecondMin,
                              iterationsPerSecondAverage,
                              "iterations/s");
            }

#undef PAD

            // Final output.
            std::cout << Console::TextGreen << "[==========]"
                      << Console::TextDefault << " Ran "
                      << instance._tests.size()
                      << (instance._tests.size() == 1 ?
                          " benchmark." : 
                          " benchmarks.")
                      << std::endl;
        }
void* exec_task(void* msg_in) {
   int* msg = (int*) msg_in;
   rankprintf("Beginning task %s on token %d. Setting status to BUSY.\n", task_name(msg[0]), msg[1]);

   //Change status to IDLE
   pthread_mutex_lock(&lock);
   node_status = STATUS_BUSY;
   pthread_mutex_unlock(&lock);

   if (TASK_GENVIS == msg[0]) {
      //Generate some visibilities
      //This won't be needed long term
      // msg[0] : task type
      // msg[1] : tokenid;
      // msg[2] : size
      int next_tok=0;
      while(token_list[next_tok] != 0 && next_tok < 256) next_tok++;
      if(next_tok>=256) throw_error("Too many tokens\n");
      token_list[next_tok] = new token;
      token_list[next_tok]->tid = msg[1];
      token_list[next_tok]->token_type = TOKEN_VIS;
      int npts = msg[2];
      token_list[next_tok]->size = npts;
      //TODO padding for degrid
      token_list[next_tok]->data = malloc(sizeof(PRECISION2)*(PAD(npts)+npts)); //in and out
      token_list[next_tok]->on_rank = rank;
  
      PRECISION2* vis = (PRECISION2*)token_list[next_tok]->data;
      vis += PAD(npts);
      //Random visibilities
      for(int n=0; n<npts;n++) {
         vis[n].x = ((float)rand())/RAND_MAX*1000;
         vis[n].y = ((float)rand())/RAND_MAX*1000;
      }
   } else if (TASK_GENIMG == msg[0]) {
      //Generate an image
      //This won't be needed long term
      // msg[0] : task type
      // msg[1] : tokenid
      // msg[2] : size
      int next_tok=0;
      while(token_list[next_tok] != 0 && next_tok < 256) next_tok++;
      if(next_tok>=256) throw_error("Too many tokens\n");
      token_list[next_tok] = new token;
      token_list[next_tok]->tid = msg[1];
      token_list[next_tok]->token_type = TOKEN_IMG;
      int img_dim = msg[2];
      token_list[next_tok]->size = img_dim;
      //TODO padding for degrid
      token_list[next_tok]->data = malloc(sizeof(PRECISION2)*img_dim*img_dim); //out and in 
      token_list[next_tok]->on_rank = rank;

      PRECISION2* img = (PRECISION2*)token_list[next_tok]->data;
      //Some image
      for(int x=0; x<img_dim;x++)
      for(int y=0; y<img_dim;y++) {
         img[x+img_dim*y].x = exp(-((x-1400.0)*(x-1400.0)+(y-3800.0)*(y-3800.0))/8000000.0)+1.0;
         img[x+img_dim*y].y = 0.4;
      }
      
   } else if (TASK_KILLTOK == msg[0]) {
      free(token_list[msg[0]]->data);
      delete token_list[msg[0]];
      token_list[msg[0]] = NULL;
   } else if (TASK_DEGRID == msg[0]) {
      // Degrid
      // msg[1] : visibility tokenid
      // msg[2] : image tokenid 
      int vistok=0, imgtok=0;
      while(token_list[vistok]->tid != msg[1] && vistok<500) vistok++;
      if (token_list[vistok]->token_type != TOKEN_VIS) 
                throw_error("First token passed to degrid "
                            "does not contain visibilities");
      while(token_list[imgtok]->tid != msg[2]&& imgtok<500) imgtok++;
      if (token_list[imgtok]->token_type != TOKEN_IMG) 
                throw_error("Second token passed to degrid "
                            "is not an image");

      
      int img_size = token_list[imgtok]->size;
      PRECISION2* img = (PRECISION2*) token_list[imgtok]->data;
      int npts = token_list[vistok]->size;
      PRECISION2* out = (PRECISION2*) token_list[vistok]->data;
      PRECISION2* in = out + PAD(npts);

      PRECISION2* gcf = (PRECISION2*)malloc(sizeof(PRECISION2*)*64*GCF_DIM*GCF_DIM);
      init_gcf(gcf, GCF_DIM);
      degridGPU(out, in, npts, img, img_size, gcf, GCF_DIM);
   } else {
      sleep(2);
   }

   rankprintf("Task complete. Setting status to IDLE.\n");
   //Change status to IDLE
   pthread_mutex_lock(&lock);
   node_status = STATUS_IDLE;
   pthread_mutex_unlock(&lock);
  
   return NULL;
}
Beispiel #14
0
static struct log_head *log_next(struct log_head *h, int size)
{
	struct log_head *n = (struct log_head *) &h->data[PAD(sizeof(struct log_head) + size)];

	return (n >= log_end) ? (log) : (n);
}
Beispiel #15
0
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                  unsigned char *buf, uint32_t buf_size) {
    struct jffs2_unknown_node *node;
    struct jffs2_unknown_node crcnode;
    uint32_t ofs, prevofs;
    uint32_t hdr_crc, buf_ofs, buf_len;
    int err;
    int noise = 0;
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
    int cleanmarkerfound = 0;
#endif

    ofs = jeb->offset;
    prevofs = jeb->offset - 1;

    D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));

#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
    if (jffs2_cleanmarker_oob(c)) {
        int ret = jffs2_check_nand_cleanmarker(c, jeb);
        D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
        /* Even if it's not found, we still scan to see
           if the block is empty. We use this information
           to decide whether to erase it or not. */
        switch (ret) {
        case 0:
            cleanmarkerfound = 1;
            break;
        case 1:
            break;
        case 2:
            return BLK_STATE_BADBLOCK;
        case 3:
            return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */
        default:
            return ret;
        }
    }
#endif
    buf_ofs = jeb->offset;

    if (!buf_size) {
        buf_len = c->sector_size;
    } else {
        buf_len = EMPTY_SCAN_SIZE(c->sector_size);
        err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
        if (err)
            return err;
    }

    /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
    ofs = 0;

    /* Scan only 4KiB of 0xFF before declaring it's empty */
    while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
        ofs += 4;

    if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        if (jffs2_cleanmarker_oob(c)) {
            /* scan oob, take care of cleanmarker */
            int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
            D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
            switch (ret) {
            case 0:
                return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
            case 1:
                return BLK_STATE_ALLDIRTY;
            default:
                return ret;
            }
        }
#endif
        D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
        if (c->cleanmarker_size == 0)
            return BLK_STATE_CLEANMARKER;	/* don't bother with re-erase */
        else
            return BLK_STATE_ALLFF;	/* OK to erase if all blocks are like this */
    }
    if (ofs) {
        D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
                  jeb->offset + ofs));
        DIRTY_SPACE(ofs);
    }

    /* Now ofs is a complete physical flash offset as it always was... */
    ofs += jeb->offset;

    noise = 10;

scan_more:
    while(ofs < jeb->offset + c->sector_size) {

        D1(ACCT_PARANOIA_CHECK(jeb));

        cond_resched();

        if (ofs & 3) {
            printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs);
            ofs = PAD(ofs);
            continue;
        }
        if (ofs == prevofs) {
            printk(KERN_WARNING "ofs 0x%08x has already been seen. Skipping\n", ofs);
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }
        prevofs = ofs;

        if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
            D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
                      jeb->offset, c->sector_size, ofs, sizeof(*node)));
            DIRTY_SPACE((jeb->offset + c->sector_size)-ofs);
            break;
        }

        if (buf_ofs + buf_len < ofs + sizeof(*node)) {
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
                      sizeof(struct jffs2_unknown_node), buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
        }

        node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];

        if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
            uint32_t inbuf_ofs;
            uint32_t empty_start;

            empty_start = ofs;
            ofs += 4;

            D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
more_empty:
            inbuf_ofs = ofs - buf_ofs;
            while (inbuf_ofs < buf_len) {
                if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) {
                    printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
                           empty_start, ofs);
                    DIRTY_SPACE(ofs-empty_start);
                    goto scan_more;
                }

                inbuf_ofs+=4;
                ofs += 4;
            }
            /* Ran off end. */
            D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));

            /* If we're only checking the beginning of a block with a cleanmarker,
               bail now */
            if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
                    c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) {
                D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
                return BLK_STATE_CLEANMARKER;
            }

            /* See how much more there is to read in this eraseblock... */
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            if (!buf_len) {
                /* No more to read. Break out of main loop without marking
                   this range of empty space as dirty (because it's not) */
                D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
                          empty_start));
                break;
            }
            D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
            goto more_empty;
        }

        if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
            printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }
        if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
            D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }
        if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
            printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
            printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }
        if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
            /* OK. We're out of possibilities. Whinge and move on */
            noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
                         JFFS2_MAGIC_BITMASK, ofs,
                         je16_to_cpu(node->magic));
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }
        /* We seem to have a node of sorts. Check the CRC */
        crcnode.magic = node->magic;
        crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
        crcnode.totlen = node->totlen;
        hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);

        if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
            noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
                         ofs, je16_to_cpu(node->magic),
                         je16_to_cpu(node->nodetype),
                         je32_to_cpu(node->totlen),
                         je32_to_cpu(node->hdr_crc),
                         hdr_crc);
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }

        if (ofs + je32_to_cpu(node->totlen) >
                jeb->offset + c->sector_size) {
            /* Eep. Node goes over the end of the erase block. */
            printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
                   ofs, je32_to_cpu(node->totlen));
            printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
            DIRTY_SPACE(4);
            ofs += 4;
            continue;
        }

        if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
            /* Wheee. This is an obsoleted node */
            D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
            DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
            ofs += PAD(je32_to_cpu(node->totlen));
            continue;
        }

        switch(je16_to_cpu(node->nodetype)) {
        case JFFS2_NODETYPE_INODE:
            if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
                buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
                D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
                          sizeof(struct jffs2_raw_inode), buf_len, ofs));
                err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
                if (err)
                    return err;
                buf_ofs = ofs;
                node = (void *)buf;
            }
            err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs);
            if (err) return err;
            ofs += PAD(je32_to_cpu(node->totlen));
            break;

        case JFFS2_NODETYPE_DIRENT:
            if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
                buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
                D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
                          je32_to_cpu(node->totlen), buf_len, ofs));
                err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
                if (err)
                    return err;
                buf_ofs = ofs;
                node = (void *)buf;
            }
            err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs);
            if (err) return err;
            ofs += PAD(je32_to_cpu(node->totlen));
            break;

        case JFFS2_NODETYPE_CLEANMARKER:
            D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
            if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
                printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
                       ofs, je32_to_cpu(node->totlen), c->cleanmarker_size);
                DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
                ofs += PAD(sizeof(struct jffs2_unknown_node));
            } else if (jeb->first_node) {
                printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
                DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node)));
                ofs += PAD(sizeof(struct jffs2_unknown_node));
            } else {
                struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();
                if (!marker_ref) {
                    printk(KERN_NOTICE "Failed to allocate node ref for clean marker\n");
                    return -ENOMEM;
                }
                marker_ref->next_in_ino = NULL;
                marker_ref->next_phys = NULL;
                marker_ref->flash_offset = ofs | REF_NORMAL;
                marker_ref->__totlen = c->cleanmarker_size;
                jeb->first_node = jeb->last_node = marker_ref;

                USED_SPACE(PAD(c->cleanmarker_size));
                ofs += PAD(c->cleanmarker_size);
            }
            break;

        case JFFS2_NODETYPE_PADDING:
            DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
            ofs += PAD(je32_to_cpu(node->totlen));
            break;

        default:
            switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
            case JFFS2_FEATURE_ROCOMPAT:
                printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
                c->flags |= JFFS2_SB_FLAG_RO;
                if (!(jffs2_is_readonly(c)))
                    return -EROFS;
                DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
                ofs += PAD(je32_to_cpu(node->totlen));
                break;

            case JFFS2_FEATURE_INCOMPAT:
                printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
                return -EINVAL;

            case JFFS2_FEATURE_RWCOMPAT_DELETE:
                D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
                DIRTY_SPACE(PAD(je32_to_cpu(node->totlen)));
                ofs += PAD(je32_to_cpu(node->totlen));
                break;

            case JFFS2_FEATURE_RWCOMPAT_COPY:
                D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
                USED_SPACE(PAD(je32_to_cpu(node->totlen)));
                ofs += PAD(je32_to_cpu(node->totlen));
                break;
            }
        }
    }


    D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset,
              jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size));

    /* mark_node_obsolete can add to wasted !! */
    if (jeb->wasted_size) {
        jeb->dirty_size += jeb->wasted_size;
        c->dirty_size += jeb->wasted_size;
        c->wasted_size -= jeb->wasted_size;
        jeb->wasted_size = 0;
    }

    if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
            && (!jeb->first_node || !jeb->first_node->next_phys) )
        return BLK_STATE_CLEANMARKER;

    /* move blocks with max 4 byte dirty space to cleanlist */
    else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) {
        c->dirty_size -= jeb->dirty_size;
        c->wasted_size += jeb->dirty_size;
        jeb->wasted_size += jeb->dirty_size;
        jeb->dirty_size = 0;
        return BLK_STATE_CLEAN;
    } else if (jeb->used_size || jeb->unchecked_size)
        return BLK_STATE_PARTDIRTY;
    else
        return BLK_STATE_ALLDIRTY;
}
Beispiel #16
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 #17
0
static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                 struct jffs2_raw_inode *ri, uint32_t ofs)
{
    struct jffs2_raw_node_ref *raw;
    struct jffs2_inode_cache *ic;
    uint32_t ino = je32_to_cpu(ri->ino);

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

    /* We do very little here now. Just check the ino# to which we should attribute
       this node; we can do all the CRC checking etc. later. There's a tradeoff here --
       we used to scan the flash once only, reading everything we want from it into
       memory, then building all our in-core data structures and freeing the extra
       information. Now we allow the first part of the mount to complete a lot quicker,
       but we have to go _back_ to the flash in order to finish the CRC checking, etc.
       Which means that the _full_ amount of time to get to proper write mode with GC
       operational may actually be _longer_ than before. Sucks to be me. */

    raw = jffs2_alloc_raw_node_ref();
    if (!raw) {
        printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n");
        return -ENOMEM;
    }

    ic = jffs2_get_ino_cache(c, ino);
    if (!ic) {
        /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the
           first node we found for this inode. Do a CRC check to protect against the former
           case */
        uint32_t crc = crc32(0, ri, sizeof(*ri)-8);

        if (crc != je32_to_cpu(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, je32_to_cpu(ri->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(ri->totlen)));
            jffs2_free_raw_node_ref(raw);
            return 0;
        }
        ic = jffs2_scan_make_ino_cache(c, ino);
        if (!ic) {
            jffs2_free_raw_node_ref(raw);
            return -ENOMEM;
        }
    }

    /* Wheee. It worked */

    raw->flash_offset = ofs | REF_UNCHECKED;
    raw->__totlen = PAD(je32_to_cpu(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",
              je32_to_cpu(ri->ino), je32_to_cpu(ri->version),
              je32_to_cpu(ri->offset),
              je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize)));

    pseudo_random += je32_to_cpu(ri->version);

    UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen)));
    return 0;
}
static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode)
{
	struct jffs2_inode_info *f, *dir_f;
	struct jffs2_sb_info *c;
	struct inode *inode;
	struct jffs2_raw_inode *ri;
	struct jffs2_raw_dirent *rd;
	struct jffs2_full_dnode *fn;
	struct jffs2_full_dirent *fd;
	int namelen;
	__u32 alloclen, phys_ofs;
	__u32 writtenlen;
	int ret;

	ri = jffs2_alloc_raw_inode();
	if (!ri)
		return -ENOMEM;
	
	c = JFFS2_SB_INFO(dir_i->i_sb);

	D1(printk(KERN_DEBUG "jffs2_create()\n"));

	/* Try to reserve enough space for both node and dirent. 
	 * Just the node will do for now, though 
	 */
	namelen = dentry->d_name.len;
	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);
	D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen));
	if (ret) {
		jffs2_free_raw_inode(ri);
		return ret;
	}

	inode = jffs2_new_inode(dir_i, mode, ri);

	if (IS_ERR(inode)) {
		D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n"));
		jffs2_free_raw_inode(ri);
		jffs2_complete_reservation(c);
		return PTR_ERR(inode);
	}

	inode->i_op = &jffs2_file_inode_operations;
	inode->i_fop = &jffs2_file_operations;
	inode->i_mapping->a_ops = &jffs2_file_address_operations;
	inode->i_mapping->nrpages = 0;

	f = JFFS2_INODE_INFO(inode);

	ri->data_crc = 0;
	ri->node_crc = crc32(0, ri, sizeof(*ri)-8);

	fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen);
	D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode));
	jffs2_free_raw_inode(ri);

	if (IS_ERR(fn)) {
		D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n"));
		/* Eeek. Wave bye bye */
		up(&f->sem);
		jffs2_complete_reservation(c);
		jffs2_clear_inode(inode);
		return PTR_ERR(fn);
	}
	/* No data here. Only a metadata node, which will be 
	   obsoleted by the first data write
	*/
	f->metadata = fn;

	/* Work out where to put the dirent node now. */
	writtenlen = PAD(writtenlen);
	phys_ofs += writtenlen;
	alloclen -= writtenlen;
	up(&f->sem);

	if (alloclen < sizeof(*rd)+namelen) {
		/* Not enough space left in this chunk. Get some more */
		jffs2_complete_reservation(c);
		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
		
		if (ret) {
			/* Eep. */
			D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n"));
			jffs2_clear_inode(inode);
			return ret;
		}
	}

	rd = jffs2_alloc_raw_dirent();
	if (!rd) {
		/* Argh. Now we treat it like a normal delete */
		jffs2_complete_reservation(c);
		jffs2_clear_inode(inode);
		return -ENOMEM;
	}

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

	rd->magic = JFFS2_MAGIC_BITMASK;
	rd->nodetype = JFFS2_NODETYPE_DIRENT;
	rd->totlen = sizeof(*rd) + namelen;
	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 = inode->i_ino;
	rd->mctime = CURRENT_TIME;
	rd->nsize = namelen;
	rd->type = DT_REG;
	rd->node_crc = crc32(0, rd, sizeof(*rd)-8);
	rd->name_crc = crc32(0, dentry->d_name.name, namelen);

	fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);

	jffs2_complete_reservation(c);
	
	if (IS_ERR(fd)) {
		/* dirent failed to write. Delete the inode normally 
		   as if it were the final unlink() */
		jffs2_free_raw_dirent(rd);
		up(&dir_f->sem);
		jffs2_clear_inode(inode);
		return PTR_ERR(fd);
	}

	dir_i->i_mtime = dir_i->i_ctime = rd->mctime;

	jffs2_free_raw_dirent(rd);

	/* Link the fd into the inode's list, obsoleting an old
	   one if necessary. */
	jffs2_add_fd_to_list(c, fd, &dir_f->dents);
	up(&dir_f->sem);

	d_instantiate(dentry, inode);

	D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
		  inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
	return 0;
}
Beispiel #19
0
/* Called with 'buf_size == 0' if buf is in fact a pointer _directly_ into
   the flash, XIP-style */
static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
                                  unsigned char *buf, uint32_t buf_size, struct jffs2_summary *s) {
    struct jffs2_unknown_node *node;
    struct jffs2_unknown_node crcnode;
    uint32_t ofs, prevofs;
    uint32_t hdr_crc, buf_ofs, buf_len;
    int err;
    int noise = 0;


#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
    int cleanmarkerfound = 0;
#endif

    ofs = jeb->offset;
    prevofs = jeb->offset - 1;

    D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));

#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
    if (jffs2_cleanmarker_oob(c)) {
        int ret;

        if (c->mtd->block_isbad(c->mtd, jeb->offset))
            return BLK_STATE_BADBLOCK;

        ret = jffs2_check_nand_cleanmarker(c, jeb);
        D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));

        /* Even if it's not found, we still scan to see
           if the block is empty. We use this information
           to decide whether to erase it or not. */
        switch (ret) {
        case 0:
            cleanmarkerfound = 1;
            break;
        case 1:
            break;
        default:
            return ret;
        }
    }
#endif

    if (jffs2_sum_active()) {
        struct jffs2_sum_marker *sm;
        void *sumptr = NULL;
        uint32_t sumlen;

        if (!buf_size) {
            /* XIP case. Just look, point at the summary if it's there */
            sm = (void *)buf + c->sector_size - sizeof(*sm);
            if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
                sumptr = buf + je32_to_cpu(sm->offset);
                sumlen = c->sector_size - je32_to_cpu(sm->offset);
            }
        } else {
            /* If NAND flash, read a whole page of it. Else just the end */
            if (c->wbuf_pagesize)
                buf_len = c->wbuf_pagesize;
            else
                buf_len = sizeof(*sm);

            /* Read as much as we want into the _end_ of the preallocated buffer */
            err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
                                      jeb->offset + c->sector_size - buf_len,
                                      buf_len);
            if (err)
                return err;

            sm = (void *)buf + buf_size - sizeof(*sm);
            if (je32_to_cpu(sm->magic) == JFFS2_SUM_MAGIC) {
                sumlen = c->sector_size - je32_to_cpu(sm->offset);
                sumptr = buf + buf_size - sumlen;

                /* Now, make sure the summary itself is available */
                if (sumlen > buf_size) {
                    /* Need to kmalloc for this. */
                    sumptr = kmalloc(sumlen, GFP_KERNEL);
                    if (!sumptr)
                        return -ENOMEM;
                    memcpy(sumptr + sumlen - buf_len, buf + buf_size - buf_len, buf_len);
                }
                if (buf_len < sumlen) {
                    /* Need to read more so that the entire summary node is present */
                    err = jffs2_fill_scan_buf(c, sumptr,
                                              jeb->offset + c->sector_size - sumlen,
                                              sumlen - buf_len);
                    if (err)
                        return err;
                }
            }

        }

        if (sumptr) {
            err = jffs2_sum_scan_sumnode(c, jeb, sumptr, sumlen, &pseudo_random);

            if (buf_size && sumlen > buf_size)
                kfree(sumptr);
            /* If it returns with a real error, bail.
               If it returns positive, that's a block classification
               (i.e. BLK_STATE_xxx) so return that too.
               If it returns zero, fall through to full scan. */
            if (err)
                return err;
        }
    }

    buf_ofs = jeb->offset;

    if (!buf_size) {
        /* This is the XIP case -- we're reading _directly_ from the flash chip */
        buf_len = c->sector_size;
    } else {
        buf_len = EMPTY_SCAN_SIZE(c->sector_size);
        err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
        if (err)
            return err;
    }

    /* We temporarily use 'ofs' as a pointer into the buffer/jeb */
    ofs = 0;

    /* Scan only 4KiB of 0xFF before declaring it's empty */
    while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
        ofs += 4;
    if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
        if (jffs2_cleanmarker_oob(c)) {
            /* scan oob, take care of cleanmarker */
            int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
            D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret));
            switch (ret) {
            case 0:
                return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF;
            case 1:
                return BLK_STATE_ALLDIRTY;
            default:
                return ret;
            }
        }
#endif
        D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
        if (c->cleanmarker_size == 0)
            return BLK_STATE_CLEANMARKER;	/* don't bother with re-erase */
        else
            return BLK_STATE_ALLFF;	/* OK to erase if all blocks are like this */
    }
    if (ofs) {
        D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
                  jeb->offset + ofs));
        if ((err = jffs2_prealloc_raw_node_refs(c, jeb, 1)))
            return err;
        if ((err = jffs2_scan_dirty_space(c, jeb, ofs)))
            return err;
    }

    /* Now ofs is a complete physical flash offset as it always was... */
    ofs += jeb->offset;

    noise = 10;

    dbg_summary("no summary found in jeb 0x%08x. Apply original scan.\n",jeb->offset);

scan_more:
    while(ofs < jeb->offset + c->sector_size) {

        jffs2_dbg_acct_paranoia_check_nolock(c, jeb);

        /* Make sure there are node refs available for use */
        err = jffs2_prealloc_raw_node_refs(c, jeb, 2);
        if (err)
            return err;

        cond_resched();

        if (ofs & 3) {
            printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs);
            ofs = PAD(ofs);
            continue;
        }
        if (ofs == prevofs) {
            printk(KERN_WARNING "ofs 0x%08x has already been seen. Skipping\n", ofs);
            if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
                return err;
            ofs += 4;
            continue;
        }
        prevofs = ofs;

        if (jeb->offset + c->sector_size < ofs + sizeof(*node)) {
            D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node),
                      jeb->offset, c->sector_size, ofs, sizeof(*node)));
            if ((err = jffs2_scan_dirty_space(c, jeb, (jeb->offset + c->sector_size)-ofs)))
                return err;
            break;
        }

        if (buf_ofs + buf_len < ofs + sizeof(*node)) {
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n",
                      sizeof(struct jffs2_unknown_node), buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
        }

        node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs];

        if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) {
            uint32_t inbuf_ofs;
            uint32_t empty_start, scan_end;

            empty_start = ofs;
            ofs += 4;
            scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE(c->sector_size)/8, buf_len);

            D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs));
more_empty:
            inbuf_ofs = ofs - buf_ofs;
            while (inbuf_ofs < scan_end) {
                /* printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n",
                       empty_start, ofs); */
                if ((err = jffs2_scan_dirty_space(c, jeb, ofs-empty_start)))
                    return err;
                goto scan_more;
            }

            inbuf_ofs+=4;
            ofs += 4;
        }
        /* Ran off end. */
        D1(printk(KERN_DEBUG "Empty flash to end of buffer at 0x%08x\n", ofs));

        /* If we're only checking the beginning of a block with a cleanmarker,
           bail now */
        if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
                c->cleanmarker_size && !jeb->dirty_size && !ref_next(jeb->first_node)) {
            D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
            return BLK_STATE_CLEANMARKER;
        }
        if (!buf_size && (scan_end != buf_len)) {/* XIP/point case */
            scan_end = buf_len;
            goto more_empty;
        }

        /* See how much more there is to read in this eraseblock... */
        buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
        if (!buf_len) {
            /* No more to read. Break out of main loop without marking
               this range of empty space as dirty (because it's not) */
            D1(printk(KERN_DEBUG "Empty flash at %08x runs to end of block. Treating as free_space\n",
                      empty_start));
            break;
        }
        /* point never reaches here */
        scan_end = buf_len;
        D1(printk(KERN_DEBUG "Reading another 0x%x at 0x%08x\n", buf_len, ofs));
        err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
        if (err)
            return err;
        buf_ofs = ofs;
        goto more_empty;
    }

    if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) {
        printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs);
        if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
            return err;
        ofs += 4;
        continue;
    }
    if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) {
        D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs));
        if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
            return err;
        ofs += 4;
        continue;
    }
    if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) {
        printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs);
        printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n");
        if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
            return err;
        ofs += 4;
        continue;
    }
    if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) {
        /* OK. We're out of possibilities. Whinge and move on */
        noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n",
                     JFFS2_MAGIC_BITMASK, ofs,
                     je16_to_cpu(node->magic));
        if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
            return err;
        ofs += 4;
        continue;
    }
    /* We seem to have a node of sorts. Check the CRC */
    crcnode.magic = node->magic;
    crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE);
    crcnode.totlen = node->totlen;
    hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4);

    if (hdr_crc != je32_to_cpu(node->hdr_crc)) {
        noisy_printk(&noise, "jffs2_scan_eraseblock(): Node at 0x%08x {0x%04x, 0x%04x, 0x%08x) has invalid CRC 0x%08x (calculated 0x%08x)\n",
                     ofs, je16_to_cpu(node->magic),
                     je16_to_cpu(node->nodetype),
                     je32_to_cpu(node->totlen),
                     je32_to_cpu(node->hdr_crc),
                     hdr_crc);
        if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
            return err;
        ofs += 4;
        continue;
    }

    if (ofs + je32_to_cpu(node->totlen) > jeb->offset + c->sector_size) {
        /* Eep. Node goes over the end of the erase block. */
        printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n",
               ofs, je32_to_cpu(node->totlen));
        printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n");
        if ((err = jffs2_scan_dirty_space(c, jeb, 4)))
            return err;
        ofs += 4;
        continue;
    }

    if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) {
        /* Wheee. This is an obsoleted node */
        D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs));
        if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
            return err;
        ofs += PAD(je32_to_cpu(node->totlen));
        continue;
    }

    switch(je16_to_cpu(node->nodetype)) {
    case JFFS2_NODETYPE_INODE:
        if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) {
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n",
                      sizeof(struct jffs2_raw_inode), buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
            node = (void *)buf;
        }
        err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs, s);
        if (err) return err;
        ofs += PAD(je32_to_cpu(node->totlen));
        break;

    case JFFS2_NODETYPE_DIRENT:
        if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n",
                      je32_to_cpu(node->totlen), buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
            node = (void *)buf;
        }
        err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs, s);
        if (err) return err;
        ofs += PAD(je32_to_cpu(node->totlen));
        break;

#ifdef CONFIG_JFFS2_FS_XATTR
    case JFFS2_NODETYPE_XATTR:
        if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            D1(printk(KERN_DEBUG "Fewer than %d bytes (xattr node)"
                      " left to end of buf. Reading 0x%x at 0x%08x\n",
                      je32_to_cpu(node->totlen), buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
            node = (void *)buf;
        }
        err = jffs2_scan_xattr_node(c, jeb, (void *)node, ofs, s);
        if (err)
            return err;
        ofs += PAD(je32_to_cpu(node->totlen));
        break;
    case JFFS2_NODETYPE_XREF:
        if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) {
            buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
            D1(printk(KERN_DEBUG "Fewer than %d bytes (xref node)"
                      " left to end of buf. Reading 0x%x at 0x%08x\n",
                      je32_to_cpu(node->totlen), buf_len, ofs));
            err = jffs2_fill_scan_buf(c, buf, ofs, buf_len);
            if (err)
                return err;
            buf_ofs = ofs;
            node = (void *)buf;
        }
        err = jffs2_scan_xref_node(c, jeb, (void *)node, ofs, s);
        if (err)
            return err;
        ofs += PAD(je32_to_cpu(node->totlen));
        break;
#endif	/* CONFIG_JFFS2_FS_XATTR */

    case JFFS2_NODETYPE_CLEANMARKER:
        D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs));
        if (je32_to_cpu(node->totlen) != c->cleanmarker_size) {
            /* printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n",
                   ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); */
            if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
                return err;
            ofs += PAD(sizeof(struct jffs2_unknown_node));
        } else if (jeb->first_node) {
            printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset);
            if ((err = jffs2_scan_dirty_space(c, jeb, PAD(sizeof(struct jffs2_unknown_node)))))
                return err;
            ofs += PAD(sizeof(struct jffs2_unknown_node));
        } else {
            jffs2_link_node_ref(c, jeb, ofs | REF_NORMAL, c->cleanmarker_size, NULL);

            ofs += PAD(c->cleanmarker_size);
        }
        break;

    case JFFS2_NODETYPE_PADDING:
        if (jffs2_sum_active())
            jffs2_sum_add_padding_mem(s, je32_to_cpu(node->totlen));
        if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
            return err;
        ofs += PAD(je32_to_cpu(node->totlen));
        break;

    default:
        switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) {
        case JFFS2_FEATURE_ROCOMPAT:
            printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
            c->flags |= JFFS2_SB_FLAG_RO;
            if (!(jffs2_is_readonly(c)))
                return -EROFS;
            if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
                return err;
            ofs += PAD(je32_to_cpu(node->totlen));
            break;

        case JFFS2_FEATURE_INCOMPAT:
            printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs);
            return -EINVAL;

        case JFFS2_FEATURE_RWCOMPAT_DELETE:
            D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));
            if ((err = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(node->totlen)))))
                return err;
            ofs += PAD(je32_to_cpu(node->totlen));
            break;

        case JFFS2_FEATURE_RWCOMPAT_COPY: {
            D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs));

            jffs2_link_node_ref(c, jeb, ofs | REF_PRISTINE, PAD(je32_to_cpu(node->totlen)), NULL);

            /* We can't summarise nodes we don't grok */
            jffs2_sum_disable_collecting(s);
            ofs += PAD(je32_to_cpu(node->totlen));
            break;
        }
        }
    }
}
Beispiel #20
0
/* Called with alloc sem _and_ erase_completion_lock */
static int jffs2_do_reserve_space(struct jffs2_sb_info *c,  uint32_t minsize, uint32_t *ofs, uint32_t *len, uint32_t sumsize)
{
	struct jffs2_eraseblock *jeb = c->nextblock;
	uint32_t nofree_size;
	
 restart:
	nofree_size = 0;
	
#ifdef CONFIG_JFFS2_SUMMARY

	if (sumsize != JFFS2_SUMMARY_NOSUM_SIZE) {
		int ret;
			if (jeb) {
				if ((ret=jffs2_sum_care_sum_collected(jeb))) 
					return ret;
				nofree_size = PAD(sumsize + jeb->sum_collected->sum_size 
							+ JFFS2_SUMMARY_FRAME_SIZE);
				D1(printk(KERN_DEBUG "JFFS2: minsize %d , jeb->free(%d) , sum_collected->size(%d) , sumsize(%d)\n",minsize,jeb->free_size,jeb->sum_collected->sum_size,sumsize));
			}
		
		if (jeb && (PAD(minsize) + PAD(jeb->sum_collected->sum_size + sumsize + JFFS2_SUMMARY_FRAME_SIZE) > jeb->free_size)) {
			D1(printk(KERN_DEBUG "JFFS2: generating summary for 0x%08x.\n", jeb->offset));
			if (jeb->sum_collected->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) {
				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
				jffs2_sum_clean_collected(jeb);
				goto restart;
			}
			
			ret = jffs2_sum_write_sumnode(c);
			
			if (ret)
				return ret;
			
			if (jeb->sum_collected->sum_size == JFFS2_SUMMARY_NOSUM_SIZE) { //jffs2_write_sumnode can't write out the summary information
				sumsize = JFFS2_SUMMARY_NOSUM_SIZE;
				jffs2_sum_clean_collected(jeb);
				goto restart;
			}
			
			/* Check, if we have a dirty block now, or if it was dirty already */
			if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
				c->dirty_size += jeb->wasted_size;
				c->wasted_size -= jeb->wasted_size;
				jeb->dirty_size += jeb->wasted_size;
				jeb->wasted_size = 0;
				if (VERYDIRTY(c, jeb->dirty_size)) {
					D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
					  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
					list_add_tail(&jeb->list, &c->very_dirty_list);
				} else {
					D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
					  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
					list_add_tail(&jeb->list, &c->dirty_list);
				}
			} else { 
				D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
				  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
				list_add_tail(&jeb->list, &c->clean_list);
			}
			c->nextblock = jeb = NULL;
		}
	}
	else {	
#endif			
		if (jeb && minsize > jeb->free_size) {
			/* Skip the end of this block and file it as having some dirty space */
			/* If there's a pending write to it, flush now */
			
			if (jffs2_wbuf_dirty(c)) {
				spin_unlock(&c->erase_completion_lock);
				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));			    
				jffs2_flush_wbuf_pad(c);
				spin_lock(&c->erase_completion_lock);
				jeb = c->nextblock;
				goto restart;
			}
			
			c->wasted_size += jeb->free_size;
			c->free_size -= jeb->free_size;
			jeb->wasted_size += jeb->free_size;
			jeb->free_size = 0;
			
			/* Check, if we have a dirty block now, or if it was dirty already */
			if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) {
				c->dirty_size += jeb->wasted_size;
				c->wasted_size -= jeb->wasted_size;
				jeb->dirty_size += jeb->wasted_size;
				jeb->wasted_size = 0;
				if (VERYDIRTY(c, jeb->dirty_size)) {
					D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to very_dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
					  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
					list_add_tail(&jeb->list, &c->very_dirty_list);
				} else {
					D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
					  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
					list_add_tail(&jeb->list, &c->dirty_list);
				}
			} else { 
				D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
				  jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
				list_add_tail(&jeb->list, &c->clean_list);
			}
			c->nextblock = jeb = NULL;
		}
#ifdef CONFIG_JFFS2_SUMMARY
	}
#endif	
	if (!jeb) {
		struct list_head *next;
		/* Take the next block off the 'free' list */

		if (list_empty(&c->free_list)) {

			if (!c->nr_erasing_blocks && 
			    !list_empty(&c->erasable_list)) {
				struct jffs2_eraseblock *ejeb;

				ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list);
				list_del(&ejeb->list);
				list_add_tail(&ejeb->list, &c->erase_pending_list);
				c->nr_erasing_blocks++;
				jffs2_erase_pending_trigger(c);
				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n",
					  ejeb->offset));
			}

			if (!c->nr_erasing_blocks && 
			    !list_empty(&c->erasable_pending_wbuf_list)) {
				D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n"));
				/* c->nextblock is NULL, no update to c->nextblock allowed */			    
				spin_unlock(&c->erase_completion_lock);
				jffs2_flush_wbuf_pad(c);
				spin_lock(&c->erase_completion_lock);
				/* Have another go. It'll be on the erasable_list now */
				return -EAGAIN;
			}

			if (!c->nr_erasing_blocks) {
				/* Ouch. We're in GC, or we wouldn't have got here.
				   And there's no space left. At all. */
				printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", 
				       c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", 
				       list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no");
				return -ENOSPC;
			}

			spin_unlock(&c->erase_completion_lock);
			/* Don't wait for it; just erase one right now */
			jffs2_erase_pending_blocks(c, 1);
			spin_lock(&c->erase_completion_lock);

			/* An erase may have failed, decreasing the
			   amount of free space available. So we must
			   restart from the beginning */
			return -EAGAIN;
		}

		next = c->free_list.next;
		list_del(next);
		c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list);
		c->nr_free_blocks--;

		if (jeb->free_size != c->sector_size - c->cleanmarker_size) {
			printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size);
			goto restart;
		}
	}
	/* OK, jeb (==c->nextblock) is now pointing at a block which definitely has
	   enough space */
	*ofs = jeb->offset + (c->sector_size - jeb->free_size);
	*len = jeb->free_size - nofree_size;

	if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size &&
	    !jeb->first_node->next_in_ino) {
		/* Only node in it beforehand was a CLEANMARKER node (we think). 
		   So mark it obsolete now that there's going to be another node
		   in the block. This will reduce used_size to zero but We've 
		   already set c->nextblock so that jffs2_mark_node_obsolete()
		   won't try to refile it to the dirty_list.
		*/
		spin_unlock(&c->erase_completion_lock);
		jffs2_mark_node_obsolete(c, jeb->first_node);
		spin_lock(&c->erase_completion_lock);
	}

	D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs));
	return 0;
}
Beispiel #21
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 #22
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 #23
0
int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio)
{
	int ret = -EAGAIN;
	int blocksneeded = c->resv_blocks_write;
	/* align it */
	minsize = PAD(minsize);

	D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize));
	down(&c->alloc_sem);

	D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n"));

	spin_lock(&c->erase_completion_lock);

	/* this needs a little more thought (true <tglx> :)) */
	while(ret == -EAGAIN) {
		while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) {
			int ret;
			uint32_t dirty, avail;

			/* calculate real dirty size
			 * dirty_size contains blocks on erase_pending_list
			 * those blocks are counted in c->nr_erasing_blocks.
			 * If one block is actually erased, it is not longer counted as dirty_space
			 * but it is counted in c->nr_erasing_blocks, so we add it and subtract it
			 * with c->nr_erasing_blocks * c->sector_size again.
			 * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks
			 * This helps us to force gc and pick eventually a clean block to spread the load.
			 * We add unchecked_size here, as we hopefully will find some space to use.
			 * This will affect the sum only once, as gc first finishes checking
			 * of nodes.
			 */
			dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
			if (dirty < c->nospc_dirty_size) {
				if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
					printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
					break;
				}
				D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
					  dirty, c->unchecked_size, c->sector_size));

				spin_unlock(&c->erase_completion_lock);
				up(&c->alloc_sem);
				return -ENOSPC;
			}
			
			/* Calc possibly available space. Possibly available means that we
			 * don't know, if unchecked size contains obsoleted nodes, which could give us some
			 * more usable space. This will affect the sum only once, as gc first finishes checking
			 * of nodes.
			 + Return -ENOSPC, if the maximum possibly available space is less or equal than 
			 * blocksneeded * sector_size.
			 * This blocks endless gc looping on a filesystem, which is nearly full, even if
			 * the check above passes.
			 */
			avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
			if ( (avail / c->sector_size) <= blocksneeded) {
				if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
					printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
					break;
				}

				D1(printk(KERN_DEBUG "max. available size 0x%08x  < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n",
					  avail, blocksneeded * c->sector_size));
				spin_unlock(&c->erase_completion_lock);
				up(&c->alloc_sem);
				return -ENOSPC;
			}

			up(&c->alloc_sem);

			D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n",
				  c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size,
				  c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size));
			spin_unlock(&c->erase_completion_lock);
			
			ret = jffs2_garbage_collect_pass(c);
			if (ret)
				return ret;

			cond_resched();

			if (signal_pending(current))
				return -EINTR;

			down(&c->alloc_sem);
			spin_lock(&c->erase_completion_lock);
		}

		ret = jffs2_do_reserve_space(c, minsize, ofs, len);
		if (ret) {
			D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret));
		}
	}
	spin_unlock(&c->erase_completion_lock);
	if (ret)
		up(&c->alloc_sem);
	return ret;
}
Beispiel #24
0
/* Process the summary node - called from jffs2_scan_eraseblock() */
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
			   struct jffs2_raw_summary *summary, uint32_t sumsize,
			   uint32_t *pseudo_random)
{
	struct jffs2_unknown_node crcnode;
	int ret, ofs;
	uint32_t crc;

	ofs = c->sector_size - sumsize;

	dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
		    jeb->offset, jeb->offset + ofs, sumsize);

	/* OK, now check for node validity and CRC */
	crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
	crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
	crcnode.totlen = summary->totlen;
	crc = crc32(0, &crcnode, sizeof(crcnode)-4);

	if (je32_to_cpu(summary->hdr_crc) != crc) {
		dbg_summary("Summary node header is corrupt (bad CRC or "
				"no summary at all)\n");
		goto crc_err;
	}

	if (je32_to_cpu(summary->totlen) != sumsize) {
		dbg_summary("Summary node is corrupt (wrong erasesize?)\n");
		goto crc_err;
	}

	crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8);

	if (je32_to_cpu(summary->node_crc) != crc) {
		dbg_summary("Summary node is corrupt (bad CRC)\n");
		goto crc_err;
	}

	crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary));

	if (je32_to_cpu(summary->sum_crc) != crc) {
		dbg_summary("Summary node data is corrupt (bad CRC)\n");
		goto crc_err;
	}

	if ( je32_to_cpu(summary->cln_mkr) ) {

		dbg_summary("Summary : CLEANMARKER node \n");

		ret = jffs2_prealloc_raw_node_refs(c, jeb, 1);
		if (ret)
			return ret;

		if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
			dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
				je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
			if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
				return ret;
		} else if (jeb->first_node) {
			dbg_summary("CLEANMARKER node not first node in block "
					"(0x%08x)\n", jeb->offset);
			if ((ret = jffs2_scan_dirty_space(c, jeb, PAD(je32_to_cpu(summary->cln_mkr)))))
				return ret;
		} else {
			jffs2_link_node_ref(c, jeb, jeb->offset | REF_NORMAL,
					    je32_to_cpu(summary->cln_mkr), NULL);
		}
	}

	ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
	/* -ENOTRECOVERABLE isn't a fatal error -- it means we should do a full
	   scan of this eraseblock. So return zero */
	if (ret == -ENOTRECOVERABLE)
		return 0;
	if (ret)
		return ret;		/* real error */

	/* for PARANOIA_CHECK */
	ret = jffs2_prealloc_raw_node_refs(c, jeb, 2);
	if (ret)
		return ret;

	sum_link_node_ref(c, jeb, ofs | REF_NORMAL, sumsize, NULL);

	if (unlikely(jeb->free_size)) {
		JFFS2_WARNING("Free size 0x%x bytes in eraseblock @0x%08x with summary?\n",
			      jeb->free_size, jeb->offset);
		jeb->wasted_size += jeb->free_size;
		c->wasted_size += jeb->free_size;
		c->free_size -= jeb->free_size;
		jeb->free_size = 0;
	}

	return jffs2_scan_classify_jeb(c, jeb);

crc_err:
	JFFS2_WARNING("Summary node crc error, skipping summary information.\n");

	return 0;
}
Beispiel #25
0
/*
 * RB_TakeVideoFrameCmd
 */
const void *
RB_TakeVideoFrameCmd(const void *data)
{
	const videoFrameCommand_t *cmd;
	byte *cBuf;
	size_t	memcount, linelen;
	int	padwidth, avipadwidth, padlen, avipadlen;
	GLint	packAlign;

	cmd = (const videoFrameCommand_t*)data;

	qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign);

	linelen = cmd->width * 3;

	/* Alignment stuff for glReadPixels */
	padwidth	= PAD(linelen, packAlign);
	padlen		= padwidth - linelen;
	/* AVI line padding */
	avipadwidth	= PAD(linelen, AVI_LINE_PADDING);
	avipadlen	= avipadwidth - linelen;

	cBuf = PADP(cmd->captureBuffer, packAlign);

	qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB,
		GL_UNSIGNED_BYTE, cBuf);

	memcount = padwidth * cmd->height;

	/* gamma correct */
	if(glConfig.deviceSupportsGamma)
		R_GammaCorrect(cBuf, memcount);

	if(cmd->motionJpeg){
		memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height,
			r_aviMotionJpegQuality->integer,
			cmd->width, cmd->height, cBuf, padlen);
		ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount);
	}else{
		byte	*lineend, *memend;
		byte	*srcptr, *destptr;

		srcptr	= cBuf;
		destptr = cmd->encodeBuffer;
		memend	= srcptr + memcount;

		/* swap R and B and remove line paddings */
		while(srcptr < memend){
			lineend = srcptr + linelen;
			while(srcptr < lineend){
				*destptr++	= srcptr[2];
				*destptr++	= srcptr[1];
				*destptr++	= srcptr[0];
				srcptr += 3;
			}

			Q_Memset(destptr, '\0', avipadlen);
			destptr += avipadlen;

			srcptr += padlen;
		}

		ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height);
	}

	return (const void*)(cmd + 1);
}
Beispiel #26
0
/* dotneato_postprocess:
 * Set graph and cluster label positions.
 * Add space for root graph label and translate graph accordingly.
 * Set final nodesize using ns.
 * Assumes the boxes of all clusters have been computed.
 * When done, the bounding box of g has LL at origin.
 */
void dotneato_postprocess(Agraph_t * g)
{
    int diff;
    pointf dimen;
    point d = { 0, 0 };

    Rankdir = GD_rankdir(g);
    Flip = GD_flip(g);
    if (Flip)
	place_flip_graph_label(g);
    else
	place_graph_label(g);

    if (GD_label(g) && !GD_label(g)->set) {
	dimen = GD_label(g)->dimen;
	PAD(dimen);
	PF2P(dimen, d);
	if (Flip) {
	    if (GD_label_pos(g) & LABEL_AT_TOP) {
		GD_bb(g).UR.x += d.y;
	    } else {
		GD_bb(g).LL.x -= d.y;
	    }

	    if (d.x > GD_bb(g).UR.y - GD_bb(g).LL.y) {
		diff = d.x - (GD_bb(g).UR.y - GD_bb(g).LL.y);
		diff = diff / 2;
		GD_bb(g).LL.y -= diff;
		GD_bb(g).UR.y += diff;
	    }
	} else {
	    if (GD_label_pos(g) & LABEL_AT_TOP) {
		if (Rankdir == RANKDIR_TB)
		    GD_bb(g).UR.y += d.y;
		else
		    GD_bb(g).LL.y -= d.y;
	    } else {
		if (Rankdir == RANKDIR_TB)
		    GD_bb(g).LL.y -= d.y;
		else
		    GD_bb(g).UR.y += d.y;
	    }

	    if (d.x > GD_bb(g).UR.x - GD_bb(g).LL.x) {
		diff = d.x - (GD_bb(g).UR.x - GD_bb(g).LL.x);
		diff = diff / 2;
		GD_bb(g).LL.x -= diff;
		GD_bb(g).UR.x += diff;
	    }
	}
    }
    switch (Rankdir) {
    case RANKDIR_TB:
	Offset = GD_bb(g).LL;
	break;
    case RANKDIR_LR:
	Offset = pointof(-GD_bb(g).UR.y, GD_bb(g).LL.x);
	break;
    case RANKDIR_BT:
	Offset = pointof(GD_bb(g).LL.x, -GD_bb(g).UR.y);
	break;
    case RANKDIR_RL:
	Offset = pointof(GD_bb(g).LL.y, GD_bb(g).LL.x);
	break;
    }
    translate_drawing(g);
    if (GD_label(g) && !GD_label(g)->set)
	place_root_label(g, d);

    if (Show_boxes) {
	char buf[BUFSIZ];
	if (Flip)
	    sprintf(buf, M2, Offset.x, Offset.y, Offset.x, Offset.y);
	else
	    sprintf(buf, M1, Offset.y, Offset.x, Offset.y, Offset.x, 
                 -Offset.x, -Offset.y);
	Show_boxes[0] = strdup(buf);
    }
}
Beispiel #27
0
/*
==================
RB_TakeVideoFrameCmd
==================
*/
const void     *RB_TakeVideoFrameCmd( const void *data )
{
	const videoFrameCommand_t *cmd;
	GLint                     packAlign;
	int                       lineLen, captureLineLen;
	byte                      *pixels;
	int                       i;
	int                       outputSize;
	int                       j;
	int                       aviLineLen;

	cmd = ( const videoFrameCommand_t * ) data;

	// RB: it is possible to we still have a videoFrameCommand_t but we already stopped
	// video recording
	if ( ri.CL_VideoRecording() )
	{
		// take care of alignment issues for reading RGB images..

		glGetIntegerv( GL_PACK_ALIGNMENT, &packAlign );

		lineLen = cmd->width * 3;
		captureLineLen = PAD( lineLen, packAlign );

		pixels = ( byte * ) PADP( cmd->captureBuffer, packAlign );
		glReadPixels( 0, 0, cmd->width, cmd->height, GL_RGB, GL_UNSIGNED_BYTE, pixels );

		if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma )
		{
			// this also runs over the padding...
			R_GammaCorrect( pixels, captureLineLen * cmd->height );
		}

		if ( cmd->motionJpeg )
		{
			// Drop alignment and line padding bytes
			for ( i = 0; i < cmd->height; ++i )
			{
				memmove( cmd->captureBuffer + i * lineLen, pixels + i * captureLineLen, lineLen );
			}

			outputSize = SaveJPGToBuffer( cmd->encodeBuffer, 3 * cmd->width * cmd->height, 90, cmd->width, cmd->height, cmd->captureBuffer );
			ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, outputSize );
		}
		else
		{
			aviLineLen = PAD( lineLen, AVI_LINE_PADDING );

			for ( i = 0; i < cmd->height; ++i )
			{
				for ( j = 0; j < lineLen; j += 3 )
				{
					cmd->encodeBuffer[ i * aviLineLen + j + 0 ] = pixels[ i * captureLineLen + j + 2 ];
					cmd->encodeBuffer[ i * aviLineLen + j + 1 ] = pixels[ i * captureLineLen + j + 1 ];
					cmd->encodeBuffer[ i * aviLineLen + j + 2 ] = pixels[ i * captureLineLen + j + 0 ];
				}

				while ( j < aviLineLen )
				{
					cmd->encodeBuffer[ i * aviLineLen + j++ ] = 0;
				}
			}

			ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, aviLineLen * cmd->height );
		}
	}

	return ( const void * )( cmd + 1 );
}
Beispiel #28
0
static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
{
	struct jffs2_inode_info *f, *dir_f;
	struct jffs2_sb_info *c;
	struct inode *inode;
	struct jffs2_raw_inode *ri;
	struct jffs2_raw_dirent *rd;
	struct jffs2_full_dnode *fn;
	struct jffs2_full_dirent *fd;
	int namelen;
	uint32_t alloclen, phys_ofs;
	uint32_t writtenlen;
	int ret;

	mode |= S_IFDIR;

	ri = jffs2_alloc_raw_inode();
	if (!ri)
		return -ENOMEM;
	
	c = JFFS2_SB_INFO(dir_i->i_sb);

	/* Try to reserve enough space for both node and dirent. 
	 * Just the node will do for now, though 
	 */
	namelen = dentry->d_name.len;
	ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL);

	if (ret) {
		jffs2_free_raw_inode(ri);
		return ret;
	}

	inode = jffs2_new_inode(dir_i, mode, ri);

	if (IS_ERR(inode)) {
		jffs2_free_raw_inode(ri);
		jffs2_complete_reservation(c);
		return PTR_ERR(inode);
	}

	inode->i_op = &jffs2_dir_inode_operations;
	inode->i_fop = &jffs2_dir_operations;
	/* Directories get nlink 2 at start */
	inode->i_nlink = 2;

	f = JFFS2_INODE_INFO(inode);

	ri->data_crc = cpu_to_je32(0);
	ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
	
	fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen);

	jffs2_free_raw_inode(ri);

	if (IS_ERR(fn)) {
		/* Eeek. Wave bye bye */
		up(&f->sem);
		jffs2_complete_reservation(c);
		jffs2_clear_inode(inode);
		return PTR_ERR(fn);
	}
	/* No data here. Only a metadata node, which will be 
	   obsoleted by the first data write
	*/
	f->metadata = fn;
	up(&f->sem);

	/* Work out where to put the dirent node now. */
	writtenlen = PAD(writtenlen);
	phys_ofs += writtenlen;
	alloclen -= writtenlen;

	if (alloclen < sizeof(*rd)+namelen) {
		/* Not enough space left in this chunk. Get some more */
		jffs2_complete_reservation(c);
		ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL);
		if (ret) {
			/* Eep. */
			jffs2_clear_inode(inode);
			return ret;
		}
	}
	
	rd = jffs2_alloc_raw_dirent();
	if (!rd) {
		/* Argh. Now we treat it like a normal delete */
		jffs2_complete_reservation(c);
		jffs2_clear_inode(inode);
		return -ENOMEM;
	}

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

	rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
	rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);
	rd->totlen = cpu_to_je32(sizeof(*rd) + namelen);
	rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4));

	rd->pino = cpu_to_je32(dir_i->i_ino);
	rd->version = cpu_to_je32(++dir_f->highest_version);
	rd->ino = cpu_to_je32(inode->i_ino);
	rd->mctime = cpu_to_je32(get_seconds());
	rd->nsize = namelen;
	rd->type = DT_DIR;
	rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
	rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen));

	fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen);
	
	if (IS_ERR(fd)) {
		/* dirent failed to write. Delete the inode normally 
		   as if it were the final unlink() */
		jffs2_complete_reservation(c);
		jffs2_free_raw_dirent(rd);
		up(&dir_f->sem);
		jffs2_clear_inode(inode);
		return PTR_ERR(fd);
	}

	dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
	dir_i->i_nlink++;

	jffs2_free_raw_dirent(rd);

	/* Link the fd into the inode's list, obsoleting an old
	   one if necessary. */
	jffs2_add_fd_to_list(c, fd, &dir_f->dents);

	up(&dir_f->sem);
	jffs2_complete_reservation(c);

	d_instantiate(dentry, inode);
	return 0;
}
Beispiel #29
0
int jffs2_sum_scan_sumnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,
				uint32_t ofs, uint32_t *pseudo_random)
{
	struct jffs2_unknown_node crcnode;
	struct jffs2_raw_node_ref *cache_ref;
	struct jffs2_raw_summary *summary;
	int ret, sumsize;
	uint32_t crc;

	sumsize = c->sector_size - ofs;
	ofs += jeb->offset;

	dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n",
				jeb->offset, ofs, sumsize);

	summary = kmalloc(sumsize, GFP_KERNEL);

	if (!summary) {
		return -ENOMEM;
	}

	ret = jffs2_fill_scan_buf(c, (unsigned char *)summary, ofs, sumsize);

	if (ret) {
		kfree(summary);
		return ret;
	}

	/* OK, now check for node validity and CRC */
	crcnode.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
	crcnode.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
	crcnode.totlen = summary->totlen;
	crc = crc32(0, &crcnode, sizeof(crcnode)-4);

	if (je32_to_cpu(summary->hdr_crc) != crc) {
		dbg_summary("Summary node header is corrupt (bad CRC or "
				"no summary at all)\n");
		goto crc_err;
	}

	if (je32_to_cpu(summary->totlen) != sumsize) {
		dbg_summary("Summary node is corrupt (wrong erasesize?)\n");
		goto crc_err;
	}

	crc = crc32(0, summary, sizeof(struct jffs2_raw_summary)-8);

	if (je32_to_cpu(summary->node_crc) != crc) {
		dbg_summary("Summary node is corrupt (bad CRC)\n");
		goto crc_err;
	}

	crc = crc32(0, summary->sum, sumsize - sizeof(struct jffs2_raw_summary));

	if (je32_to_cpu(summary->sum_crc) != crc) {
		dbg_summary("Summary node data is corrupt (bad CRC)\n");
		goto crc_err;
	}

	if ( je32_to_cpu(summary->cln_mkr) ) {

		dbg_summary("Summary : CLEANMARKER node \n");

		if (je32_to_cpu(summary->cln_mkr) != c->cleanmarker_size) {
			dbg_summary("CLEANMARKER node has totlen 0x%x != normal 0x%x\n",
				je32_to_cpu(summary->cln_mkr), c->cleanmarker_size);
			UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
		} else if (jeb->first_node) {
			dbg_summary("CLEANMARKER node not first node in block "
					"(0x%08x)\n", jeb->offset);
			UNCHECKED_SPACE(PAD(je32_to_cpu(summary->cln_mkr)));
		} else {
			struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref();

			if (!marker_ref) {
				JFFS2_NOTICE("Failed to allocate node ref for clean marker\n");
				kfree(summary);
				return -ENOMEM;
			}

			marker_ref->next_in_ino = NULL;
			marker_ref->next_phys = NULL;
			marker_ref->flash_offset = jeb->offset | REF_NORMAL;
			marker_ref->__totlen = je32_to_cpu(summary->cln_mkr);
			jeb->first_node = jeb->last_node = marker_ref;

			USED_SPACE( PAD(je32_to_cpu(summary->cln_mkr)) );
		}
	}

	if (je32_to_cpu(summary->padded)) {
		DIRTY_SPACE(je32_to_cpu(summary->padded));
	}

	ret = jffs2_sum_process_sum_data(c, jeb, summary, pseudo_random);
	if (ret)
		return ret;

	/* for PARANOIA_CHECK */
	cache_ref = jffs2_alloc_raw_node_ref();

	if (!cache_ref) {
		JFFS2_NOTICE("Failed to allocate node ref for cache\n");
		return -ENOMEM;
	}

	cache_ref->next_in_ino = NULL;
	cache_ref->next_phys = NULL;
	cache_ref->flash_offset = ofs | REF_NORMAL;
	cache_ref->__totlen = sumsize;

	if (!jeb->first_node)
		jeb->first_node = cache_ref;
	if (jeb->last_node)
		jeb->last_node->next_phys = cache_ref;
	jeb->last_node = cache_ref;

	USED_SPACE(sumsize);

	jeb->wasted_size += jeb->free_size;
	c->wasted_size += jeb->free_size;
	c->free_size -= jeb->free_size;
	jeb->free_size = 0;

	return jffs2_scan_classify_jeb(c, jeb);

crc_err:
	JFFS2_WARNING("Summary node crc error, skipping summary information.\n");

	return 0;
}
Beispiel #30
0
 *	@c: superblock info
 *	@ofs: physical location of this physical node
 *	@len: length of this physical node
 *	@ino: inode number with which this physical node is associated
 *
 *	Should only be used to report nodes for which space has been allocated 
 *	by jffs2_reserve_space.
 *
 *	Must be called with the alloc_sem held.
 */
 
int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty)
{
	struct jffs2_eraseblock *jeb;

	len = PAD(len);
	jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size];
	D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len));
#if 1
	if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) {
		printk(KERN_WARNING "argh. node added in wrong place\n");
		jffs2_free_raw_node_ref(new);
		return -EINVAL;
	}
#endif
	if (!jeb->first_node)
		jeb->first_node = new;
	if (jeb->last_node)
		jeb->last_node->next_phys = new;
	jeb->last_node = new;