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

📄 gc.c

📁 jffs2源代码基于2。6内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	if (ref_obsolete(raw)) {		spin_unlock(&c->erase_completion_lock);		D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n"));		/* They'll call again */		goto upnout;	}	spin_unlock(&c->erase_completion_lock);	/* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */	if (f->metadata && f->metadata->raw == raw) {		fn = f->metadata;		ret = jffs2_garbage_collect_metadata(c, jeb, f, fn);		goto upnout;	}	/* FIXME. Read node and do lookup? */	for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) {		if (frag->node && frag->node->raw == raw) {			fn = frag->node;			end = frag->ofs + frag->size;			if (!nrfrags++)				start = frag->ofs;			if (nrfrags == frag->node->frags)				break; /* We've found them all */		}	}	if (fn) {		if (ref_flags(raw) == REF_PRISTINE) {			ret = jffs2_garbage_collect_pristine(c, f->inocache, raw);			if (!ret) {				/* Urgh. Return it sensibly. */				frag->node->raw = f->inocache->nodes;			}				if (ret != -EBADFD)				goto upnout;		}		/* We found a datanode. Do the GC */		if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) {			/* It crosses a page boundary. Therefore, it must be a hole. */			ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end);		} else {			/* It could still be a hole. But we GC the page this way anyway */			ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end);		}		goto upnout;	}		/* Wasn't a dnode. Try dirent */	for (fd = f->dents; fd; fd=fd->next) {		if (fd->raw == raw)			break;	}	if (fd && fd->ino) {		ret = jffs2_garbage_collect_dirent(c, jeb, f, fd);	} else if (fd) {		ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd);	} else {		printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n",		       ref_offset(raw), f->inocache->ino);		if (ref_obsolete(raw)) {			printk(KERN_WARNING "But it's obsolete so we don't mind too much\n");		} else {			ret = -EIO;		}	} upnout:	up(&f->sem);	return ret;}static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, 					  struct jffs2_inode_cache *ic,					  struct jffs2_raw_node_ref *raw){	union jffs2_node_union *node;	struct jffs2_raw_node_ref *nraw;	size_t retlen;	int ret;	uint32_t phys_ofs, alloclen;	uint32_t crc, rawlen;	int retried = 0;	D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw)));	rawlen = ref_totlen(c, c->gcblock, raw);	/* Ask for a small amount of space (or the totlen if smaller) because we	   don't want to force wastage of the end of a block if splitting would	   work. */	ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, 					      rawlen), &phys_ofs, &alloclen);	if (ret)		return ret;	if (alloclen < rawlen) {		/* Doesn't fit untouched. We'll go the old route and split it */		return -EBADFD;	}	node = kmalloc(rawlen, GFP_KERNEL);	if (!node)               return -ENOMEM;	ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node);	if (!ret && retlen != rawlen)		ret = -EIO;	if (ret)		goto out_node;	crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4);	if (je32_to_cpu(node->u.hdr_crc) != crc) {		printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",		       ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc);		goto bail;	}	switch(je16_to_cpu(node->u.nodetype)) {	case JFFS2_NODETYPE_INODE:		crc = crc32(0, node, sizeof(node->i)-8);		if (je32_to_cpu(node->i.node_crc) != crc) {			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",			       ref_offset(raw), je32_to_cpu(node->i.node_crc), crc);			goto bail;		}		if (je32_to_cpu(node->i.dsize)) {			crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize));			if (je32_to_cpu(node->i.data_crc) != crc) {				printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",				       ref_offset(raw), je32_to_cpu(node->i.data_crc), crc);				goto bail;			}		}		break;	case JFFS2_NODETYPE_DIRENT:		crc = crc32(0, node, sizeof(node->d)-8);		if (je32_to_cpu(node->d.node_crc) != crc) {			printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n",			       ref_offset(raw), je32_to_cpu(node->d.node_crc), crc);			goto bail;		}		if (node->d.nsize) {			crc = crc32(0, node->d.name, node->d.nsize);			if (je32_to_cpu(node->d.name_crc) != crc) {				printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n",				       ref_offset(raw), je32_to_cpu(node->d.name_crc), crc);				goto bail;			}		}		break;	default:		printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", 		       ref_offset(raw), je16_to_cpu(node->u.nodetype));		goto bail;	}	nraw = jffs2_alloc_raw_node_ref();	if (!nraw) {		ret = -ENOMEM;		goto out_node;	}	/* OK, all the CRCs are good; this node can just be copied as-is. */ retry:	nraw->flash_offset = phys_ofs;	nraw->__totlen = rawlen;	nraw->next_phys = NULL;	ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node);	if (ret || (retlen != rawlen)) {		printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n",                       rawlen, phys_ofs, ret, retlen);		if (retlen) {                        /* Doesn't belong to any inode */			nraw->next_in_ino = NULL;			nraw->flash_offset |= REF_OBSOLETE;			jffs2_add_physical_node_ref(c, nraw);			jffs2_mark_node_obsolete(c, nraw);		} else {			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);                        jffs2_free_raw_node_ref(nraw);		}		if (!retried && (nraw == jffs2_alloc_raw_node_ref())) {			/* Try to reallocate space and retry */			uint32_t dummy;			struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];			retried = 1;			D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n"));						ACCT_SANITY_CHECK(c,jeb);			D1(ACCT_PARANOIA_CHECK(jeb));			ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy);			if (!ret) {				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));				ACCT_SANITY_CHECK(c,jeb);				D1(ACCT_PARANOIA_CHECK(jeb));				goto retry;			}			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));			jffs2_free_raw_node_ref(nraw);		}		if (!ret)			ret = -EIO;		goto out_node;	}	nraw->flash_offset |= REF_PRISTINE;	jffs2_add_physical_node_ref(c, nraw);	/* Link into per-inode list. This is safe because of the ic	   state being INO_STATE_GC. Note that if we're doing this	   for an inode which is in-code, the 'nraw' pointer is then	   going to be fetched from ic->nodes by our caller. */        nraw->next_in_ino = ic->nodes;        ic->nodes = nraw;	jffs2_mark_node_obsolete(c, raw);	D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); out_node:	kfree(node);	return ret; bail:	ret = -EBADFD;	goto out_node;}static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 					struct jffs2_inode_info *f, struct jffs2_full_dnode *fn){	struct jffs2_full_dnode *new_fn;	struct jffs2_raw_inode ri;	jint16_t dev;	char *mdata = NULL, mdatalen = 0;	uint32_t alloclen, phys_ofs;	int ret;	if (S_ISBLK(JFFS2_F_I_MODE(f)) ||	    S_ISCHR(JFFS2_F_I_MODE(f)) ) {		/* For these, we don't actually need to read the old node */		/* FIXME: for minor or major > 255. */		dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | 			JFFS2_F_I_RDEV_MIN(f)));		mdata = (char *)&dev;		mdatalen = sizeof(dev);		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen));	} else if (S_ISLNK(JFFS2_F_I_MODE(f))) {		mdatalen = fn->size;		mdata = kmalloc(fn->size, GFP_KERNEL);		if (!mdata) {			printk(KERN_WARNING "kmalloc of mdata failed in jffs2_garbage_collect_metadata()\n");			return -ENOMEM;		}		ret = jffs2_read_dnode(c, f, fn, mdata, 0, mdatalen);		if (ret) {			printk(KERN_WARNING "read of old metadata failed in jffs2_garbage_collect_metadata(): %d\n", ret);			kfree(mdata);			return ret;		}		D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bites of symlink target\n", mdatalen));	}		ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen);	if (ret) {		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n",		       sizeof(ri)+ mdatalen, ret);		goto out;	}		memset(&ri, 0, sizeof(ri));	ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);	ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);	ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen);	ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4));	ri.ino = cpu_to_je32(f->inocache->ino);	ri.version = cpu_to_je32(++f->highest_version);	ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));	ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));	ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));	ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));	ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));	ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));	ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));	ri.offset = cpu_to_je32(0);	ri.csize = cpu_to_je32(mdatalen);	ri.dsize = cpu_to_je32(mdatalen);	ri.compr = JFFS2_COMPR_NONE;	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));	ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen));	new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC);	if (IS_ERR(new_fn)) {		printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));		ret = PTR_ERR(new_fn);		goto out;	}	jffs2_mark_node_obsolete(c, fn->raw);	jffs2_free_full_dnode(fn);	f->metadata = new_fn; out:	if (S_ISLNK(JFFS2_F_I_MODE(f)))		kfree(mdata);	return ret;}static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 					struct jffs2_inode_info *f, struct jffs2_full_dirent *fd){	struct jffs2_full_dirent *new_fd;	struct jffs2_raw_dirent rd;	uint32_t alloclen, phys_ofs;	int ret;	rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);	rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT);	rd.nsize = strlen(fd->name);	rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize);	rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4));	rd.pino = cpu_to_je32(f->inocache->ino);	rd.version = cpu_to_je32(++f->highest_version);	rd.ino = cpu_to_je32(fd->ino);	rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f)));	rd.type = fd->type;	rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8));	rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize));		ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen);	if (ret) {		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n",		       sizeof(rd)+rd.nsize, ret);		return ret;	}	new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC);	if (IS_ERR(new_fd)) {		printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd));		return PTR_ERR(new_fd);	}	jffs2_add_fd_to_list(c, new_fd, &f->dents);	return 0;}static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 					struct jffs2_inode_info *f, struct jffs2_full_dirent *fd){	struct jffs2_full_dirent **fdp = &f->dents;	int found = 0;	/* On a medium where we can't actually mark nodes obsolete	   pernamently, such as NAND flash, we need to work out	   whether this deletion dirent is still needed to actively	   delete a 'real' dirent with the same name that's still	   somewhere else on the flash. */	if (!jffs2_can_mark_obsolete(c)) {		struct jffs2_raw_dirent *rd;		struct jffs2_raw_node_ref *raw;		int ret;		size_t retlen;		int name_len = strlen(fd->name);		uint32_t name_crc = crc32(0, fd->name, name_len);		uint32_t rawlen = ref_totlen(c, jeb, fd->raw);		rd = kmalloc(rawlen, GFP_KERNEL);		if (!rd)			return -ENOMEM;		/* Prevent the erase code from nicking the obsolete node refs while		   we're looking at them. I really don't like this extra lock but		   can't see any alternative. Suggestions on a postcard to... */		down(&c->erase_free_sem);		for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {			/* We only care about obsolete ones */			if (!(ref_obsolete(raw)))				continue;			/* Any dirent with the same name is going to have the same length... */			if (ref_totlen(c, NULL, raw) != rawlen)				continue;			/* Doesn't matter if there's one in the same erase block. We're going to 			   delete it too at the same time. */			if ((raw->flash_offset & ~(c->sector_size-1)) ==			    (fd->raw->flash_offset & ~(c->sector_size-1)))				continue;			D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));			/* This is an obsolete node belonging to the same directory, and it's of the right			   length. We need to take a closer look...*/			ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd);			if (ret) {				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw));				/* If we can't read it, we don't need to continue to obsolete it. Continue */				continue;			}			if (retlen != rawlen) {

⌨️ 快捷键说明

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