⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readinode.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	size_t retlen;	int len, err;	rii->mctime_ver = 0;	dbg_readinode("ino #%u\n", f->inocache->ino);	/* FIXME: in case of NOR and available ->point() this	 * needs to be fixed. */	len = sizeof(union jffs2_node_union) + c->wbuf_pagesize;	buf = kmalloc(len, GFP_KERNEL);	if (!buf)		return -ENOMEM;	spin_lock(&c->erase_completion_lock);	valid_ref = jffs2_first_valid_node(f->inocache->nodes);	if (!valid_ref && f->inocache->ino != 1)		JFFS2_WARNING("Eep. No valid nodes for ino #%u.\n", f->inocache->ino);	while (valid_ref) {		/* We can hold a pointer to a non-obsolete node without the spinlock,		   but _obsolete_ nodes may disappear at any time, if the block		   they're in gets erased. So if we mark 'ref' obsolete while we're		   not holding the lock, it can go away immediately. For that reason,		   we find the next valid node first, before processing 'ref'.		*/		ref = valid_ref;		valid_ref = jffs2_first_valid_node(ref->next_in_ino);		spin_unlock(&c->erase_completion_lock);		cond_resched();		/*		 * At this point we don't know the type of the node we're going		 * to read, so we do not know the size of its header. In order		 * to minimize the amount of flash IO we assume the header is		 * of size = JFFS2_MIN_NODE_HEADER.		 */		len = JFFS2_MIN_NODE_HEADER;		if (jffs2_is_writebuffered(c)) {			int end, rem;			/*			 * We are about to read JFFS2_MIN_NODE_HEADER bytes,			 * but this flash has some minimal I/O unit. It is			 * possible that we'll need to read more soon, so read			 * up to the next min. I/O unit, in order not to			 * re-read the same min. I/O unit twice.			 */			end = ref_offset(ref) + len;			rem = end % c->wbuf_pagesize;			if (rem)				end += c->wbuf_pagesize - rem;			len = end - ref_offset(ref);		}		dbg_readinode("read %d bytes at %#08x(%d).\n", len, ref_offset(ref), ref_flags(ref));		/* FIXME: point() */		err = jffs2_flash_read(c, ref_offset(ref), len, &retlen, buf);		if (err) {			JFFS2_ERROR("can not read %d bytes from 0x%08x, " "error code: %d.\n", len, ref_offset(ref), err);			goto free_out;		}		if (retlen < len) {			JFFS2_ERROR("short read at %#08x: %zu instead of %d.\n", ref_offset(ref), retlen, len);			err = -EIO;			goto free_out;		}		node = (union jffs2_node_union *)buf;		/* No need to mask in the valid bit; it shouldn't be invalid */		if (je32_to_cpu(node->u.hdr_crc) != crc32(0, node, sizeof(node->u)-4)) {			JFFS2_NOTICE("Node header CRC failed at %#08x. {%04x,%04x,%08x,%08x}\n",				     ref_offset(ref), je16_to_cpu(node->u.magic),				     je16_to_cpu(node->u.nodetype),				     je32_to_cpu(node->u.totlen),				     je32_to_cpu(node->u.hdr_crc));			jffs2_dbg_dump_node(c, ref_offset(ref));			jffs2_mark_node_obsolete(c, ref);			goto cont;		}		if (je16_to_cpu(node->u.magic) != JFFS2_MAGIC_BITMASK) {			/* Not a JFFS2 node, whinge and move on */			JFFS2_NOTICE("Wrong magic bitmask 0x%04x in node header at %#08x.\n",				     je16_to_cpu(node->u.magic), ref_offset(ref));			jffs2_mark_node_obsolete(c, ref);			goto cont;		}		switch (je16_to_cpu(node->u.nodetype)) {		case JFFS2_NODETYPE_DIRENT:			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_dirent) &&			    len < sizeof(struct jffs2_raw_dirent)) {				err = read_more(c, ref, sizeof(struct jffs2_raw_dirent), &len, buf);				if (unlikely(err))					goto free_out;			}			err = read_direntry(c, ref, &node->d, retlen, rii);			if (unlikely(err))				goto free_out;			break;		case JFFS2_NODETYPE_INODE:			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_raw_inode) &&			    len < sizeof(struct jffs2_raw_inode)) {				err = read_more(c, ref, sizeof(struct jffs2_raw_inode), &len, buf);				if (unlikely(err))					goto free_out;			}			err = read_dnode(c, ref, &node->i, len, rii);			if (unlikely(err))				goto free_out;			break;		default:			if (JFFS2_MIN_NODE_HEADER < sizeof(struct jffs2_unknown_node) &&			    len < sizeof(struct jffs2_unknown_node)) {				err = read_more(c, ref, sizeof(struct jffs2_unknown_node), &len, buf);				if (unlikely(err))					goto free_out;			}			err = read_unknown(c, ref, &node->u);			if (unlikely(err))				goto free_out;		}	cont:		spin_lock(&c->erase_completion_lock);	}	spin_unlock(&c->erase_completion_lock);	kfree(buf);	f->highest_version = rii->highest_version;	dbg_readinode("nodes of inode #%u were read, the highest version is %u, latest_mctime %u, mctime_ver %u.\n",		      f->inocache->ino, rii->highest_version, rii->latest_mctime,		      rii->mctime_ver);	return 0; free_out:	jffs2_free_tmp_dnode_info_list(&rii->tn_root);	jffs2_free_full_dirent_list(rii->fds);	rii->fds = NULL;	kfree(buf);	return err;}static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,					struct jffs2_inode_info *f,					struct jffs2_raw_inode *latest_node){	struct jffs2_readinode_info rii;	uint32_t crc, new_size;	size_t retlen;	int ret;	dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);	memset(&rii, 0, sizeof(rii));	/* Grab all nodes relevant to this ino */	ret = jffs2_get_inode_nodes(c, f, &rii);	if (ret) {		JFFS2_ERROR("cannot read nodes for ino %u, returned error is %d\n", f->inocache->ino, ret);		if (f->inocache->state == INO_STATE_READING)			jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);		return ret;	}	ret = jffs2_build_inode_fragtree(c, f, &rii);	if (ret) {		JFFS2_ERROR("Failed to build final fragtree for inode #%u: error %d\n",			    f->inocache->ino, ret);		if (f->inocache->state == INO_STATE_READING)			jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);		jffs2_free_tmp_dnode_info_list(&rii.tn_root);		/* FIXME: We could at least crc-check them all */		if (rii.mdata_tn) {			jffs2_free_full_dnode(rii.mdata_tn->fn);			jffs2_free_tmp_dnode_info(rii.mdata_tn);			rii.mdata_tn = NULL;		}		return ret;	}	if (rii.mdata_tn) {		if (rii.mdata_tn->fn->raw == rii.latest_ref) {			f->metadata = rii.mdata_tn->fn;			jffs2_free_tmp_dnode_info(rii.mdata_tn);		} else {			jffs2_kill_tn(c, rii.mdata_tn);		}		rii.mdata_tn = NULL;	}	f->dents = rii.fds;	jffs2_dbg_fragtree_paranoia_check_nolock(f);	if (unlikely(!rii.latest_ref)) {		/* No data nodes for this inode. */		if (f->inocache->ino != 1) {			JFFS2_WARNING("no data nodes found for ino #%u\n", f->inocache->ino);			if (!rii.fds) {				if (f->inocache->state == INO_STATE_READING)					jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);				return -EIO;			}			JFFS2_NOTICE("but it has children so we fake some modes for it\n");		}		latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO);		latest_node->version = cpu_to_je32(0);		latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0);		latest_node->isize = cpu_to_je32(0);		latest_node->gid = cpu_to_je16(0);		latest_node->uid = cpu_to_je16(0);		if (f->inocache->state == INO_STATE_READING)			jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);		return 0;	}	ret = jffs2_flash_read(c, ref_offset(rii.latest_ref), sizeof(*latest_node), &retlen, (void *)latest_node);	if (ret || retlen != sizeof(*latest_node)) {		JFFS2_ERROR("failed to read from flash: error %d, %zd of %zd bytes read\n",			ret, retlen, sizeof(*latest_node));		/* FIXME: If this fails, there seems to be a memory leak. Find it. */		up(&f->sem);		jffs2_do_clear_inode(c, f);		return ret?ret:-EIO;	}	crc = crc32(0, latest_node, sizeof(*latest_node)-8);	if (crc != je32_to_cpu(latest_node->node_crc)) {		JFFS2_ERROR("CRC failed for read_inode of inode %u at physical location 0x%x\n",			f->inocache->ino, ref_offset(rii.latest_ref));		up(&f->sem);		jffs2_do_clear_inode(c, f);		return -EIO;	}	switch(jemode_to_cpu(latest_node->mode) & S_IFMT) {	case S_IFDIR:		if (rii.mctime_ver > je32_to_cpu(latest_node->version)) {			/* The times in the latest_node are actually older than			   mctime in the latest dirent. Cheat. */			latest_node->ctime = latest_node->mtime = cpu_to_je32(rii.latest_mctime);		}		break;	case S_IFREG:		/* If it was a regular file, truncate it to the latest node's isize */		new_size = jffs2_truncate_fragtree(c, &f->fragtree, je32_to_cpu(latest_node->isize));		if (new_size != je32_to_cpu(latest_node->isize)) {			JFFS2_WARNING("Truncating ino #%u to %d bytes failed because it only had %d bytes to start with!\n",				      f->inocache->ino, je32_to_cpu(latest_node->isize), new_size);			latest_node->isize = cpu_to_je32(new_size);		}		break;	case S_IFLNK:		/* Hack to work around broken isize in old symlink code.		   Remove this when dwmw2 comes to his senses and stops		   symlinks from being an entirely gratuitous special		   case. */		if (!je32_to_cpu(latest_node->isize))			latest_node->isize = latest_node->dsize;		if (f->inocache->state != INO_STATE_CHECKING) {			/* Symlink's inode data is the target path. Read it and			 * keep in RAM to facilitate quick follow symlink			 * operation. */			f->target = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);			if (!f->target) {				JFFS2_ERROR("can't allocate %d bytes of memory for the symlink target path cache\n", je32_to_cpu(latest_node->csize));				up(&f->sem);				jffs2_do_clear_inode(c, f);				return -ENOMEM;			}			ret = jffs2_flash_read(c, ref_offset(rii.latest_ref) + sizeof(*latest_node),						je32_to_cpu(latest_node->csize), &retlen, (char *)f->target);			if (ret  || retlen != je32_to_cpu(latest_node->csize)) {				if (retlen != je32_to_cpu(latest_node->csize))					ret = -EIO;				kfree(f->target);				f->target = NULL;				up(&f->sem);				jffs2_do_clear_inode(c, f);				return -ret;			}			f->target[je32_to_cpu(latest_node->csize)] = '\0';			dbg_readinode("symlink's target '%s' cached\n", f->target);		}		/* fall through... */	case S_IFBLK:	case S_IFCHR:		/* Certain inode types should have only one data node, and it's		   kept as the metadata node */		if (f->metadata) {			JFFS2_ERROR("Argh. Special inode #%u with mode 0%o had metadata node\n",			       f->inocache->ino, jemode_to_cpu(latest_node->mode));			up(&f->sem);			jffs2_do_clear_inode(c, f);			return -EIO;		}		if (!frag_first(&f->fragtree)) {			JFFS2_ERROR("Argh. Special inode #%u with mode 0%o has no fragments\n",			       f->inocache->ino, jemode_to_cpu(latest_node->mode));			up(&f->sem);			jffs2_do_clear_inode(c, f);			return -EIO;		}		/* ASSERT: f->fraglist != NULL */		if (frag_next(frag_first(&f->fragtree))) {			JFFS2_ERROR("Argh. Special inode #%u with mode 0x%x had more than one node\n",			       f->inocache->ino, jemode_to_cpu(latest_node->mode));			/* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */			up(&f->sem);			jffs2_do_clear_inode(c, f);			return -EIO;		}		/* OK. We're happy */		f->metadata = frag_first(&f->fragtree)->node;		jffs2_free_node_frag(frag_first(&f->fragtree));		f->fragtree = RB_ROOT;		break;	}	if (f->inocache->state == INO_STATE_READING)		jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT);	return 0;}/* Scan the list of all nodes present for this ino, build map of versions, etc. */int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,			uint32_t ino, struct jffs2_raw_inode *latest_node){	dbg_readinode("read inode #%u\n", ino); retry_inocache:	spin_lock(&c->inocache_lock);	f->inocache = jffs2_get_ino_cache(c, ino);	if (f->inocache) {		/* Check its state. We may need to wait before we can use it */		switch(f->inocache->state) {		case INO_STATE_UNCHECKED:		case INO_STATE_CHECKEDABSENT:			f->inocache->state = INO_STATE_READING;			break;		case INO_STATE_CHECKING:		case INO_STATE_GC:			/* If it's in either of these states, we need			   to wait for whoever's got it to finish and			   put it back. */			dbg_readinode("waiting for ino #%u in state %d\n", ino, f->inocache->state);			sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock);			goto retry_inocache;		case INO_STATE_READING:		case INO_STATE_PRESENT:			/* Eep. This should never happen. It can			happen if Linux calls read_inode() again			before clear_inode() has finished though. */			JFFS2_ERROR("Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state);			/* Fail. That's probably better than allowing it to succeed */			f->inocache = NULL;			break;		default:			BUG();		}	}	spin_unlock(&c->inocache_lock);	if (!f->inocache && ino == 1) {		/* Special case - no root inode on medium */		f->inocache = jffs2_alloc_inode_cache();		if (!f->inocache) {			JFFS2_ERROR("cannot allocate inocache for root inode\n");			return -ENOMEM;		}		dbg_readinode("creating inocache for root inode\n");		memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));		f->inocache->ino = f->inocache->nlink = 1;		f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;		f->inocache->state = INO_STATE_READING;		jffs2_add_ino_cache(c, f->inocache);	}	if (!f->inocache) {		JFFS2_ERROR("requestied to read an nonexistent ino %u\n", ino);		return -ENOENT;	}	return jffs2_do_read_inode_internal(c, f, latest_node);}int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic){	struct jffs2_raw_inode n;	struct jffs2_inode_info *f = kzalloc(sizeof(*f), GFP_KERNEL);	int ret;	if (!f)		return -ENOMEM;	init_MUTEX_LOCKED(&f->sem);	f->inocache = ic;	ret = jffs2_do_read_inode_internal(c, f, &n);	if (!ret) {		up(&f->sem);		jffs2_do_clear_inode(c, f);	}	kfree (f);	return ret;}void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f){	struct jffs2_full_dirent *fd, *fds;	int deleted;	jffs2_clear_acl(f);	jffs2_xattr_delete_inode(c, f->inocache);	down(&f->sem);	deleted = f->inocache && !f->inocache->nlink;	if (f->inocache && f->inocache->state != INO_STATE_CHECKING)		jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);	if (f->metadata) {		if (deleted)			jffs2_mark_node_obsolete(c, f->metadata->raw);		jffs2_free_full_dnode(f->metadata);	}	jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);	if (f->target) {		kfree(f->target);		f->target = NULL;	}	fds = f->dents;	while(fds) {		fd = fds;		fds = fd->next;		jffs2_free_full_dirent(fd);	}	if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {		jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);		if (f->inocache->nodes == (void *)f->inocache)			jffs2_del_ino_cache(c, f->inocache);	}	up(&f->sem);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -