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

📄 gc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	return ret;}static int jffs2_garbage_collect_live(struct jffs2_sb_info *c,  struct jffs2_eraseblock *jeb,				      struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f){	struct jffs2_node_frag *frag;	struct jffs2_full_dnode *fn = NULL;	struct jffs2_full_dirent *fd;	uint32_t start = 0, end = 0, nrfrags = 0;	int ret = 0;	down(&f->sem);	/* Now we have the lock for this inode. Check that it's still the one at the head	   of the list. */	spin_lock(&c->erase_completion_lock);	if (c->gcblock != jeb) {		spin_unlock(&c->erase_completion_lock);		D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n"));		goto upnout;	}	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 {			jffs2_dbg_dump_node(c, ref_offset(raw));			BUG();		}	} 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;	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)));	alloclen = 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. */	if (ic && alloclen > sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN)		alloclen = sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN;	ret = jffs2_reserve_space_gc(c, alloclen, &alloclen, rawlen);	/* 'rawlen' is not the exact summary size; it is only an upper estimation */	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 (strnlen(node->d.name, node->d.nsize) != node->d.nsize) {			printk(KERN_WARNING "Name in dirent node at 0x%08x contains zeroes\n", ref_offset(raw));			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 node 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:		/* If it's inode-less, we don't _know_ what it is. Just copy it intact */		if (ic) {			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;		}	}	/* OK, all the CRCs are good; this node can just be copied as-is. */ retry:	phys_ofs = write_ofs(c);	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) {			jffs2_add_physical_node_ref(c, phys_ofs | REF_OBSOLETE, rawlen, NULL);		} else {			printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", phys_ofs);		}		if (!retried) {			/* 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"));			jffs2_dbg_acct_sanity_check(c,jeb);			jffs2_dbg_acct_paranoia_check(c, jeb);			ret = jffs2_reserve_space_gc(c, rawlen, &dummy, rawlen);						/* this is not the exact summary size of it,							it is only an upper estimation */			if (!ret) {				D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs));				jffs2_dbg_acct_sanity_check(c,jeb);				jffs2_dbg_acct_paranoia_check(c, jeb);				goto retry;			}			D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret));		}		if (!ret)			ret = -EIO;		goto out_node;	}	jffs2_add_physical_node_ref(c, phys_ofs | REF_PRISTINE, rawlen, ic);	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;	struct jffs2_node_frag *last_frag;	union jffs2_device_node dev;	char *mdata = NULL, mdatalen = 0;	uint32_t alloclen, ilen;	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 */		mdatalen = jffs2_encode_dev(&dev, JFFS2_F_I_RDEV(f));		mdata = (char *)&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, &alloclen,				JFFS2_SUMMARY_INODE_SIZE);	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;	}	last_frag = frag_last(&f->fragtree);	if (last_frag)		/* Fetch the inode length from the fragtree rather then		 * from i_size since i_size may have not been updated yet */		ilen = last_frag->ofs + last_frag->size;	else		ilen = JFFS2_F_I_SIZE(f);	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(ilen);	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, 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;	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);	/* If the times on this inode were set by explicit utime() they can be different,	   so refrain from splatting them. */	if (JFFS2_F_I_MTIME(f) == JFFS2_F_I_CTIME(f))		rd.mctime = cpu_to_je32(JFFS2_F_I_MTIME(f));	else		rd.mctime = cpu_to_je32(0);	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, &alloclen,				JFFS2_SUMMARY_DIRENT_SIZE(rd.nsize));	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, 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) {			cond_resched();			/* 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 (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))				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

⌨️ 快捷键说明

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