nilfs2: reject incompatible filesystem
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Wed, 21 Jul 2010 18:22:20 +0000 (03:22 +0900)
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Fri, 23 Jul 2010 01:02:16 +0000 (10:02 +0900)
This forces nilfs to check compatibility of feature flags so as to
reject a filesystem with unknown features when it mounts or remounts
the filesystem.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
fs/nilfs2/nilfs.h
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.c

index cfedc48d78d9293d8f7e37321f2e57d03f8817c0..0842d775b3e09393abf21676fbfb61171baf9e14 100644 (file)
@@ -275,6 +275,8 @@ extern struct nilfs_super_block *
 nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
 extern int nilfs_store_magic_and_option(struct super_block *,
                                        struct nilfs_super_block *, char *);
+extern int nilfs_check_feature_compatibility(struct super_block *,
+                                            struct nilfs_super_block *);
 extern void nilfs_set_log_cursor(struct nilfs_super_block *,
                                 struct the_nilfs *);
 extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
index 164457316df17ef743e8e5b85fbba0859a9810ec..26078b3407c9a15e8a473e80536e25bcb6baefe0 100644 (file)
@@ -790,6 +790,30 @@ int nilfs_store_magic_and_option(struct super_block *sb,
        return !parse_options(data, sb, 0) ? -EINVAL : 0 ;
 }
 
+int nilfs_check_feature_compatibility(struct super_block *sb,
+                                     struct nilfs_super_block *sbp)
+{
+       __u64 features;
+
+       features = le64_to_cpu(sbp->s_feature_incompat) &
+               ~NILFS_FEATURE_INCOMPAT_SUPP;
+       if (features) {
+               printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
+                      "optional features (%llx)\n",
+                      (unsigned long long)features);
+               return -EINVAL;
+       }
+       features = le64_to_cpu(sbp->s_feature_compat_ro) &
+               ~NILFS_FEATURE_COMPAT_RO_SUPP;
+       if (!(sb->s_flags & MS_RDONLY) && features) {
+               printk(KERN_ERR "NILFS: couldn't mount RDWR because of "
+                      "unsupported optional features (%llx)\n",
+                      (unsigned long long)features);
+               return -EINVAL;
+       }
+       return 0;
+}
+
 /**
  * nilfs_fill_super() - initialize a super block instance
  * @sb: super_block
@@ -984,11 +1008,26 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
                nilfs_cleanup_super(sbi);
                up_write(&nilfs->ns_sem);
        } else {
+               __u64 features;
+
                /*
                 * Mounting a RDONLY partition read-write, so reread and
                 * store the current valid flag.  (It may have been changed
                 * by fsck since we originally mounted the partition.)
                 */
+               down_read(&nilfs->ns_sem);
+               features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
+                       ~NILFS_FEATURE_COMPAT_RO_SUPP;
+               up_read(&nilfs->ns_sem);
+               if (features) {
+                       printk(KERN_WARNING "NILFS (device %s): couldn't "
+                              "remount RDWR because of unsupported optional "
+                              "features (%llx)\n",
+                              sb->s_id, (unsigned long long)features);
+                       err = -EROFS;
+                       goto restore_opts;
+               }
+
                sb->s_flags &= ~MS_RDONLY;
 
                err = nilfs_attach_segment_constructor(sbi);
index f2efc8c5be7fbd6a75f7f4773b095ec9c63037d3..da67b560f3c3f31d05ecf025ad1271c5ce197626 100644 (file)
@@ -385,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
                goto skip_recovery;
 
        if (s_flags & MS_RDONLY) {
+               __u64 features;
+
                if (nilfs_test_opt(sbi, NORECOVERY)) {
                        printk(KERN_INFO "NILFS: norecovery option specified. "
                               "skipping roll-forward recovery\n");
                        goto skip_recovery;
                }
+               features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
+                       ~NILFS_FEATURE_COMPAT_RO_SUPP;
+               if (features) {
+                       printk(KERN_ERR "NILFS: couldn't proceed with "
+                              "recovery because of unsupported optional "
+                              "features (%llx)\n",
+                              (unsigned long long)features);
+                       err = -EROFS;
+                       goto failed_unload;
+               }
                if (really_read_only) {
                        printk(KERN_ERR "NILFS: write access "
                               "unavailable, cannot proceed.\n");
@@ -644,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
                if (err)
                        goto out;
 
+               err = nilfs_check_feature_compatibility(sb, sbp);
+               if (err)
+                       goto out;
+
                blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
                if (sb->s_blocksize != blocksize &&
                    !sb_set_blocksize(sb, blocksize)) {
@@ -669,6 +685,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
        if (err)
                goto failed_sbh;
 
+       err = nilfs_check_feature_compatibility(sb, sbp);
+       if (err)
+               goto failed_sbh;
+
        blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
        if (sb->s_blocksize != blocksize) {
                int hw_blocksize = bdev_logical_block_size(sb->s_bdev);