aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nilfs2/nilfs.h2
-rw-r--r--fs/nilfs2/super.c39
-rw-r--r--fs/nilfs2/the_nilfs.c20
3 files changed, 61 insertions, 0 deletions
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index cfedc48d78d9..0842d775b3e0 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -275,6 +275,8 @@ extern struct nilfs_super_block *
275nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **); 275nilfs_read_super_block(struct super_block *, u64, int, struct buffer_head **);
276extern int nilfs_store_magic_and_option(struct super_block *, 276extern int nilfs_store_magic_and_option(struct super_block *,
277 struct nilfs_super_block *, char *); 277 struct nilfs_super_block *, char *);
278extern int nilfs_check_feature_compatibility(struct super_block *,
279 struct nilfs_super_block *);
278extern void nilfs_set_log_cursor(struct nilfs_super_block *, 280extern void nilfs_set_log_cursor(struct nilfs_super_block *,
279 struct the_nilfs *); 281 struct the_nilfs *);
280extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *, 282extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *,
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 164457316df1..26078b3407c9 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -790,6 +790,30 @@ int nilfs_store_magic_and_option(struct super_block *sb,
790 return !parse_options(data, sb, 0) ? -EINVAL : 0 ; 790 return !parse_options(data, sb, 0) ? -EINVAL : 0 ;
791} 791}
792 792
793int nilfs_check_feature_compatibility(struct super_block *sb,
794 struct nilfs_super_block *sbp)
795{
796 __u64 features;
797
798 features = le64_to_cpu(sbp->s_feature_incompat) &
799 ~NILFS_FEATURE_INCOMPAT_SUPP;
800 if (features) {
801 printk(KERN_ERR "NILFS: couldn't mount because of unsupported "
802 "optional features (%llx)\n",
803 (unsigned long long)features);
804 return -EINVAL;
805 }
806 features = le64_to_cpu(sbp->s_feature_compat_ro) &
807 ~NILFS_FEATURE_COMPAT_RO_SUPP;
808 if (!(sb->s_flags & MS_RDONLY) && features) {
809 printk(KERN_ERR "NILFS: couldn't mount RDWR because of "
810 "unsupported optional features (%llx)\n",
811 (unsigned long long)features);
812 return -EINVAL;
813 }
814 return 0;
815}
816
793/** 817/**
794 * nilfs_fill_super() - initialize a super block instance 818 * nilfs_fill_super() - initialize a super block instance
795 * @sb: super_block 819 * @sb: super_block
@@ -984,11 +1008,26 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
984 nilfs_cleanup_super(sbi); 1008 nilfs_cleanup_super(sbi);
985 up_write(&nilfs->ns_sem); 1009 up_write(&nilfs->ns_sem);
986 } else { 1010 } else {
1011 __u64 features;
1012
987 /* 1013 /*
988 * Mounting a RDONLY partition read-write, so reread and 1014 * Mounting a RDONLY partition read-write, so reread and
989 * store the current valid flag. (It may have been changed 1015 * store the current valid flag. (It may have been changed
990 * by fsck since we originally mounted the partition.) 1016 * by fsck since we originally mounted the partition.)
991 */ 1017 */
1018 down_read(&nilfs->ns_sem);
1019 features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
1020 ~NILFS_FEATURE_COMPAT_RO_SUPP;
1021 up_read(&nilfs->ns_sem);
1022 if (features) {
1023 printk(KERN_WARNING "NILFS (device %s): couldn't "
1024 "remount RDWR because of unsupported optional "
1025 "features (%llx)\n",
1026 sb->s_id, (unsigned long long)features);
1027 err = -EROFS;
1028 goto restore_opts;
1029 }
1030
992 sb->s_flags &= ~MS_RDONLY; 1031 sb->s_flags &= ~MS_RDONLY;
993 1032
994 err = nilfs_attach_segment_constructor(sbi); 1033 err = nilfs_attach_segment_constructor(sbi);
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index f2efc8c5be7f..da67b560f3c3 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -385,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
385 goto skip_recovery; 385 goto skip_recovery;
386 386
387 if (s_flags & MS_RDONLY) { 387 if (s_flags & MS_RDONLY) {
388 __u64 features;
389
388 if (nilfs_test_opt(sbi, NORECOVERY)) { 390 if (nilfs_test_opt(sbi, NORECOVERY)) {
389 printk(KERN_INFO "NILFS: norecovery option specified. " 391 printk(KERN_INFO "NILFS: norecovery option specified. "
390 "skipping roll-forward recovery\n"); 392 "skipping roll-forward recovery\n");
391 goto skip_recovery; 393 goto skip_recovery;
392 } 394 }
395 features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
396 ~NILFS_FEATURE_COMPAT_RO_SUPP;
397 if (features) {
398 printk(KERN_ERR "NILFS: couldn't proceed with "
399 "recovery because of unsupported optional "
400 "features (%llx)\n",
401 (unsigned long long)features);
402 err = -EROFS;
403 goto failed_unload;
404 }
393 if (really_read_only) { 405 if (really_read_only) {
394 printk(KERN_ERR "NILFS: write access " 406 printk(KERN_ERR "NILFS: write access "
395 "unavailable, cannot proceed.\n"); 407 "unavailable, cannot proceed.\n");
@@ -644,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
644 if (err) 656 if (err)
645 goto out; 657 goto out;
646 658
659 err = nilfs_check_feature_compatibility(sb, sbp);
660 if (err)
661 goto out;
662
647 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); 663 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
648 if (sb->s_blocksize != blocksize && 664 if (sb->s_blocksize != blocksize &&
649 !sb_set_blocksize(sb, blocksize)) { 665 !sb_set_blocksize(sb, blocksize)) {
@@ -669,6 +685,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
669 if (err) 685 if (err)
670 goto failed_sbh; 686 goto failed_sbh;
671 687
688 err = nilfs_check_feature_compatibility(sb, sbp);
689 if (err)
690 goto failed_sbh;
691
672 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); 692 blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size);
673 if (sb->s_blocksize != blocksize) { 693 if (sb->s_blocksize != blocksize) {
674 int hw_blocksize = bdev_logical_block_size(sb->s_bdev); 694 int hw_blocksize = bdev_logical_block_size(sb->s_bdev);