diff options
Diffstat (limited to 'fs/jffs2/jffs2_1pass.c')
| -rw-r--r-- | fs/jffs2/jffs2_1pass.c | 227 | 
1 files changed, 171 insertions, 56 deletions
| diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 35743fc2f..30a6dba6e 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -389,6 +389,12 @@ static inline void *get_fl_mem_nor(u32 off)  	return (void*)addr;  } +static inline void *get_fl_mem_nor_copy(u32 off, u32 size, void *ext_buf) +{ +	memcpy(ext_buf, get_fl_mem_nor(off), size); +	return ext_buf; +} +  static inline void *get_node_mem_nor(u32 off)  {  	return (void*)get_fl_mem_nor(off); @@ -405,8 +411,11 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)  	struct mtdids *id = current_part->dev->id;  #if defined(CONFIG_CMD_FLASH) -	if (id->type == MTD_DEV_TYPE_NOR) +	if (id->type == MTD_DEV_TYPE_NOR) { +		if (ext_buf) +			return get_fl_mem_nor_copy(off, size, ext_buf);  		return get_fl_mem_nor(off); +	}  #endif  #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) @@ -478,9 +487,6 @@ static char *compr_names[] = {  #endif  }; -/* Spinning wheel */ -static char spinner[] = { '|', '/', '-', '\\' }; -  /* Memory management */  struct mem_block {  	u32	index; @@ -651,23 +657,6 @@ static int compare_dirents(struct b_node *new, struct b_node *old)  }  #endif -static u32 -jffs2_scan_empty(u32 start_offset, struct part_info *part) -{ -	char *max = (char *)(part->offset + part->size - sizeof(struct jffs2_raw_inode)); -	char *offset = (char *)(part->offset + start_offset); -	u32 off; - -	while (offset < max && -	       *(u32*)get_fl_mem((u32)offset, sizeof(u32), &off) == 0xFFFFFFFF) { -		offset += sizeof(u32); -		/* return if spinning is due */ -		if (((u32)offset & ((1 << SPIN_BLKSIZE)-1)) == 0) break; -	} - -	return (u32)offset - part->offset; -} -  void  jffs2_free_cache(struct part_info *part)  { @@ -766,6 +755,10 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  					put_fl_mem(jNode);  					continue;  				} +				if (!data_crc(jNode)) { +					put_fl_mem(jNode); +					continue; +				}  				lDest = (uchar *) (dest + jNode->offset);  #if 0 @@ -1268,17 +1261,33 @@ dump_dirents(struct b_lists *pL)  }  #endif +#define min_t(type, x, y) ({                    \ +	type __min1 = (x);                      \ +	type __min2 = (y);                      \ +	__min1 < __min2 ? __min1: __min2; }) + +#define DEFAULT_EMPTY_SCAN_SIZE	4096 + +static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) +{ +	if (sector_size < DEFAULT_EMPTY_SCAN_SIZE) +		return sector_size; +	else +		return DEFAULT_EMPTY_SCAN_SIZE; +} +  static u32  jffs2_1pass_build_lists(struct part_info * part)  {  	struct b_lists *pL;  	struct jffs2_unknown_node *node; -	u32 offset, oldoffset = 0; -	u32 max = part->size - sizeof(struct jffs2_raw_inode); -	u32 counter = 0; +	u32 nr_sectors = part->size/part->sector_size; +	u32 i;  	u32 counter4 = 0;  	u32 counterF = 0;  	u32 counterN = 0; +	u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE; +	char *buf;  	/* turn off the lcd.  Refreshing the lcd adds 50% overhead to the */  	/* jffs2 list building enterprise nope.  in newer versions the overhead is */ @@ -1288,70 +1297,176 @@ jffs2_1pass_build_lists(struct part_info * part)  	/* if we are building a list we need to refresh the cache. */  	jffs_init_1pass_list(part);  	pL = (struct b_lists *)part->jffs2_priv; -	offset = 0; +	buf = malloc(buf_size);  	puts ("Scanning JFFS2 FS:   ");  	/* start at the beginning of the partition */ -	while (offset < max) { -		if ((oldoffset >> SPIN_BLKSIZE) != (offset >> SPIN_BLKSIZE)) { -			printf("\b\b%c ", spinner[counter++ % sizeof(spinner)]); -			oldoffset = offset; -		} +	for (i = 0; i < nr_sectors; i++) { +		uint32_t sector_ofs = i * part->sector_size; +		uint32_t buf_ofs = sector_ofs; +		uint32_t buf_len = EMPTY_SCAN_SIZE(part->sector_size); +		uint32_t ofs, prevofs;  		WATCHDOG_RESET(); +		get_fl_mem((u32)part->offset + buf_ofs, buf_len, buf); + +		/* We temporarily use 'ofs' as a pointer into the buffer/jeb */ +		ofs = 0; -		node = (struct jffs2_unknown_node *) get_node_mem((u32)part->offset + offset); -		if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) { +		/* Scan only 4KiB of 0xFF before declaring it's empty */ +		while (ofs < EMPTY_SCAN_SIZE(part->sector_size) && +				*(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) +			ofs += 4; + +		if (ofs == EMPTY_SCAN_SIZE(part->sector_size)) +			continue; + +		ofs += sector_ofs; +		prevofs = ofs - 1; + +	scan_more: +		while (ofs < sector_ofs + part->sector_size) { +			if (ofs == prevofs) { +				printf("offset %08x already seen, skip\n", ofs); +				ofs += 4; +				counter4++; +				continue; +			} +			prevofs = ofs; +			if (sector_ofs + part->sector_size < +					ofs + sizeof(*node)) +				break; +			if (buf_ofs + buf_len < ofs + sizeof(*node)) { +				buf_len = min_t(uint32_t, buf_size, sector_ofs +						+ part->sector_size - ofs); +				get_fl_mem((u32)part->offset + ofs, buf_len, +					   buf); +				buf_ofs = ofs; +			} + +			node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs]; + +			if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { +				uint32_t inbuf_ofs; +				uint32_t empty_start, scan_end; + +				empty_start = ofs; +				ofs += 4; +				scan_end = min_t(uint32_t, EMPTY_SCAN_SIZE( +							part->sector_size)/8, +							buf_len); +			more_empty: +				inbuf_ofs = ofs - buf_ofs; +				while (inbuf_ofs < scan_end) { +					if (*(uint32_t *)(&buf[inbuf_ofs]) != +							0xffffffff) +						goto scan_more; + +					inbuf_ofs += 4; +					ofs += 4; +				} +				/* Ran off end. */ + +				/* See how much more there is to read in this +				 * eraseblock... +				 */ +				buf_len = min_t(uint32_t, buf_size, +						sector_ofs + +						part->sector_size - ofs); +				if (!buf_len) { +					/* No more to read. Break out of main +					 * loop without marking this range of +					 * empty space as dirty (because it's +					 * not) +					 */ +					break; +				} +				scan_end = buf_len; +				get_fl_mem((u32)part->offset + ofs, buf_len, +					   buf); +				buf_ofs = ofs; +				goto more_empty; +			} +			if (node->magic != JFFS2_MAGIC_BITMASK || +					!hdr_crc(node)) { +				ofs += 4; +				counter4++; +				continue; +			} +			if (ofs + node->totlen > +					sector_ofs + part->sector_size) { +				ofs += 4; +				counter4++; +				continue; +			}  			/* if its a fragment add it */ -			if (node->nodetype == JFFS2_NODETYPE_INODE && -				    inode_crc((struct jffs2_raw_inode *) node) && -				    data_crc((struct jffs2_raw_inode *) node)) { +			switch (node->nodetype) { +			case JFFS2_NODETYPE_INODE: +				if (buf_ofs + buf_len < ofs + sizeof(struct +							jffs2_raw_inode)) { +					get_fl_mem((u32)part->offset + ofs, +						   buf_len, buf); +					buf_ofs = ofs; +					node = (void *)buf; +				} +				if (!inode_crc((struct jffs2_raw_inode *) node)) +				       break; +  				if (insert_node(&pL->frag, (u32) part->offset + -						offset) == NULL) { -					put_fl_mem(node); +						ofs) == NULL)  					return 0; +				break; +			case JFFS2_NODETYPE_DIRENT: +				if (buf_ofs + buf_len < ofs + sizeof(struct +							jffs2_raw_dirent) + +							((struct +							 jffs2_raw_dirent *) +							node)->nsize) { +					get_fl_mem((u32)part->offset + ofs, +						   buf_len, buf); +					buf_ofs = ofs; +					node = (void *)buf;  				} -			} else if (node->nodetype == JFFS2_NODETYPE_DIRENT && -				   dirent_crc((struct jffs2_raw_dirent *) node)  && -				   dirent_name_crc((struct jffs2_raw_dirent *) node)) { + +				if (!dirent_crc((struct jffs2_raw_dirent *) +							node) || +						!dirent_name_crc( +							(struct +							 jffs2_raw_dirent *) +							node)) +					break;  				if (! (counterN%100))  					puts ("\b\b.  ");  				if (insert_node(&pL->dir, (u32) part->offset + -						offset) == NULL) { -					put_fl_mem(node); +						ofs) == NULL)  					return 0; -				}  				counterN++; -			} else if (node->nodetype == JFFS2_NODETYPE_CLEANMARKER) { +				break; +			case JFFS2_NODETYPE_CLEANMARKER:  				if (node->totlen != sizeof(struct jffs2_unknown_node))  					printf("OOPS Cleanmarker has bad size "  						"%d != %zu\n",  						node->totlen,  						sizeof(struct jffs2_unknown_node)); -			} else if (node->nodetype == JFFS2_NODETYPE_PADDING) { +				break; +			case JFFS2_NODETYPE_PADDING:  				if (node->totlen < sizeof(struct jffs2_unknown_node))  					printf("OOPS Padding has bad size "  						"%d < %zu\n",  						node->totlen,  						sizeof(struct jffs2_unknown_node)); -			} else { +				break; +			default:  				printf("Unknown node type: %x len %d offset 0x%x\n",  					node->nodetype, -					node->totlen, offset); +					node->totlen, ofs);  			} -			offset += ((node->totlen + 3) & ~3); +			ofs += ((node->totlen + 3) & ~3);  			counterF++; -		} else if (node->magic == JFFS2_EMPTY_BITMASK && -			   node->nodetype == JFFS2_EMPTY_BITMASK) { -			offset = jffs2_scan_empty(offset, part); -		} else {	/* if we know nothing, we just step and look. */ -			offset += 4; -			counter4++;  		} -/*             printf("unknown node magic %4.4x %4.4x @ %lx\n", node->magic, node->nodetype, (unsigned long)node); */ -		put_fl_mem(node);  	} +	free(buf);  	putstr("\b\b done.\r\n");		/* close off the dots */  	/* turn the lcd back on. */  	/* splash(); */ |