From ece50ef6d4b5191636c971ee3896ca22fa538625 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Tue, 5 Nov 2013 16:16:03 +0100
Subject: [PATCH] mount_root: fix jffs2 handling on MTD devices emulated by
 gluebi

The jffs2_ready() function in mount_root.c checks
the presence of various JFFS2 markers at the start
of a given MTD device. The function works on NOR
flashes because JFFS2 puts 'cleanmarker' nodes at
the start of freshly erased blocks.

However if jffs2 is used on a MTD device emulated
by the gluebi layer, the 'cleanmarker' nodes are
not present and the jffs2_ready() function fails.

Update the code to handle jffs2 correctly even on
MTD devices emulated by the gluebi layer.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
 mount_root.c |   90 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 83 insertions(+), 7 deletions(-)

--- a/mount_root.c
+++ b/mount_root.c
@@ -54,6 +54,14 @@ enum {
 	FS_DEADCODE,
 };
 
+enum mtd_type {
+	MTD_TYPE_NOT_FOUND,
+	MTD_TYPE_NOR,
+	MTD_TYPE_NAND,
+	MTD_TYPE_UBI,
+	MTD_TYPE_UNKNOWN,
+};
+
 static const char *argv0;
 
 /* this is a raw syscall - man 2 pivot_root */
@@ -223,6 +231,64 @@ static int find_mtd_char(char *name, cha
 	return 0;
 }
 
+static enum mtd_type mtd_get_type(char *index)
+{
+	static char p[256];
+	static char buf[32];
+	FILE *fp;
+	size_t sz;
+
+	snprintf(p, sizeof(p), "/sys/class/mtd/mtd%s/type", index);
+
+	fp = fopen(p, "r");
+	if (!fp) {
+		ERROR("unable to open %s\n", p);
+		return MTD_TYPE_NOT_FOUND;
+	}
+
+	memset(buf, 0, sizeof(buf));
+	sz = fread(buf, 1, sizeof(buf) - 1, fp);
+	fclose(fp);
+
+	if (sz <= 1) {
+		ERROR("unable to read from %s\n", p);
+		return MTD_TYPE_UNKNOWN;
+	}
+
+	while (sz > 0) {
+		sz--;
+
+		if (buf[sz] != '\n')
+			break;
+
+		buf[sz] = 0;
+	}
+
+	if (strcmp(buf, "nor") == 0)
+		return MTD_TYPE_NOR;
+
+	if (strcmp(buf, "nand") == 0)
+		return MTD_TYPE_NAND;
+
+	if (strcmp(buf, "ubi") == 0)
+		return MTD_TYPE_UBI;
+
+	ERROR("mtd%s has unknow type '%s'\n", index, buf);
+	return MTD_TYPE_UNKNOWN;
+}
+
+static enum mtd_type mtd_get_type_by_name(char *name)
+{
+	char *index;
+
+	index = find_mtd_index(name);
+	if (!index)
+		return MTD_TYPE_NOT_FOUND;
+
+	return mtd_get_type(index);
+}
+
+
 static int mtd_unlock(char *mtd)
 {
 	struct erase_info_user mtdlock;
@@ -277,7 +343,7 @@ static int mtd_mount_jffs2(void)
 	return mtd_unlock(rootfs_data);
 }
 
-static int jffs2_ready(char *mtd)
+static int jffs2_ready(char *mtd, enum mtd_type type)
 {
 	FILE *fp = fopen(mtd, "r");
 	__u32 deadc0de;
@@ -298,16 +364,21 @@ static int jffs2_ready(char *mtd)
 	}
 
 	deadc0de = __be32_to_cpu(deadc0de);
-	jffs2 = __be16_to_cpu(deadc0de >> 16);
+	if (deadc0de == 0xdeadc0de) {
+		LOG("jffs2 is not ready - EOF marker found\n");
+		return FS_DEADCODE;
+	}
 
+	jffs2 = __be16_to_cpu(deadc0de >> 16);
 	if (jffs2 == 0x1985) {
 		LOG("jffs2 is ready\n");
 		return FS_JFFS2;
 	}
 
-	if (deadc0de == 0xdeadc0de) {
-		LOG("jffs2 is not ready - marker found\n");
-		return FS_DEADCODE;
+	if (type == MTD_TYPE_UBI &&
+	    deadc0de == 0xffffffff) {
+		LOG("jffs2 is ready\n");
+		return FS_JFFS2;
 	}
 
 	ERROR("No jffs2 marker was found\n");
@@ -638,6 +709,7 @@ static int main_switch2jffs(int argc, ch
 	char mtd[32];
 	char *mp;
 	int ret = -1;
+	enum mtd_type type;
 
 	if (find_overlay_mount("overlayfs:/tmp/root"))
 		return -1;
@@ -659,7 +731,8 @@ static int main_switch2jffs(int argc, ch
 		return ret;
 	}
 
-	switch (jffs2_ready(mtd)) {
+	type = mtd_get_type_by_name("rootfs_data");
+	switch (jffs2_ready(mtd, type)) {
 	case FS_NONE:
 		ERROR("no jffs2 marker found\n");
 		/* fall through */
@@ -781,12 +854,15 @@ int main(int argc, char **argv)
 		LOG("mounting /dev/root\n");
 		mount("/dev/root", "/", NULL, MS_NOATIME | MS_REMOUNT, 0);
 	} else {
+		enum mtd_type type;
+
 		if (!extroot("")) {
 			fprintf(stderr, "mount_root: switched to extroot\n");
 			return 0;
 		}
 
-		switch (jffs2_ready(mtd)) {
+		type = mtd_get_type_by_name("rootfs_data");
+		switch (jffs2_ready(mtd, type)) {
 		case FS_NONE:
 		case FS_DEADCODE:
 			return ramoverlay();
