Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
[safe/jmp/linux-2.6] / fs / ubifs / sb.c
index c5da201..57085e4 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "ubifs.h"
 #include <linux/random.h>
+#include <linux/math64.h>
 
 /*
  * Default journal size in logical eraseblocks as a percent of total
@@ -80,7 +81,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first;
        int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0;
        int min_leb_cnt = UBIFS_MIN_LEB_CNT;
-       uint64_t tmp64, main_bytes;
+       long long tmp64, main_bytes;
        __le64 tmp_le64;
 
        /* Some functions called from here depend on the @c->key_len filed */
@@ -160,7 +161,7 @@ static int create_default_filesystem(struct ubifs_info *c)
        if (!sup)
                return -ENOMEM;
 
-       tmp64 = (uint64_t)max_buds * c->leb_size;
+       tmp64 = (long long)max_buds * c->leb_size;
        if (big_lpt)
                sup_flags |= UBIFS_FLG_BIGLPT;
 
@@ -187,12 +188,12 @@ static int create_default_filesystem(struct ubifs_info *c)
 
        generate_random_uuid(sup->uuid);
 
-       main_bytes = (uint64_t)main_lebs * c->leb_size;
-       tmp64 = main_bytes * DEFAULT_RP_PERCENT;
-       do_div(tmp64, 100);
+       main_bytes = (long long)main_lebs * c->leb_size;
+       tmp64 = div_u64(main_bytes * DEFAULT_RP_PERCENT, 100);
        if (tmp64 > DEFAULT_MAX_RP_SIZE)
                tmp64 = DEFAULT_MAX_RP_SIZE;
        sup->rp_size = cpu_to_le64(tmp64);
+       sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION);
 
        err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0, UBI_LONGTERM);
        kfree(sup);
@@ -532,17 +533,39 @@ int ubifs_read_superblock(struct ubifs_info *c)
        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) {
@@ -623,7 +646,6 @@ int ubifs_read_superblock(struct ubifs_info *c)
        c->main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS;
        c->main_lebs -= c->log_lebs + c->lpt_lebs + c->orph_lebs;
        c->main_first = c->leb_cnt - c->main_lebs;
-       c->report_rp_size = ubifs_reported_space(c, c->rp_size);
 
        err = validate_sb(c, sup);
 out: