]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
UBIFS: add R/O compatibility
authorArtem Bityutskiy <Artem.Bityutskiy@nokia.com>
Fri, 27 Mar 2009 09:21:14 +0000 (10:21 +0100)
committerWolfgang Denk <wd@denx.de>
Sat, 4 Apr 2009 20:44:22 +0000 (22:44 +0200)
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>
fs/ubifs/sb.c
fs/ubifs/super.c
fs/ubifs/ubifs-media.h
fs/ubifs/ubifs.h

index 9708fda95229643da8f819feecba16ee199d6460..00c9cd31a017e7520b6181d54b9ba72529674853 100644 (file)
@@ -235,17 +235,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) {
index 95f2a412508ec2e02b1c5ba8b57c7f02ee7774cc..391dea4256e7a0a57bd54cf52c35f57e8bc33b6a 100644 (file)
@@ -727,8 +727,9 @@ static int mount_ubifs(struct ubifs_info *c)
        x = (long long)c->log_lebs * c->leb_size + c->max_bud_bytes;
        ubifs_msg("journal size:       %lld bytes (%lld KiB, %lld MiB, %d "
                  "LEBs)", x, x >> 10, x >> 20, c->log_lebs + c->max_bud_cnt);
-       ubifs_msg("media format:       %d (latest is %d)",
-                 c->fmt_version, UBIFS_FORMAT_VERSION);
+       ubifs_msg("media format:       w%d/r%d (latest is w%d/r%d)",
+                 c->fmt_version, c->ro_compat_version,
+                 UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION);
        ubifs_msg("default compressor: %s", ubifs_compr_name(c->default_compr));
        ubifs_msg("reserved for root:  %llu bytes (%llu KiB)",
                c->report_rp_size, c->report_rp_size >> 10);
@@ -967,6 +968,15 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
        if (c->max_inode_sz > MAX_LFS_FILESIZE)
                sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
 
+       if (c->rw_incompat) {
+               ubifs_err("the file-system is not R/W-compatible");
+               ubifs_msg("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);
+               return -EROFS;
+       }
+
        mutex_lock(&c->umount_mutex);
        err = mount_ubifs(c);
        if (err) {
index b25fc36cf72f1fa70889dc3749f892e604673e75..3eee07e0c4955b91a0aff3e0be7c5e0c6368dc3e 100644 (file)
 /* UBIFS node magic number (must not have the padding byte first or last) */
 #define UBIFS_NODE_MAGIC  0x06101831
 
-/* UBIFS on-flash format version */
+/*
+ * UBIFS on-flash format version. This version is increased when the on-flash
+ * format is changing. If this happens, UBIFS is will support older versions as
+ * well. But older UBIFS code will not support newer formats. Format changes
+ * will be rare and only when absolutely necessary, e.g. to fix a bug or to add
+ * a new feature.
+ *
+ * UBIFS went into mainline kernel with format version 4. The older formats
+ * were development formats.
+ */
 #define UBIFS_FORMAT_VERSION 4
 
+/*
+ * Read-only compatibility version. If the UBIFS format is changed, older UBIFS
+ * implementations will not be able to mount newer formats in read-write mode.
+ * However, depending on the change, it may be possible to mount newer formats
+ * in R/O mode. This is indicated by the R/O compatibility version which is
+ * stored in the super-block.
+ *
+ * This is needed to support boot-loaders which only need R/O mounting. With
+ * this flag it is possible to do UBIFS format changes without a need to update
+ * boot-loaders.
+ */
+#define UBIFS_RO_COMPAT_VERSION 0
+
 /* Minimum logical eraseblock size in bytes */
 #define UBIFS_MIN_LEB_SZ (15*1024)
 
@@ -53,7 +75,7 @@
 
 /*
  * If compressed data length is less than %UBIFS_MIN_COMPRESS_DIFF bytes
- * shorter than uncompressed data length, UBIFS preferes to leave this data
+ * shorter than uncompressed data length, UBIFS prefers to leave this data
  * node uncompress, because it'll be read faster.
  */
 #define UBIFS_MIN_COMPRESS_DIFF 64
@@ -586,6 +608,7 @@ struct ubifs_pad_node {
  * @padding2: reserved for future, zeroes
  * @time_gran: time granularity in nanoseconds
  * @uuid: UUID generated when the file system image was created
+ * @ro_compat_version: UBIFS R/O compatibility version
  */
 struct ubifs_sb_node {
        struct ubifs_ch ch;
@@ -612,7 +635,8 @@ struct ubifs_sb_node {
        __le64 rp_size;
        __le32 time_gran;
        __u8 uuid[16];
-       __u8 padding2[3972];
+       __le32 ro_compat_version;
+       __u8 padding2[3968];
 } __attribute__ ((packed));
 
 /**
index f342dd8bf1b91beaed862984857a291e6c981794..91351de75a7d0772f14c908d269d28fc9b28fbff 100644 (file)
@@ -1386,6 +1386,7 @@ struct ubifs_debug_info;
  *          by @commit_sem
  * @cnt_lock: protects @highest_inum and @max_sqnum counters
  * @fmt_version: UBIFS on-flash format version
+ * @ro_compat_version: R/O compatibility version
  * @uuid: UUID from super block
  *
  * @lhead_lnum: log head logical eraseblock number
@@ -1418,6 +1419,7 @@ struct ubifs_debug_info;
  *                   recovery)
  * @bulk_read: enable bulk-reads
  * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
+ * @rw_incompat: the media is not R/W compatible
  *
  * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
  *             @calc_idx_sz
@@ -1628,6 +1630,7 @@ struct ubifs_info {
        unsigned long long cmt_no;
        spinlock_t cnt_lock;
        int fmt_version;
+       int ro_compat_version;
        unsigned char uuid[16];
 
        int lhead_lnum;
@@ -1656,6 +1659,7 @@ struct ubifs_info {
        unsigned int no_chk_data_crc:1;
        unsigned int bulk_read:1;
        unsigned int default_compr:2;
+       unsigned int rw_incompat:1;
 
        struct mutex tnc_mutex;
        struct ubifs_zbranch zroot;