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

📄 gc.c

📁 这是著名的jffs2嵌入式日志文件系统的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, 					struct inode *inode, struct jffs2_full_dirent *fd){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	struct jffs2_full_dirent *new_fd;	struct jffs2_raw_dirent rd;	__u32 alloclen, phys_ofs;	int ret;	rd.magic = JFFS2_MAGIC_BITMASK;	rd.nodetype = JFFS2_NODETYPE_DIRENT;	rd.nsize = strlen(fd->name);	rd.totlen = sizeof(rd) + rd.nsize;	rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4);	rd.pino = inode->i_ino;	rd.version = ++f->highest_version;	rd.ino = fd->ino;	rd.mctime = max(inode->i_mtime, inode->i_ctime);	rd.type = fd->type;	rd.node_crc = crc32(0, &rd, sizeof(rd)-8);	rd.name_crc = 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 %d bytes for garbage_collect_dirent failed: %d\n",		       sizeof(rd)+rd.nsize, ret);		return ret;	}	new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL);	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 inode *inode, struct jffs2_full_dirent *fd){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	struct jffs2_full_dirent **fdp = &f->dents;	int found = 0;	/* FIXME: When we run on 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. For now, we know that we've actually obliterated	   all the older dirents when they became obsolete, so we didn't	   really need to write the deletion to flash in the first place.	*/	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 #%lu\n", fd->name, inode->i_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 inode *inode, struct jffs2_full_dnode *fn,				      __u32 start, __u32 end){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	struct jffs2_raw_inode ri;	struct jffs2_node_frag *frag;	struct jffs2_full_dnode *new_fn;	__u32 alloclen, phys_ofs;	int ret;	D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n",		  inode->i_ino, start, end));		memset(&ri, 0, sizeof(ri));	if(fn->frags > 1) {		size_t readlen;		__u32 crc;		/* It's partially obsoleted by a later write. So we have to 		   write it out again with the _same_ version as before */		ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri);		if (readlen != sizeof(ri) || ret) {			printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen);			goto fill;		}		if (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",			       fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE);			return -EIO;		}		if (ri.totlen != sizeof(ri)) {			printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n",			       fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri));			return -EIO;		}		crc = crc32(0, &ri, sizeof(ri)-8);		if (crc != 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",			       fn->raw->flash_offset & ~3, 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 #%lu will be lost\n", 			       start, end, inode->i_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", fn->raw->flash_offset & ~3);			printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", 			       start, end, inode->i_ino);			goto fill;		}	} else {	fill:		ri.magic = JFFS2_MAGIC_BITMASK;		ri.nodetype = JFFS2_NODETYPE_INODE;		ri.totlen = sizeof(ri);		ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);		ri.ino = inode->i_ino;		ri.version = ++f->highest_version;		ri.offset = start;		ri.dsize = end - start;		ri.csize = 0;		ri.compr = JFFS2_COMPR_ZERO;	}	ri.mode = inode->i_mode;	ri.uid = inode->i_uid;	ri.gid = inode->i_gid;	ri.isize = inode->i_size;	ri.atime = inode->i_atime;	ri.ctime = inode->i_ctime;	ri.mtime = inode->i_mtime;	ri.data_crc = 0;	ri.node_crc = crc32(0, &ri, sizeof(ri)-8);	ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen);	if (ret) {		printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n",		       sizeof(ri), ret);		return ret;	}	new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL);	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 (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, ri.version, f->highest_version, ri.ino);	});	for (frag = f->fraglist; frag; frag = frag->next) {		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 inode *inode, struct jffs2_full_dnode *fn,				       __u32 start, __u32 end){	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	struct jffs2_full_dnode *new_fn;	struct jffs2_raw_inode ri;	__u32 alloclen, phys_ofs, offset, orig_end;		int ret = 0;	unsigned char *comprbuf = NULL, *writebuf;	struct page *pg;	unsigned char *pg_ptr;	memset(&ri, 0, sizeof(ri));	D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n",		  inode->i_ino, start, end));	orig_end = end;	/* If we're looking at the last node in the block we're	   garbage-collecting, we allow ourselves to merge as if the	   block was already erasing. We're likely to be GC'ing a	   partial page, and the next block we GC is likely to have	   the other half of this page right at the beginning, which	   means we'd expand it _then_, as nr_erasing_blocks would have	   increased since we checked, and in doing so would obsolete 	   the partial node which we'd have written here. Meaning that 	   the GC would churn and churn, and just leave dirty blocks in	   it's wake.	*/	if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) {		/* Shitloads of space */		/* FIXME: Integrate this properly with GC calculations */		start &= ~(PAGE_CACHE_SIZE-1);		end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size);		D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n",			  start, end));		if (end < orig_end) {			printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end);			end = orig_end;		}	}		/* 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 = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode);	if (IS_ERR(pg)) {		printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg));		return PTR_ERR(pg);	}	pg_ptr = (char *)kmap(pg);	comprbuf = kmalloc(end - start, GFP_KERNEL);	offset = start;	while(offset < orig_end) {		__u32 datalen;		__u32 cdatalen;		char comprtype = JFFS2_COMPR_NONE;		ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen);		if (ret) {			printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n",			       sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret);			break;		}		cdatalen = min(alloclen - sizeof(ri), end - offset);		datalen = end - offset;		writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1));		if (comprbuf) {			comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen);		}		if (comprtype) {			writebuf = comprbuf;		} else {			datalen = cdatalen;		}		ri.magic = JFFS2_MAGIC_BITMASK;		ri.nodetype = JFFS2_NODETYPE_INODE;		ri.totlen = sizeof(ri) + cdatalen;		ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4);		ri.ino = inode->i_ino;		ri.version = ++f->highest_version;		ri.mode = inode->i_mode;		ri.uid = inode->i_uid;		ri.gid = inode->i_gid;		ri.isize = inode->i_size;		ri.atime = inode->i_atime;		ri.ctime = inode->i_ctime;		ri.mtime = inode->i_mtime;		ri.offset = offset;		ri.csize = cdatalen;		ri.dsize = datalen;		ri.compr = comprtype;		ri.node_crc = crc32(0, &ri, sizeof(ri)-8);		ri.data_crc = crc32(0, writebuf, cdatalen);			new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL);		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;		}	}	if (comprbuf) kfree(comprbuf);	kunmap(pg);	/* XXX: Does the page get freed automatically? */	/* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */	page_cache_release(pg);	return ret;}

⌨️ 快捷键说明

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