diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/fat/fat.c | 7 | ||||
| -rw-r--r-- | fs/jffs2/jffs2_1pass.c | 646 | ||||
| -rw-r--r-- | fs/jffs2/jffs2_nand_1pass.c | 10 | ||||
| -rw-r--r-- | fs/jffs2/jffs2_private.h | 5 | ||||
| -rw-r--r-- | fs/jffs2/summary.h | 163 | 
5 files changed, 720 insertions, 111 deletions
| diff --git a/fs/fat/fat.c b/fs/fat/fat.c index 2f0bd8c14..a9dde7def 100644 --- a/fs/fat/fat.c +++ b/fs/fat/fat.c @@ -84,6 +84,7 @@ fat_register_device(block_dev_desc_t *dev_desc, int part_no)  		return -1;  	}  #if (defined(CONFIG_CMD_IDE) || \ +     defined(CONFIG_CMD_SATA) || \       defined(CONFIG_CMD_SCSI) || \       defined(CONFIG_CMD_USB) || \       defined(CONFIG_MMC) || \ @@ -184,7 +185,7 @@ static void get_name (dir_entry *dirent, char *s_name)  	if (*s_name == DELETED_FLAG)  		*s_name = '\0';  	else if (*s_name == aRING) -		*s_name = 'å'; +		*s_name = DELETED_FLAG;  	downcase (s_name);  } @@ -489,7 +490,7 @@ get_vfatname(fsdata *mydata, int curclust, __u8 *cluster,  	l_name[idx] = '\0';  	if (*l_name == DELETED_FLAG) *l_name = '\0'; -	else if (*l_name == aRING) *l_name = 'å'; +	else if (*l_name == aRING) *l_name = DELETED_FLAG;  	downcase(l_name);  	/* Return the real directory entry */ @@ -980,12 +981,14 @@ file_fat_detectfs(void)  		return 1;  	}  #if defined(CONFIG_CMD_IDE) || \ +    defined(CONFIG_CMD_SATA) || \      defined(CONFIG_CMD_SCSI) || \      defined(CONFIG_CMD_USB) || \      defined(CONFIG_MMC)  	printf("Interface:  ");  	switch(cur_dev->if_type) {  		case IF_TYPE_IDE :	printf("IDE"); break; +		case IF_TYPE_SATA :	printf("SATA"); break;  		case IF_TYPE_SCSI :	printf("SCSI"); break;  		case IF_TYPE_ATAPI :	printf("ATAPI"); break;  		case IF_TYPE_USB :	printf("USB"); break; diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c index 5d22dd78e..11b66ab4b 100644 --- a/fs/jffs2/jffs2_1pass.c +++ b/fs/jffs2/jffs2_1pass.c @@ -92,7 +92,7 @@   * - implemented fragment sorting to ensure that the newest data is copied   *   if there are multiple copies of fragments for a certain file offset.   * - * The fragment sorting feature must be enabled by CFG_JFFS2_SORT_FRAGMENTS. + * The fragment sorting feature must be enabled by CONFIG_SYS_JFFS2_SORT_FRAGMENTS.   * Sorting is done while adding fragments to the lists, which is more or less a   * bubble sort. This takes a lot of time, and is most probably not an issue if   * the boot filesystem is always mounted readonly. @@ -119,6 +119,7 @@  #include <watchdog.h>  #include <jffs2/jffs2.h>  #include <jffs2/jffs2_1pass.h> +#include <linux/mtd/compat.h>  #include "jffs2_private.h" @@ -138,6 +139,8 @@  # define DEBUGF(fmt,args...)  #endif +#include "summary.h" +  /* keeps pointer to currentlu processed partition */  static struct part_info *current_part; @@ -245,7 +248,7 @@ static void *get_fl_mem_nand(u32 off, u32 size, void *ext_buf)  	return buf;  } -static void *get_node_mem_nand(u32 off) +static void *get_node_mem_nand(u32 off, void *ext_buf)  {  	struct jffs2_unknown_node node;  	void *ret = NULL; @@ -255,7 +258,7 @@ static void *get_node_mem_nand(u32 off)  	if (!(ret = get_fl_mem_nand(off, node.magic ==  			       JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node), -			       NULL))) { +			       ext_buf))) {  		printf("off = %#x magic %#x type %#x node.totlen = %d\n",  		       off, node.magic, node.nodetype, node.totlen);  	} @@ -268,6 +271,107 @@ static void put_fl_mem_nand(void *buf)  }  #endif +#if defined(CONFIG_CMD_ONENAND) + +#include <linux/mtd/mtd.h> +#include <linux/mtd/onenand.h> +#include <onenand_uboot.h> + +#define ONENAND_PAGE_SIZE 2048 +#define ONENAND_PAGE_SHIFT 11 +#define ONENAND_PAGE_MASK (~(ONENAND_PAGE_SIZE-1)) + +#ifndef ONENAND_CACHE_PAGES +#define ONENAND_CACHE_PAGES 4 +#endif +#define ONENAND_CACHE_SIZE (ONENAND_CACHE_PAGES*ONENAND_PAGE_SIZE) + +static u8* onenand_cache; +static u32 onenand_cache_off = (u32)-1; + +static int read_onenand_cached(u32 off, u32 size, u_char *buf) +{ +	u32 bytes_read = 0; +	size_t retlen; +	int cpy_bytes; + +	while (bytes_read < size) { +		if ((off + bytes_read < onenand_cache_off) || +		    (off + bytes_read >= onenand_cache_off + ONENAND_CACHE_SIZE)) { +			onenand_cache_off = (off + bytes_read) & ONENAND_PAGE_MASK; +			if (!onenand_cache) { +				/* This memory never gets freed but 'cause +				   it's a bootloader, nobody cares */ +				onenand_cache = malloc(ONENAND_CACHE_SIZE); +				if (!onenand_cache) { +					printf("read_onenand_cached: can't alloc cache size %d bytes\n", +					       ONENAND_CACHE_SIZE); +					return -1; +				} +			} + +			retlen = ONENAND_CACHE_SIZE; +			if (onenand_read(&onenand_mtd, onenand_cache_off, retlen, +						&retlen, onenand_cache) != 0 || +					retlen != ONENAND_CACHE_SIZE) { +				printf("read_onenand_cached: error reading nand off %#x size %d bytes\n", +					onenand_cache_off, ONENAND_CACHE_SIZE); +				return -1; +			} +		} +		cpy_bytes = onenand_cache_off + ONENAND_CACHE_SIZE - (off + bytes_read); +		if (cpy_bytes > size - bytes_read) +			cpy_bytes = size - bytes_read; +		memcpy(buf + bytes_read, +		       onenand_cache + off + bytes_read - onenand_cache_off, +		       cpy_bytes); +		bytes_read += cpy_bytes; +	} +	return bytes_read; +} + +static void *get_fl_mem_onenand(u32 off, u32 size, void *ext_buf) +{ +	u_char *buf = ext_buf ? (u_char *)ext_buf : (u_char *)malloc(size); + +	if (NULL == buf) { +		printf("get_fl_mem_onenand: can't alloc %d bytes\n", size); +		return NULL; +	} +	if (read_onenand_cached(off, size, buf) < 0) { +		if (!ext_buf) +			free(buf); +		return NULL; +	} + +	return buf; +} + +static void *get_node_mem_onenand(u32 off, void *ext_buf) +{ +	struct jffs2_unknown_node node; +	void *ret = NULL; + +	if (NULL == get_fl_mem_onenand(off, sizeof(node), &node)) +		return NULL; + +	ret = get_fl_mem_onenand(off, node.magic == +			JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node), +			ext_buf); +	if (!ret) { +		printf("off = %#x magic %#x type %#x node.totlen = %d\n", +		       off, node.magic, node.nodetype, node.totlen); +	} +	return ret; +} + + +static void put_fl_mem_onenand(void *buf) +{ +	free(buf); +} +#endif +  #if defined(CONFIG_CMD_FLASH)  /* @@ -276,7 +380,7 @@ static void put_fl_mem_nand(void *buf)   * NOR flash memory is mapped in processor's address space,   * just return address.   */ -static inline void *get_fl_mem_nor(u32 off) +static inline void *get_fl_mem_nor(u32 off, u32 size, void *ext_buf)  {  	u32 addr = off;  	struct mtdids *id = current_part->dev->id; @@ -285,12 +389,22 @@ static inline void *get_fl_mem_nor(u32 off)  	flash_info_t *flash = &flash_info[id->num];  	addr += flash->start[0]; +	if (ext_buf) { +		memcpy(ext_buf, (void *)addr, size); +		return ext_buf; +	}  	return (void*)addr;  } -static inline void *get_node_mem_nor(u32 off) +static inline void *get_node_mem_nor(u32 off, void *ext_buf)  { -	return (void*)get_fl_mem_nor(off); +	struct jffs2_unknown_node *pNode; + +	/* pNode will point directly to flash - don't provide external buffer +	   and don't care about size */ +	pNode = get_fl_mem_nor(off, 0, NULL); +	return (void *)get_fl_mem_nor(off, pNode->magic == JFFS2_MAGIC_BITMASK ? +			pNode->totlen : sizeof(*pNode), ext_buf);  }  #endif @@ -304,8 +418,9 @@ 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) -		return get_fl_mem_nor(off); +	if (id->type == MTD_DEV_TYPE_NOR) { +		return get_fl_mem_nor(off, size, ext_buf); +	}  #endif  #if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) @@ -313,38 +428,57 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)  		return get_fl_mem_nand(off, size, ext_buf);  #endif +#if defined(CONFIG_CMD_ONENAND) +	if (id->type == MTD_DEV_TYPE_ONENAND) +		return get_fl_mem_onenand(off, size, ext_buf); +#endif +  	printf("get_fl_mem: unknown device type, using raw offset!\n");  	return (void*)off;  } -static inline void *get_node_mem(u32 off) +static inline void *get_node_mem(u32 off, void *ext_buf)  {  	struct mtdids *id = current_part->dev->id;  #if defined(CONFIG_CMD_FLASH)  	if (id->type == MTD_DEV_TYPE_NOR) -		return get_node_mem_nor(off); +		return get_node_mem_nor(off, ext_buf);  #endif  #if defined(CONFIG_JFFS2_NAND) && \      defined(CONFIG_CMD_NAND)  	if (id->type == MTD_DEV_TYPE_NAND) -		return get_node_mem_nand(off); +		return get_node_mem_nand(off, ext_buf); +#endif + +#if defined(CONFIG_CMD_ONENAND) +	if (id->type == MTD_DEV_TYPE_ONENAND) +		return get_node_mem_onenand(off, ext_buf);  #endif  	printf("get_node_mem: unknown device type, using raw offset!\n");  	return (void*)off;  } -static inline void put_fl_mem(void *buf) +static inline void put_fl_mem(void *buf, void *ext_buf)  { -#if defined(CONFIG_JFFS2_NAND) && \ -    defined(CONFIG_CMD_NAND)  	struct mtdids *id = current_part->dev->id; -	if (id->type == MTD_DEV_TYPE_NAND) +	/* If buf is the same as ext_buf, it was provided by the caller - +	   we shouldn't free it then. */ +	if (buf == ext_buf) +		return; +	switch (id->type) { +#if defined(CONFIG_JFFS2_NAND) && defined(CONFIG_CMD_NAND) +	case MTD_DEV_TYPE_NAND:  		return put_fl_mem_nand(buf);  #endif +#if defined(CONFIG_CMD_ONENAND) +	case MTD_DEV_TYPE_ONENAND: +		return put_fl_mem_onenand(buf); +#endif +	}  }  /* Compression names */ @@ -362,9 +496,6 @@ static char *compr_names[] = {  #endif  }; -/* Spinning wheel */ -static char spinner[] = { '|', '/', '-', '\\' }; -  /* Memory management */  struct mem_block {  	u32	index; @@ -426,7 +557,7 @@ static struct b_node *  insert_node(struct b_list *list, u32 offset)  {  	struct b_node *new; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  	struct b_node *b, *prev;  #endif @@ -436,7 +567,7 @@ insert_node(struct b_list *list, u32 offset)  	}  	new->offset = offset; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  	if (list->listTail != NULL && list->listCompare(new, list->listTail))  		prev = list->listTail;  	else if (list->listLast != NULL && list->listCompare(new, list->listLast)) @@ -473,7 +604,7 @@ insert_node(struct b_list *list, u32 offset)  	return new;  } -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  /* Sort data entries with the latest version last, so that if there   * is overlapping data the latest version will be used.   */ @@ -535,23 +666,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)  { @@ -561,6 +675,7 @@ jffs2_free_cache(struct part_info *part)  		pL = (struct b_lists *)part->jffs2_priv;  		free_nodes(&pL->frag);  		free_nodes(&pL->dir); +		free(pL->readbuf);  		free(pL);  	}  } @@ -576,7 +691,7 @@ jffs_init_1pass_list(struct part_info *part)  		pL = (struct b_lists *)part->jffs2_priv;  		memset(pL, 0, sizeof(*pL)); -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  		pL->dir.listCompare = compare_dirents;  		pL->frag.listCompare = compare_inodes;  #endif @@ -597,7 +712,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  	long ret;  	int i;  	u32 counter = 0; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  	/* Find file size before loading any data, so fragments that  	 * start past the end of file can be ignored. A fragment  	 * that is partially in the file is loaded, so extra data may @@ -607,7 +722,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  	 */  	for (b = pL->frag.listHead; b != NULL; b = b->next) {  		jNode = (struct jffs2_raw_inode *) get_fl_mem(b->offset, -		        sizeof(struct jffs2_raw_inode), NULL); +			sizeof(struct jffs2_raw_inode), pL->readbuf);  		if ((inode == jNode->ino)) {  			/* get actual file length from the newest node */  			if (jNode->version >= latestVersion) { @@ -615,12 +730,13 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  				latestVersion = jNode->version;  			}  		} -		put_fl_mem(jNode); +		put_fl_mem(jNode, pL->readbuf);  	}  #endif  	for (b = pL->frag.listHead; b != NULL; b = b->next) { -		jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset); +		jNode = (struct jffs2_raw_inode *) get_node_mem(b->offset, +								pL->readbuf);  		if ((inode == jNode->ino)) {  #if 0  			putLabeledWord("\r\n\r\nread_inode: totlen = ", jNode->totlen); @@ -635,7 +751,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  			putLabeledWord("read_inode: flags = ", jNode->flags);  #endif -#ifndef CFG_JFFS2_SORT_FRAGMENTS +#ifndef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  			/* get actual file length from the newest node */  			if (jNode->version >= latestVersion) {  				totalSize = jNode->isize; @@ -647,7 +763,14 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  				src = ((uchar *) jNode) + sizeof(struct jffs2_raw_inode);  				/* ignore data behind latest known EOF */  				if (jNode->offset > totalSize) { -					put_fl_mem(jNode); +					put_fl_mem(jNode, pL->readbuf); +					continue; +				} +				if (b->datacrc == CRC_UNKNOWN) +					b->datacrc = data_crc(jNode) ? +						CRC_OK : CRC_BAD; +				if (b->datacrc == CRC_BAD) { +					put_fl_mem(jNode, pL->readbuf);  					continue;  				} @@ -688,7 +811,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  				default:  					/* unknown */  					putLabeledWord("UNKOWN COMPRESSION METHOD = ", jNode->compr); -					put_fl_mem(jNode); +					put_fl_mem(jNode, pL->readbuf);  					return -1;  					break;  				} @@ -700,7 +823,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 inode, char *dest)  #endif  		}  		counter++; -		put_fl_mem(jNode); +		put_fl_mem(jNode, pL->readbuf);  	}  #if 0 @@ -726,12 +849,13 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)  	counter = 0;  	/* we need to search all and return the inode with the highest version */  	for(b = pL->dir.listHead; b; b = b->next, counter++) { -		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset); +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf);  		if ((pino == jDir->pino) && (len == jDir->nsize) &&  		    (jDir->ino) &&	/* 0 for unlink */  		    (!strncmp((char *)jDir->name, name, len))) {	/* a match */  			if (jDir->version < version) { -				put_fl_mem(jDir); +				put_fl_mem(jDir, pL->readbuf);  				continue;  			} @@ -753,7 +877,7 @@ jffs2_1pass_find_inode(struct b_lists * pL, const char *name, u32 pino)  		putLabeledWord("b = ", (u32) b);  		putLabeledWord("counter = ", counter);  #endif -		put_fl_mem(jDir); +		put_fl_mem(jDir, pL->readbuf);  	}  	return inode;  } @@ -824,9 +948,7 @@ static inline u32 dump_inode(struct b_lists * pL, struct jffs2_raw_dirent *d, st  	st.st_mtime = i->mtime;  	st.st_mode = i->mode;  	st.st_ino = i->ino; - -	/* neither dsize nor isize help us.. do it the long way */ -	st.st_size = jffs2_1pass_read_inode(pL, i->ino, NULL); +	st.st_size = i->isize;  	dump_stat(&st, fname); @@ -849,7 +971,8 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)  	struct jffs2_raw_dirent *jDir;  	for (b = pL->dir.listHead; b; b = b->next) { -		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset); +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf);  		if ((pino == jDir->pino) && (jDir->ino)) { /* ino=0 -> unlink */  			u32 i_version = 0;  			struct jffs2_raw_inode ojNode; @@ -860,21 +983,25 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)  				jNode = (struct jffs2_raw_inode *)  					get_fl_mem(b2->offset, sizeof(ojNode), &ojNode);  				if (jNode->ino == jDir->ino && jNode->version >= i_version) { +					i_version = jNode->version;  					if (i) -						put_fl_mem(i); +						put_fl_mem(i, NULL);  					if (jDir->type == DT_LNK) -						i = get_node_mem(b2->offset); +						i = get_node_mem(b2->offset, +								 NULL);  					else -						i = get_fl_mem(b2->offset, sizeof(*i), NULL); +						i = get_fl_mem(b2->offset, +							       sizeof(*i), +							       NULL);  				}  				b2 = b2->next;  			}  			dump_inode(pL, jDir, i); -			put_fl_mem(i); +			put_fl_mem(i, NULL);  		} -		put_fl_mem(jDir); +		put_fl_mem(jDir, pL->readbuf);  	}  	return pino;  } @@ -952,10 +1079,11 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)  	/* we need to search all and return the inode with the highest version */  	for(b = pL->dir.listHead; b; b = b->next) { -		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset); +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf);  		if (ino == jDir->ino) {  			if (jDir->version < version) { -				put_fl_mem(jDir); +				put_fl_mem(jDir, pL->readbuf);  				continue;  			} @@ -972,7 +1100,7 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)  			jDirFoundPino = jDir->pino;  			version = jDir->version;  		} -		put_fl_mem(jDir); +		put_fl_mem(jDir, pL->readbuf);  	}  	/* now we found the right entry again. (shoulda returned inode*) */  	if (jDirFoundType != DT_LNK) @@ -981,7 +1109,8 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)  	/* it's a soft link so we follow it again. */  	b2 = pL->frag.listHead;  	while (b2) { -		jNode = (struct jffs2_raw_inode *) get_node_mem(b2->offset); +		jNode = (struct jffs2_raw_inode *) get_node_mem(b2->offset, +								pL->readbuf);  		if (jNode->ino == jDirFoundIno) {  			src = (unsigned char *)jNode + sizeof(struct jffs2_raw_inode); @@ -993,11 +1122,11 @@ jffs2_1pass_resolve_inode(struct b_lists * pL, u32 ino)  #endif  			strncpy(tmp, (char *)src, jNode->dsize);  			tmp[jNode->dsize] = '\0'; -			put_fl_mem(jNode); +			put_fl_mem(jNode, pL->readbuf);  			break;  		}  		b2 = b2->next; -		put_fl_mem(jNode); +		put_fl_mem(jNode, pL->readbuf);  	}  	/* ok so the name of the new file to find is in tmp */  	/* if it starts with a slash it is root based else shared dirs */ @@ -1091,6 +1220,132 @@ jffs2_1pass_rescan_needed(struct part_info *part)  	return 0;  } +#define dbg_summary(...) do {} while (0); +/* Process the stored summary information - helper function for + * jffs2_sum_scan_sumnode() + */ + +static int jffs2_sum_process_sum_data(struct part_info *part, uint32_t offset, +				struct jffs2_raw_summary *summary, +				struct b_lists *pL) +{ +	void *sp; +	int i; + +	sp = summary->sum; + +	for (i = 0; i < summary->sum_num; i++) { +		dbg_summary("processing summary index %d\n", i); + +		switch (((struct jffs2_sum_unknown_flash *)sp)->nodetype) { +			case JFFS2_NODETYPE_INODE: { +				struct jffs2_sum_inode_flash *spi; +				spi = sp; + +				dbg_summary("Inode at 0x%08x-0x%08x\n", +					    offset + spi->offset, +					    offset + spi->offset + spi->totlen); + +				if (insert_node(&pL->frag, (u32) part->offset + +						offset + spi->offset) == NULL) +					return -1; + +				sp += JFFS2_SUMMARY_INODE_SIZE; + +				break; +			} + +			case JFFS2_NODETYPE_DIRENT: { +				struct jffs2_sum_dirent_flash *spd; +				spd = sp; + +				dbg_summary("Dirent at 0x%08x-0x%08x\n", +					    offset + spd->offset, +					    offset + spd->offset + spd->totlen); + +				if (insert_node(&pL->dir, (u32) part->offset + +						offset + spd->offset) == NULL) +					return -1; + +				sp += JFFS2_SUMMARY_DIRENT_SIZE(spd->nsize); + +				break; +			} +			default : { +				uint16_t nodetype = +					((struct jffs2_sum_unknown_flash *) +					 sp)->nodetype; +				printf("Unsupported node type %x found in " +						"summary!\n", nodetype); +				break; +			} +		} +	} +	return 0; +} + +/* Process the summary node - called from jffs2_scan_eraseblock() */ +int jffs2_sum_scan_sumnode(struct part_info *part, uint32_t offset, +			   struct jffs2_raw_summary *summary, uint32_t sumsize, +			   struct b_lists *pL) +{ +	struct jffs2_unknown_node crcnode; +	int ret, ofs; +	uint32_t crc; + +	ofs = part->sector_size - sumsize; + +	dbg_summary("summary found for 0x%08x at 0x%08x (0x%x bytes)\n", +		    offset, offset + ofs, sumsize); + +	/* OK, now check for node validity and CRC */ +	crcnode.magic = JFFS2_MAGIC_BITMASK; +	crcnode.nodetype = JFFS2_NODETYPE_SUMMARY; +	crcnode.totlen = summary->totlen; +	crc = crc32_no_comp(0, (uchar *)&crcnode, sizeof(crcnode)-4); + +	if (summary->hdr_crc != crc) { +		dbg_summary("Summary node header is corrupt (bad CRC or " +				"no summary at all)\n"); +		goto crc_err; +	} + +	if (summary->totlen != sumsize) { +		dbg_summary("Summary node is corrupt (wrong erasesize?)\n"); +		goto crc_err; +	} + +	crc = crc32_no_comp(0, (uchar *)summary, +			sizeof(struct jffs2_raw_summary)-8); + +	if (summary->node_crc != crc) { +		dbg_summary("Summary node is corrupt (bad CRC)\n"); +		goto crc_err; +	} + +	crc = crc32_no_comp(0, (uchar *)summary->sum, +			sumsize - sizeof(struct jffs2_raw_summary)); + +	if (summary->sum_crc != crc) { +		dbg_summary("Summary node data is corrupt (bad CRC)\n"); +		goto crc_err; +	} + +	if (summary->cln_mkr) +		dbg_summary("Summary : CLEANMARKER node \n"); + +	ret = jffs2_sum_process_sum_data(part, offset, summary, pL); +	if (ret) +		return ret;		/* real error */ + +	return 1; + +crc_err: +	putstr("Summary node crc error, skipping summary information.\n"); + +	return 0; +} +  #ifdef DEBUG_FRAGMENTS  static void  dump_fragments(struct b_lists *pL) @@ -1132,7 +1387,8 @@ dump_dirents(struct b_lists *pL)  	putstr("\r\n\r\n******The directory Entries******\r\n");  	b = pL->dir.listHead;  	while (b) { -		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset); +		jDir = (struct jffs2_raw_dirent *) get_node_mem(b->offset, +								pL->readbuf);  		putstr("\r\n");  		putnstr(jDir->name, jDir->nsize);  		putLabeledWord("\r\n\tbuild_list: magic = ", jDir->magic); @@ -1148,22 +1404,34 @@ dump_dirents(struct b_lists *pL)  		putLabeledWord("\tbuild_list: name_crc = ", jDir->name_crc);  		putLabeledWord("\tbuild_list: offset = ", b->offset);	/* FIXME: ? [RS] */  		b = b->next; -		put_fl_mem(jDir); +		put_fl_mem(jDir, pL->readbuf);  	}  }  #endif +#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 max_totlen = 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 */ @@ -1173,71 +1441,245 @@ 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; +		uint32_t ofs, prevofs; +		struct jffs2_sum_marker *sm; +		void *sumptr = NULL; +		uint32_t sumlen; +		int ret;  		WATCHDOG_RESET(); -		node = (struct jffs2_unknown_node *) get_node_mem((u32)part->offset + offset); -		if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) { +		buf_len = sizeof(*sm); + +		/* Read as much as we want into the _end_ of the preallocated +		 * buffer +		 */ +		get_fl_mem(part->offset + sector_ofs + part->sector_size - +				buf_len, buf_len, buf + buf_size - buf_len); + +		sm = (void *)buf + buf_size - sizeof(*sm); +		if (sm->magic == JFFS2_SUM_MAGIC) { +			sumlen = part->sector_size - sm->offset; +			sumptr = buf + buf_size - sumlen; + +			/* Now, make sure the summary itself is available */ +			if (sumlen > buf_size) { +				/* Need to kmalloc for this. */ +				sumptr = malloc(sumlen); +				if (!sumptr) { +					putstr("Can't get memory for summary " +							"node!\n"); +					return 0; +				} +				memcpy(sumptr + sumlen - buf_len, buf + +						buf_size - buf_len, buf_len); +			} +			if (buf_len < sumlen) { +				/* Need to read more so that the entire summary +				 * node is present +				 */ +				get_fl_mem(part->offset + sector_ofs + +						part->sector_size - sumlen, +						sumlen - buf_len, sumptr); +			} +		} + +		if (sumptr) { +			ret = jffs2_sum_scan_sumnode(part, sector_ofs, sumptr, +					sumlen, pL); + +			if (buf_size && sumlen > buf_size) +				free(sumptr); +			if (ret < 0) +				return 0; +			if (ret) +				continue; + +		} + +		buf_len = EMPTY_SCAN_SIZE(part->sector_size); + +		get_fl_mem((u32)part->offset + buf_ofs, buf_len, buf); + +		/* We temporarily use 'ofs' as a pointer into the buffer/jeb */ +		ofs = 0; + +		/* 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; +				if (max_totlen < node->totlen) +					max_totlen = node->totlen; +				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; -				} +				if (max_totlen < node->totlen) +					max_totlen = node->totlen;  				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; +			case JFFS2_NODETYPE_SUMMARY: +				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 */ + +	/* We don't care if malloc failed - then each read operation will +	 * allocate its own buffer as necessary (NAND) or will read directly +	 * from flash (NOR). +	 */ +	pL->readbuf = malloc(max_totlen); +  	/* turn the lcd back on. */  	/* splash(); */ diff --git a/fs/jffs2/jffs2_nand_1pass.c b/fs/jffs2/jffs2_nand_1pass.c index e288d5a84..6eb674550 100644 --- a/fs/jffs2/jffs2_nand_1pass.c +++ b/fs/jffs2/jffs2_nand_1pass.c @@ -96,7 +96,7 @@ add_node(struct b_list *list, int size)  static struct b_node *  insert_node(struct b_list *list, struct b_node *new)  { -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  	struct b_node *b, *prev;  	if (list->listTail != NULL && list->listCompare(new, list->listTail)) @@ -173,7 +173,7 @@ insert_dirent(struct b_list *list, struct jffs2_raw_dirent *node, u32 offset)  	return insert_node(list, (struct b_node *)new);  } -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  /* Sort data entries with the latest version last, so that if there   * is overlapping data the latest version will be used.   */ @@ -250,7 +250,7 @@ jffs_init_1pass_list(struct part_info *part)  		pL = (struct b_lists *)part->jffs2_priv;  		memset(pL, 0, sizeof(*pL)); -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  		pL->dir.listCompare = compare_dirents;  		pL->frag.listCompare = compare_inodes;  #endif @@ -268,7 +268,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 ino, char *dest,  	u32 latestVersion = 0;  	long ret; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  	/* Find file size before loading any data, so fragments that  	 * start past the end of file can be ignored. A fragment  	 * that is partially in the file is loaded, so extra data may @@ -290,7 +290,7 @@ jffs2_1pass_read_inode(struct b_lists *pL, u32 ino, char *dest,  	for (jNode = (struct b_inode *)pL->frag.listHead; jNode; jNode = jNode->next) {  		if ((ino != jNode->ino))  			continue; -#ifndef CFG_JFFS2_SORT_FRAGMENTS +#ifndef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  		/* get actual file length from the newest node */  		if (jNode->version >= latestVersion) {  			totalSize = jNode->isize; diff --git a/fs/jffs2/jffs2_private.h b/fs/jffs2/jffs2_private.h index 46ed644e4..658b32521 100644 --- a/fs/jffs2/jffs2_private.h +++ b/fs/jffs2/jffs2_private.h @@ -7,12 +7,13 @@  struct b_node {  	u32 offset;  	struct b_node *next; +	enum { CRC_UNKNOWN = 0, CRC_OK, CRC_BAD } datacrc;  };  struct b_list {  	struct b_node *listTail;  	struct b_node *listHead; -#ifdef CFG_JFFS2_SORT_FRAGMENTS +#ifdef CONFIG_SYS_JFFS2_SORT_FRAGMENTS  	struct b_node *listLast;  	int (*listCompare)(struct b_node *new, struct b_node *node);  	u32 listLoops; @@ -24,7 +25,7 @@ struct b_list {  struct b_lists {  	struct b_list dir;  	struct b_list frag; - +	void *readbuf;  };  struct b_compr_info { diff --git a/fs/jffs2/summary.h b/fs/jffs2/summary.h new file mode 100644 index 000000000..834933cd1 --- /dev/null +++ b/fs/jffs2/summary.h @@ -0,0 +1,163 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright © 2004  Ferenc Havasi <havasi@inf.u-szeged.hu>, + *		     Zoltan Sogor <weth@inf.u-szeged.hu>, + *		     Patrik Kluba <pajko@halom.u-szeged.hu>, + *		     University of Szeged, Hungary + * + * For licensing information, see the file 'LICENCE' in this directory. + * + */ + +#ifndef JFFS2_SUMMARY_H +#define JFFS2_SUMMARY_H + +#define BLK_STATE_ALLFF		0 +#define BLK_STATE_CLEAN		1 +#define BLK_STATE_PARTDIRTY	2 +#define BLK_STATE_CLEANMARKER	3 +#define BLK_STATE_ALLDIRTY	4 +#define BLK_STATE_BADBLOCK	5 + +#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff +#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash)) +#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x)) +#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash)) +#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash)) + +/* Summary structures used on flash */ + +struct jffs2_sum_unknown_flash +{ +	__u16 nodetype;	/* node type */ +}; + +struct jffs2_sum_inode_flash +{ +	__u16 nodetype;	/* node type */ +	__u32 inode;		/* inode number */ +	__u32 version;	/* inode version */ +	__u32 offset;	/* offset on jeb */ +	__u32 totlen; 	/* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_flash +{ +	__u16 nodetype;	/* == JFFS_NODETYPE_DIRENT */ +	__u32 totlen;	/* record length */ +	__u32 offset;	/* offset on jeb */ +	__u32 pino;		/* parent inode */ +	__u32 version;	/* dirent version */ +	__u32 ino; 		/* == zero for unlink */ +	uint8_t nsize;		/* dirent name size */ +	uint8_t type;		/* dirent type */ +	uint8_t name[0];	/* dirent name */ +} __attribute__((packed)); + +struct jffs2_sum_xattr_flash +{ +	__u16 nodetype;	/* == JFFS2_NODETYPE_XATR */ +	__u32 xid;		/* xattr identifier */ +	__u32 version;	/* version number */ +	__u32 offset;	/* offset on jeb */ +	__u32 totlen;	/* node length */ +} __attribute__((packed)); + +struct jffs2_sum_xref_flash +{ +	__u16 nodetype;	/* == JFFS2_NODETYPE_XREF */ +	__u32 offset;	/* offset on jeb */ +} __attribute__((packed)); + +union jffs2_sum_flash +{ +	struct jffs2_sum_unknown_flash u; +	struct jffs2_sum_inode_flash i; +	struct jffs2_sum_dirent_flash d; +	struct jffs2_sum_xattr_flash x; +	struct jffs2_sum_xref_flash r; +}; + +/* Summary structures used in the memory */ + +struct jffs2_sum_unknown_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype;	/* node type */ +}; + +struct jffs2_sum_inode_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype;	/* node type */ +	__u32 inode;		/* inode number */ +	__u32 version;	/* inode version */ +	__u32 offset;	/* offset on jeb */ +	__u32 totlen; 	/* record length */ +} __attribute__((packed)); + +struct jffs2_sum_dirent_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype;	/* == JFFS_NODETYPE_DIRENT */ +	__u32 totlen;	/* record length */ +	__u32 offset;	/* ofset on jeb */ +	__u32 pino;		/* parent inode */ +	__u32 version;	/* dirent version */ +	__u32 ino; 		/* == zero for unlink */ +	uint8_t nsize;		/* dirent name size */ +	uint8_t type;		/* dirent type */ +	uint8_t name[0];	/* dirent name */ +} __attribute__((packed)); + +struct jffs2_sum_xattr_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype; +	__u32 xid; +	__u32 version; +	__u32 offset; +	__u32 totlen; +} __attribute__((packed)); + +struct jffs2_sum_xref_mem +{ +	union jffs2_sum_mem *next; +	__u16 nodetype; +	__u32 offset; +} __attribute__((packed)); + +union jffs2_sum_mem +{ +	struct jffs2_sum_unknown_mem u; +	struct jffs2_sum_inode_mem i; +	struct jffs2_sum_dirent_mem d; +	struct jffs2_sum_xattr_mem x; +	struct jffs2_sum_xref_mem r; +}; + +/* Summary related information stored in superblock */ + +struct jffs2_summary +{ +	uint32_t sum_size;      /* collected summary information for nextblock */ +	uint32_t sum_num; +	uint32_t sum_padded; +	union jffs2_sum_mem *sum_list_head; +	union jffs2_sum_mem *sum_list_tail; + +	__u32 *sum_buf;	/* buffer for writing out summary */ +}; + +/* Summary marker is stored at the end of every sumarized erase block */ + +struct jffs2_sum_marker +{ +	__u32 offset;	/* offset of the summary node in the jeb */ +	__u32 magic; 	/* == JFFS2_SUM_MAGIC */ +}; + +#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker)) + +#endif /* JFFS2_SUMMARY_H */ |