UBIFS: add R/O compatibility

Now UBIFS is supported by u-boot. If we ever decide to change the
media format, then people will have to upgrade their u-boots to
mount new format images. However, very often it is possible to
preserve R/O forward-compatibility, even though the write
forward-compatibility is not preserved.

This patch introduces a new super-block field which stores the
R/O compatibility version.

Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Acked-by: Adrian Hunter <Adrian.Hunter@nokia.com>
Signed-off-by: Stefan Roese <sr@denx.de>
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 9708fda..00c9cd3 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -235,17 +235,39 @@
 	if (IS_ERR(sup))
 		return PTR_ERR(sup);
 
+	c->fmt_version = le32_to_cpu(sup->fmt_version);
+	c->ro_compat_version = le32_to_cpu(sup->ro_compat_version);
+
 	/*
 	 * The software supports all previous versions but not future versions,
 	 * due to the unavailability of time-travelling equipment.
 	 */
-	c->fmt_version = le32_to_cpu(sup->fmt_version);
 	if (c->fmt_version > UBIFS_FORMAT_VERSION) {
-		ubifs_err("on-flash format version is %d, but software only "
-			  "supports up to version %d", c->fmt_version,
-			  UBIFS_FORMAT_VERSION);
-		err = -EINVAL;
-		goto out;
+		struct super_block *sb = c->vfs_sb;
+		int mounting_ro = sb->s_flags & MS_RDONLY;
+
+		ubifs_assert(!c->ro_media || mounting_ro);
+		if (!mounting_ro ||
+		    c->ro_compat_version > UBIFS_RO_COMPAT_VERSION) {
+			ubifs_err("on-flash format version is w%d/r%d, but "
+				  "software only supports up to version "
+				  "w%d/r%d", c->fmt_version,
+				  c->ro_compat_version, UBIFS_FORMAT_VERSION,
+				  UBIFS_RO_COMPAT_VERSION);
+			if (c->ro_compat_version <= UBIFS_RO_COMPAT_VERSION) {
+				ubifs_msg("only R/O mounting is possible");
+				err = -EROFS;
+			} else
+				err = -EINVAL;
+			goto out;
+		}
+
+		/*
+		 * The FS is mounted R/O, and the media format is
+		 * R/O-compatible with the UBIFS implementation, so we can
+		 * mount.
+		 */
+		c->rw_incompat = 1;
 	}
 
 	if (c->fmt_version < 3) {