diff --git a/fs/jffs2/jffs2_1pass.c b/fs/jffs2/jffs2_1pass.c
index 30a6dba6e00f6c0026adcd3c48b9e8f89f0add24..73d3ddc9e137fa7e68cc8e1855e9186d3fffeeaa 100644
--- a/fs/jffs2/jffs2_1pass.c
+++ b/fs/jffs2/jffs2_1pass.c
@@ -245,7 +245,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 +255,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);
 	}
@@ -344,7 +344,7 @@ static void *get_fl_mem_onenand(u32 off, u32 size, void *ext_buf)
 	return buf;
 }
 
-static void *get_node_mem_onenand(u32 off)
+static void *get_node_mem_onenand(u32 off, void *ext_buf)
 {
 	struct jffs2_unknown_node node;
 	void *ret = NULL;
@@ -354,7 +354,7 @@ static void *get_node_mem_onenand(u32 off)
 
 	ret = get_fl_mem_onenand(off, node.magic ==
 			JFFS2_MAGIC_BITMASK ? node.totlen : sizeof(node),
-			NULL);
+			ext_buf);
 	if (!ret) {
 		printf("off = %#x magic %#x type %#x node.totlen = %d\n",
 		       off, node.magic, node.nodetype, node.totlen);
@@ -377,7 +377,7 @@ static void put_fl_mem_onenand(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;
@@ -386,18 +386,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_fl_mem_nor_copy(u32 off, u32 size, void *ext_buf)
+static inline void *get_node_mem_nor(u32 off, void *ext_buf)
 {
-	memcpy(ext_buf, get_fl_mem_nor(off), size);
-	return ext_buf;
-}
+	struct jffs2_unknown_node *pNode;
 
-static inline void *get_node_mem_nor(u32 off)
-{
-	return (void*)get_fl_mem_nor(off);
+	/* 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
 
@@ -412,9 +416,7 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
 
 #if defined(CONFIG_CMD_FLASH)
 	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);
+		return get_fl_mem_nor(off, size, ext_buf);
 	}
 #endif
 
@@ -432,34 +434,38 @@ static inline void *get_fl_mem(u32 off, u32 size, void *ext_buf)
 	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);
+		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)
 {
 	struct mtdids *id = current_part->dev->id;
 
+	/* 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:
@@ -666,6 +672,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);
 	}
 }
@@ -712,7 +719,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) {
@@ -720,12 +727,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);
@@ -752,11 +760,11 @@ 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 (!data_crc(jNode)) {
-					put_fl_mem(jNode);
+					put_fl_mem(jNode, pL->readbuf);
 					continue;
 				}
 
@@ -797,7 +805,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;
 				}
@@ -809,7 +817,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
@@ -835,12 +843,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;
 			}
 
@@ -862,7 +871,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;
 }
@@ -956,7 +965,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;
@@ -969,20 +979,23 @@ jffs2_1pass_list_inodes(struct b_lists * pL, u32 pino)
 				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;
 }
@@ -1060,10 +1073,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;
 			}
 
@@ -1080,7 +1094,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)
@@ -1089,7 +1103,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);
 
@@ -1101,11 +1116,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 */
@@ -1240,7 +1255,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);
@@ -1256,7 +1272,7 @@ 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
@@ -1286,6 +1302,7 @@ jffs2_1pass_build_lists(struct part_info * part)
 	u32 counter4 = 0;
 	u32 counterF = 0;
 	u32 counterN = 0;
+	u32 max_totlen = 0;
 	u32 buf_size = DEFAULT_EMPTY_SCAN_SIZE;
 	char *buf;
 
@@ -1415,6 +1432,8 @@ jffs2_1pass_build_lists(struct part_info * part)
 				if (insert_node(&pL->frag, (u32) part->offset +
 						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
@@ -1440,6 +1459,8 @@ jffs2_1pass_build_lists(struct part_info * part)
 				if (insert_node(&pL->dir, (u32) part->offset +
 						ofs) == NULL)
 					return 0;
+				if (max_totlen < node->totlen)
+					max_totlen = node->totlen;
 				counterN++;
 				break;
 			case JFFS2_NODETYPE_CLEANMARKER:
@@ -1468,6 +1489,13 @@ jffs2_1pass_build_lists(struct part_info * part)
 
 	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_private.h b/fs/jffs2/jffs2_private.h
index 97457627c1573a6d8405655325ad3b44e854cc7d..3633deaaf83cc2b26e8e72c179e7a42dfa3ec192 100644
--- a/fs/jffs2/jffs2_private.h
+++ b/fs/jffs2/jffs2_private.h
@@ -24,7 +24,7 @@ struct b_list {
 struct b_lists {
 	struct b_list dir;
 	struct b_list frag;
-
+	void *readbuf;
 };
 
 struct b_compr_info {