BUG_ON(end > JFFS2_F_I_SIZE(f)); 
D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size)); 
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, phys_ofs, 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));		BUG_ON(end > JFFS2_F_I_SIZE(f));		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, &phys_ofs, &alloclen);		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, phys_ofs, 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;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/8557fd51c22e4c2109f062decd19de439061ceae/gc.c/buggy/fs/jffs2/gc.c