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

📄 gc.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			   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) {				printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %u) reading header from obsolete node at %08x\n",				       retlen, rawlen, ref_offset(raw));				continue;			}			if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT)				continue;			/* If the name CRC doesn't match, skip */			if (je32_to_cpu(rd->name_crc) != name_crc)				continue;			/* If the name length doesn't match, or it's another deletion dirent, skip */			if (rd->nsize != name_len || !je32_to_cpu(rd->ino))				continue;			/* OK, check the actual name now */			if (memcmp(rd->name, fd->name, name_len))				continue;			/* OK. The name really does match. There really is still an older node on			   the flash which our deletion dirent obsoletes. So we have to write out			   a new deletion dirent to replace it */			up(&c->erase_free_sem);			D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n",				  ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino)));			kfree(rd);			return jffs2_garbage_collect_dirent(c, jeb, f, fd);		}		up(&c->erase_free_sem);		kfree(rd);	}	/* FIXME: If we're deleting a dirent which contains the current mtime and ctime,	   we should update the metadata node with those times accordingly */	/* No need for it any more. Just mark it obsolete and remove it from the list */	while (*fdp) {		if ((*fdp) == fd) {			found = 1;			*fdp = fd->next;			break;		}		fdp = &(*fdp)->next;	}	if (!found) {		printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%u\n", fd->name, f->inocache->ino);	}	jffs2_mark_node_obsolete(c, fd->raw);	jffs2_free_full_dirent(fd);	return 0;}static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,				      struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,				      uint32_t start, uint32_t end){	struct jffs2_raw_inode ri;	struct jffs2_node_frag *frag;	struct jffs2_full_dnode *new_fn;	uint32_t alloclen, ilen;	int ret;	D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",		  f->inocache->ino, start, end));	memset(&ri, 0, sizeof(ri));	if(fn->frags > 1) {		size_t readlen;		uint32_t crc;		/* It's partially obsoleted by a later write. So we have to		   write it out again with the _same_ version as before */		ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri);		if (readlen != sizeof(ri) || ret) {			printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen);			goto fill;		}		if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) {			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n",			       ref_offset(fn->raw),			       je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE);			return -EIO;		}		if (je32_to_cpu(ri.totlen) != sizeof(ri)) {			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n",			       ref_offset(fn->raw),			       je32_to_cpu(ri.totlen), sizeof(ri));			return -EIO;		}		crc = crc32(0, &ri, sizeof(ri)-8);		if (crc != je32_to_cpu(ri.node_crc)) {			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n",			       ref_offset(fn->raw),			       je32_to_cpu(ri.node_crc), crc);			/* FIXME: We could possibly deal with this by writing new holes for each frag */			printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",			       start, end, f->inocache->ino);			goto fill;		}		if (ri.compr != JFFS2_COMPR_ZERO) {			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw));			printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n",			       start, end, f->inocache->ino);			goto fill;		}	} else {	fill:		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);		ri.totlen = cpu_to_je32(sizeof(ri));		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.offset = cpu_to_je32(start);		ri.dsize = cpu_to_je32(end - start);		ri.csize = cpu_to_je32(0);		ri.compr = JFFS2_COMPR_ZERO;	}	frag = frag_last(&f->fragtree);	if (frag)		/* Fetch the inode length from the fragtree rather then		 * from i_size since i_size may have not been updated yet */		ilen = frag->ofs + frag->size;	else		ilen = JFFS2_F_I_SIZE(f);	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.data_crc = cpu_to_je32(0);	ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));	ret = jffs2_reserve_space_gc(c, sizeof(ri), &alloclen,				     JFFS2_SUMMARY_INODE_SIZE);	if (ret) {		printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n",		       sizeof(ri), ret);		return ret;	}	new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_GC);	if (IS_ERR(new_fn)) {		printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn));		return PTR_ERR(new_fn);	}	if (je32_to_cpu(ri.version) == f->highest_version) {		jffs2_add_full_dnode_to_inode(c, f, new_fn);		if (f->metadata) {			jffs2_mark_node_obsolete(c, f->metadata->raw);			jffs2_free_full_dnode(f->metadata);			f->metadata = NULL;		}		return 0;	}	/*	 * We should only get here in the case where the node we are	 * replacing had more than one frag, so we kept the same version	 * number as before. (Except in case of error -- see 'goto fill;'	 * above.)	 */	D1(if(unlikely(fn->frags <= 1)) {		printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n",		       fn->frags, je32_to_cpu(ri.version), f->highest_version,		       je32_to_cpu(ri.ino));	});	/* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */	mark_ref_normal(new_fn->raw);	for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs);	     frag; frag = frag_next(frag)) {		if (frag->ofs > fn->size + fn->ofs)			break;		if (frag->node == fn) {			frag->node = new_fn;			new_fn->frags++;			fn->frags--;		}	}	if (fn->frags) {		printk(KERN_WARNING "jffs2_garbage_collect_hole: Old node still has frags!\n");		BUG();	}	if (!new_fn->frags) {		printk(KERN_WARNING "jffs2_garbage_collect_hole: New node has no frags!\n");		BUG();	}	jffs2_mark_node_obsolete(c, fn->raw);	jffs2_free_full_dnode(fn);	return 0;}static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,				       struct jffs2_inode_info *f, struct jffs2_full_dnode *fn,				       uint32_t start, uint32_t end){	struct jffs2_full_dnode *new_fn;	struct jffs2_raw_inode ri;	uint32_t alloclen, offset, orig_end, orig_start;	int ret = 0;	unsigned char *comprbuf = NULL, *writebuf;	unsigned long pg;	unsigned char *pg_ptr;	memset(&ri, 0, sizeof(ri));	D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n",		  f->inocache->ino, start, end));	orig_end = end;	orig_start = start;	if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) {		/* Attempt to do some merging. But only expand to cover logically		   adjacent frags if the block containing them is already considered		   to be dirty. Otherwise we end up with GC just going round in		   circles dirtying the nodes it already wrote out, especially		   on NAND where we have small eraseblocks and hence a much higher		   chance of nodes having to be split to cross boundaries. */		struct jffs2_node_frag *frag;		uint32_t min, max;		min = start & ~(PAGE_CACHE_SIZE-1);		max = min + PAGE_CACHE_SIZE;		frag = jffs2_lookup_node_frag(&f->fragtree, start);		/* BUG_ON(!frag) but that'll happen anyway... */		BUG_ON(frag->ofs != start);		/* First grow down... */		while((frag = frag_prev(frag)) && frag->ofs >= min) {			/* If the previous frag doesn't even reach the beginning, there's			   excessive fragmentation. Just merge. */			if (frag->ofs > min) {				D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n",					  frag->ofs, frag->ofs+frag->size));				start = frag->ofs;				continue;			}			/* OK. This frag holds the first byte of the page. */			if (!frag->node || !frag->node->raw) {				D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n",					  frag->ofs, frag->ofs+frag->size));				break;			} else {				/* OK, it's a frag which extends to the beginning of the page. Does it live				   in a block which is still considered clean? If so, don't obsolete it.				   If not, cover it anyway. */				struct jffs2_raw_node_ref *raw = frag->node->raw;				struct jffs2_eraseblock *jeb;				jeb = &c->blocks[raw->flash_offset / c->sector_size];				if (jeb == c->gcblock) {					D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n",						  frag->ofs, frag->ofs+frag->size, ref_offset(raw)));					start = frag->ofs;					break;				}				if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {					D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n",						  frag->ofs, frag->ofs+frag->size, jeb->offset));					break;				}				D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n",						  frag->ofs, frag->ofs+frag->size, jeb->offset));				start = frag->ofs;				break;			}		}		/* ... then up */		/* Find last frag which is actually part of the node we're to GC. */		frag = jffs2_lookup_node_frag(&f->fragtree, end-1);		while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) {			/* If the previous frag doesn't even reach the beginning, there's lots			   of fragmentation. Just merge. */			if (frag->ofs+frag->size < max) {				D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n",					  frag->ofs, frag->ofs+frag->size));				end = frag->ofs + frag->size;				continue;			}			if (!frag->node || !frag->node->raw) {				D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n",					  frag->ofs, frag->ofs+frag->size));				break;			} else {				/* OK, it's a frag which extends to the beginning of the page. Does it live				   in a block which is still considered clean? If so, don't obsolete it.				   If not, cover it anyway. */				struct jffs2_raw_node_ref *raw = frag->node->raw;				struct jffs2_eraseblock *jeb;				jeb = &c->blocks[raw->flash_offset / c->sector_size];				if (jeb == c->gcblock) {					D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n",						  frag->ofs, frag->ofs+frag->size, ref_offset(raw)));					end = frag->ofs + frag->size;					break;				}				if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) {					D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n",						  frag->ofs, frag->ofs+frag->size, jeb->offset));					break;				}				D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n",						  frag->ofs, frag->ofs+frag->size, jeb->offset));				end = frag->ofs + frag->size;				break;			}		}		D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",			  orig_start, orig_end, start, end));		D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size));		BUG_ON(end < orig_end);		BUG_ON(start > orig_start);	}	/* First, use readpage() to read the appropriate page into the page cache */	/* Q: What happens if we actually try to GC the _same_ page for which commit_write()	 *    triggered garbage collection in the first place?	 * A: I _think_ it's OK. read_cache_page shouldn't deadlock, we'll write out the	 *    page OK. We'll actually write it out again in commit_write, which is a little	 *    suboptimal, but at least we're correct.	 */	pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg);	if (IS_ERR(pg_ptr)) {		printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr));		return PTR_ERR(pg_ptr);	}	offset = start;	while(offset < orig_end) {		uint32_t datalen;		uint32_t cdatalen;		uint16_t comprtype = JFFS2_COMPR_NONE;		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN,					&alloclen, JFFS2_SUMMARY_INODE_SIZE);		if (ret) {			printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n",			       sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);			break;		}		cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset);		datalen = end - offset;		writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));		comprtype = jffs2_compress(c, f, writebuf, &comprbuf, &datalen, &cdatalen);		ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);		ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);		ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen);		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(offset);		ri.csize = cpu_to_je32(cdatalen);		ri.dsize = cpu_to_je32(datalen);		ri.compr = comprtype & 0xff;		ri.usercompr = (comprtype >> 8) & 0xff;		ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8));		ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));		new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, ALLOC_GC);		jffs2_free_comprbuf(comprbuf, writebuf);		if (IS_ERR(new_fn)) {			printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn));			ret = PTR_ERR(new_fn);			break;		}		ret = jffs2_add_full_dnode_to_inode(c, f, new_fn);		offset += datalen;		if (f->metadata) {			jffs2_mark_node_obsolete(c, f->metadata->raw);			jffs2_free_full_dnode(f->metadata);			f->metadata = NULL;		}	}	jffs2_gc_release_page(c, pg_ptr, &pg);	return ret;}

⌨️ 快捷键说明

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